Let's benchmark malloc
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Apr 2014 21:38:49 +0000 (21:38 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Apr 2014 21:38:49 +0000 (21:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=131118

Reviewed by Mark Hahnenberg.

I want to replace fastMalloc with something faster (fasterMalloc?).
I wrote these benchmarks to test / drive development.

* MallocBench: Added.
* MallocBench/MallocBench: Added.
* MallocBench/MallocBench.xcodeproj: Added.
* MallocBench/MallocBench.xcodeproj/project.pbxproj: Added.
* MallocBench/MallocBench/Benchmark.cpp: Added.
(allocateHeap):
(deallocateHeap):
(Benchmark::Benchmark):
(Benchmark::printBenchmarks):
(Benchmark::runOnce):
(Benchmark::run):
(Benchmark::printReport):
(Benchmark::currentTimeMS):
(Benchmark::currentMemoryBytes):
* MallocBench/MallocBench/Benchmark.h: Added.
(Benchmark::Memory::Memory):
(Benchmark::Memory::operator-):
(Benchmark::isValid):
* MallocBench/MallocBench/CPUCount.cpp: Added.
(cpuCount):
* MallocBench/MallocBench/CPUCount.h: Added.
* MallocBench/MallocBench/CommandLine.cpp: Added.
(CommandLine::printUsage):
* MallocBench/MallocBench/CommandLine.h: Added.
(CommandLine::isValid):
(CommandLine::benchmarkName):
(CommandLine::isParallel):
(CommandLine::heapSize):
(CommandLine::measureHeap):
* MallocBench/MallocBench/Interpreter.cpp: Added.
(Interpreter::Interpreter):
(Interpreter::~Interpreter):
(Interpreter::run):
* MallocBench/MallocBench/Interpreter.h: Added.
* MallocBench/MallocBench/balloon.cpp: Added.
(benchmark_balloon):
* MallocBench/MallocBench/balloon.h: Added.
* MallocBench/MallocBench/big.cpp: Added.
(benchmark_big):
* MallocBench/MallocBench/big.h: Added.
* MallocBench/MallocBench/churn.cpp: Added.
(HeapDouble::operator new):
(HeapDouble::operator delete):
(HeapDouble::HeapDouble):
(HeapDouble::operator+=):
(benchmark_churn):
* MallocBench/MallocBench/churn.h: Added.
* MallocBench/MallocBench/crash.ops: Added.
* MallocBench/MallocBench/facebook.cpp: Added.
(benchmark_facebook):
* MallocBench/MallocBench/facebook.h: Added.
* MallocBench/MallocBench/facebook.ops: Added.
* MallocBench/MallocBench/fragment.cpp: Added.
(validate):
(benchmark_fragment):
(benchmark_fragment_iterate):
* MallocBench/MallocBench/fragment.h: Added.
* MallocBench/MallocBench/list.cpp: Added.
(benchmark_list_allocate):
(benchmark_list_traverse):
* MallocBench/MallocBench/list.h: Added.
* MallocBench/MallocBench/main.cpp: Added.
(main):
* MallocBench/MallocBench/mbmalloc.cpp: Added.
* MallocBench/MallocBench/mbmalloc.h: Added.
* MallocBench/MallocBench/medium.cpp: Added.
(benchmark_medium):
* MallocBench/MallocBench/medium.h: Added.
* MallocBench/MallocBench/message.cpp: Added.
(benchmark_message_one):
(benchmark_message_many):
* MallocBench/MallocBench/message.h: Added.
* MallocBench/MallocBench/realloc.cpp: Added.
(benchmark_realloc):
* MallocBench/MallocBench/realloc.h: Added.
* MallocBench/MallocBench/tree.cpp: Added.
(benchmark_tree_allocate):
(benchmark_tree_traverse):
(benchmark_tree_churn):
* MallocBench/MallocBench/tree.h: Added.
* MallocBench/run-malloc-benchmarks: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@166667 268f45cc-cd09-0410-ab3c-d52691b4dbfc

35 files changed:
PerformanceTests/ChangeLog
PerformanceTests/MallocBench/MallocBench.xcodeproj/project.pbxproj [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/Benchmark.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/Benchmark.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/CPUCount.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/CPUCount.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/CommandLine.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/CommandLine.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/Interpreter.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/Interpreter.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/balloon.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/balloon.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/big.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/big.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/churn.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/churn.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/facebook.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/facebook.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/facebook.ops [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/fragment.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/fragment.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/list.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/list.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/main.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/mbmalloc.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/mbmalloc.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/medium.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/medium.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/message.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/message.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/realloc.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/realloc.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/tree.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/tree.h [new file with mode: 0644]
PerformanceTests/MallocBench/run-malloc-benchmarks [new file with mode: 0755]

index 6e5c07d..4277c4a 100644 (file)
@@ -1,3 +1,95 @@
+2014-04-02  Geoffrey Garen  <ggaren@apple.com>
+
+        Let's benchmark malloc
+        https://bugs.webkit.org/show_bug.cgi?id=131118
+
+        Reviewed by Mark Hahnenberg.
+
+        I want to replace fastMalloc with something faster (fasterMalloc?).
+        I wrote these benchmarks to test / drive development.
+
+        * MallocBench: Added.
+        * MallocBench/MallocBench: Added.
+        * MallocBench/MallocBench.xcodeproj: Added.
+        * MallocBench/MallocBench.xcodeproj/project.pbxproj: Added.
+        * MallocBench/MallocBench/Benchmark.cpp: Added.
+        (allocateHeap):
+        (deallocateHeap):
+        (Benchmark::Benchmark):
+        (Benchmark::printBenchmarks):
+        (Benchmark::runOnce):
+        (Benchmark::run):
+        (Benchmark::printReport):
+        (Benchmark::currentTimeMS):
+        (Benchmark::currentMemoryBytes):
+        * MallocBench/MallocBench/Benchmark.h: Added.
+        (Benchmark::Memory::Memory):
+        (Benchmark::Memory::operator-):
+        (Benchmark::isValid):
+        * MallocBench/MallocBench/CPUCount.cpp: Added.
+        (cpuCount):
+        * MallocBench/MallocBench/CPUCount.h: Added.
+        * MallocBench/MallocBench/CommandLine.cpp: Added.
+        (CommandLine::printUsage):
+        * MallocBench/MallocBench/CommandLine.h: Added.
+        (CommandLine::isValid):
+        (CommandLine::benchmarkName):
+        (CommandLine::isParallel):
+        (CommandLine::heapSize):
+        (CommandLine::measureHeap):
+        * MallocBench/MallocBench/Interpreter.cpp: Added.
+        (Interpreter::Interpreter):
+        (Interpreter::~Interpreter):
+        (Interpreter::run):
+        * MallocBench/MallocBench/Interpreter.h: Added.
+        * MallocBench/MallocBench/balloon.cpp: Added.
+        (benchmark_balloon):
+        * MallocBench/MallocBench/balloon.h: Added.
+        * MallocBench/MallocBench/big.cpp: Added.
+        (benchmark_big):
+        * MallocBench/MallocBench/big.h: Added.
+        * MallocBench/MallocBench/churn.cpp: Added.
+        (HeapDouble::operator new):
+        (HeapDouble::operator delete):
+        (HeapDouble::HeapDouble):
+        (HeapDouble::operator+=):
+        (benchmark_churn):
+        * MallocBench/MallocBench/churn.h: Added.
+        * MallocBench/MallocBench/crash.ops: Added.
+        * MallocBench/MallocBench/facebook.cpp: Added.
+        (benchmark_facebook):
+        * MallocBench/MallocBench/facebook.h: Added.
+        * MallocBench/MallocBench/facebook.ops: Added.
+        * MallocBench/MallocBench/fragment.cpp: Added.
+        (validate):
+        (benchmark_fragment):
+        (benchmark_fragment_iterate):
+        * MallocBench/MallocBench/fragment.h: Added.
+        * MallocBench/MallocBench/list.cpp: Added.
+        (benchmark_list_allocate):
+        (benchmark_list_traverse):
+        * MallocBench/MallocBench/list.h: Added.
+        * MallocBench/MallocBench/main.cpp: Added.
+        (main):
+        * MallocBench/MallocBench/mbmalloc.cpp: Added.
+        * MallocBench/MallocBench/mbmalloc.h: Added.
+        * MallocBench/MallocBench/medium.cpp: Added.
+        (benchmark_medium):
+        * MallocBench/MallocBench/medium.h: Added.
+        * MallocBench/MallocBench/message.cpp: Added.
+        (benchmark_message_one):
+        (benchmark_message_many):
+        * MallocBench/MallocBench/message.h: Added.
+        * MallocBench/MallocBench/realloc.cpp: Added.
+        (benchmark_realloc):
+        * MallocBench/MallocBench/realloc.h: Added.
+        * MallocBench/MallocBench/tree.cpp: Added.
+        (benchmark_tree_allocate):
+        (benchmark_tree_traverse):
+        (benchmark_tree_churn):
+        * MallocBench/MallocBench/tree.h: Added.
+        * MallocBench/run-malloc-benchmarks: Added.
+
 2014-03-29  Mark Lam  <mark.lam@apple.com>
 
         LongSpider 3d-morph result check is inappropriate.
diff --git a/PerformanceTests/MallocBench/MallocBench.xcodeproj/project.pbxproj b/PerformanceTests/MallocBench/MallocBench.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..c8a5828
--- /dev/null
@@ -0,0 +1,449 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 46;
+       objects = {
+
+/* Begin PBXBuildFile section */
+               14105E7F18DF7D73003A106E /* balloon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14105E7D18DF7D73003A106E /* balloon.cpp */; };
+               14105E8218E13EEC003A106E /* realloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14105E8018E13EEC003A106E /* realloc.cpp */; };
+               1444AE93177E79BB00F8030A /* fragment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1444AE91177E79BB00F8030A /* fragment.cpp */; };
+               1444AE96177E8DF200F8030A /* message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1444AE94177E8DF200F8030A /* message.cpp */; };
+               14452CB0177D24460097E057 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14452CAF177D24460097E057 /* main.cpp */; };
+               14452CEF177D47110097E057 /* churn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14452CED177D47110097E057 /* churn.cpp */; };
+               1451FAED18B14B7100DB6D47 /* medium.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1451FAEB18B14B7100DB6D47 /* medium.cpp */; };
+               14976EC8177E3649006B819A /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14976EC6177E3649006B819A /* list.cpp */; };
+               14976ECC177E3C87006B819A /* CommandLine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14976ECB177E3C87006B819A /* CommandLine.cpp */; };
+               14976ECE177E3D67006B819A /* Benchmark.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14976ECD177E3D67006B819A /* Benchmark.cpp */; };
+               14976ED1177E4AF7006B819A /* tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14976ECF177E4AF7006B819A /* tree.cpp */; };
+               14C5008D184016CF007A531D /* facebook.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14C5008B184016CF007A531D /* facebook.cpp */; };
+               14C5009018401841007A531D /* facebook.ops in CopyFiles */ = {isa = PBXBuildFile; fileRef = 14C5008E18401726007A531D /* facebook.ops */; };
+               14C5009318403DA0007A531D /* Interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14C5009118403DA0007A531D /* Interpreter.cpp */; };
+               14CC393C18EA812B004AFE34 /* libmbmalloc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 14CC393818EA811F004AFE34 /* libmbmalloc.dylib */; settings = {ATTRIBUTES = (Weak, ); }; };
+               14CC393F18EA8184004AFE34 /* mbmalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14CC391C18EA6759004AFE34 /* mbmalloc.cpp */; };
+               14CE4A6017BD355800288DAA /* big.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14CE4A5E17BD355800288DAA /* big.cpp */; };
+               14E11932177ECC8B003A8D15 /* CPUCount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14E11930177ECC8B003A8D15 /* CPUCount.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+               14CC393D18EA813F004AFE34 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 14452CA1177D24460097E057 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 14CC393718EA811F004AFE34;
+                       remoteInfo = mbmalloc;
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+               14452CA7177D24460097E057 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 12;
+                       dstPath = "";
+                       dstSubfolderSpec = 7;
+                       files = (
+                               14C5009018401841007A531D /* facebook.ops in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+               14105E7D18DF7D73003A106E /* balloon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = balloon.cpp; path = MallocBench/balloon.cpp; sourceTree = "<group>"; };
+               14105E7E18DF7D73003A106E /* balloon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = balloon.h; path = MallocBench/balloon.h; sourceTree = "<group>"; };
+               14105E8018E13EEC003A106E /* realloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = realloc.cpp; path = MallocBench/realloc.cpp; sourceTree = "<group>"; };
+               14105E8118E13EEC003A106E /* realloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = realloc.h; path = MallocBench/realloc.h; sourceTree = "<group>"; };
+               1444AE91177E79BB00F8030A /* fragment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fragment.cpp; path = MallocBench/fragment.cpp; sourceTree = "<group>"; };
+               1444AE92177E79BB00F8030A /* fragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fragment.h; path = MallocBench/fragment.h; sourceTree = "<group>"; };
+               1444AE94177E8DF200F8030A /* message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = message.cpp; path = MallocBench/message.cpp; sourceTree = "<group>"; };
+               1444AE95177E8DF200F8030A /* message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = message.h; path = MallocBench/message.h; sourceTree = "<group>"; };
+               14452CA9177D24460097E057 /* MallocBench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = MallocBench; sourceTree = BUILT_PRODUCTS_DIR; };
+               14452CAF177D24460097E057 /* main.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+               14452CED177D47110097E057 /* churn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = churn.cpp; path = MallocBench/churn.cpp; sourceTree = "<group>"; };
+               14452CEE177D47110097E057 /* churn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = churn.h; path = MallocBench/churn.h; sourceTree = "<group>"; };
+               1451FAEB18B14B7100DB6D47 /* medium.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = medium.cpp; path = MallocBench/medium.cpp; sourceTree = "<group>"; };
+               1451FAEC18B14B7100DB6D47 /* medium.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = medium.h; path = MallocBench/medium.h; sourceTree = "<group>"; };
+               14976EC6177E3649006B819A /* list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = list.cpp; path = MallocBench/list.cpp; sourceTree = "<group>"; };
+               14976EC7177E3649006B819A /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = list.h; path = MallocBench/list.h; sourceTree = "<group>"; };
+               14976EC9177E3B4A006B819A /* Benchmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Benchmark.h; sourceTree = "<group>"; };
+               14976ECA177E3C05006B819A /* CommandLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommandLine.h; sourceTree = "<group>"; };
+               14976ECB177E3C87006B819A /* CommandLine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommandLine.cpp; sourceTree = "<group>"; };
+               14976ECD177E3D67006B819A /* Benchmark.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Benchmark.cpp; sourceTree = "<group>"; };
+               14976ECF177E4AF7006B819A /* tree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tree.cpp; path = MallocBench/tree.cpp; sourceTree = "<group>"; };
+               14976ED0177E4AF7006B819A /* tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tree.h; path = MallocBench/tree.h; sourceTree = "<group>"; };
+               14C5008B184016CF007A531D /* facebook.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = facebook.cpp; path = MallocBench/facebook.cpp; sourceTree = "<group>"; };
+               14C5008C184016CF007A531D /* facebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = facebook.h; path = MallocBench/facebook.h; sourceTree = "<group>"; };
+               14C5008E18401726007A531D /* facebook.ops */ = {isa = PBXFileReference; lastKnownFileType = file; name = facebook.ops; path = MallocBench/facebook.ops; sourceTree = "<group>"; };
+               14C5009118403DA0007A531D /* Interpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Interpreter.cpp; sourceTree = "<group>"; };
+               14C5009218403DA0007A531D /* Interpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Interpreter.h; sourceTree = "<group>"; };
+               14CC391C18EA6759004AFE34 /* mbmalloc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mbmalloc.cpp; path = MallocBench/mbmalloc.cpp; sourceTree = "<group>"; };
+               14CC393818EA811F004AFE34 /* libmbmalloc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libmbmalloc.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+               14CE4A5E17BD355800288DAA /* big.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = big.cpp; path = MallocBench/big.cpp; sourceTree = "<group>"; };
+               14CE4A5F17BD355800288DAA /* big.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = big.h; path = MallocBench/big.h; sourceTree = "<group>"; };
+               14E11930177ECC8B003A8D15 /* CPUCount.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPUCount.cpp; sourceTree = "<group>"; };
+               14E11931177ECC8B003A8D15 /* CPUCount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CPUCount.h; sourceTree = "<group>"; };
+               14E11934177F5219003A8D15 /* mbmalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mbmalloc.h; path = MallocBench/mbmalloc.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               14452CA6177D24460097E057 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               14CC393C18EA812B004AFE34 /* libmbmalloc.dylib in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               14CC393518EA811F004AFE34 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               14452CA0177D24460097E057 = {
+                       isa = PBXGroup;
+                       children = (
+                               14E11933177F51AC003A8D15 /* Benchmarks */,
+                               14452CAE177D24460097E057 /* MallocBench */,
+                               14CC391B18EA6722004AFE34 /* mbmalloc */,
+                               14452CAA177D24460097E057 /* Products */,
+                       );
+                       sourceTree = "<group>";
+               };
+               14452CAA177D24460097E057 /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               14452CA9177D24460097E057 /* MallocBench */,
+                               14CC393818EA811F004AFE34 /* libmbmalloc.dylib */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               14452CAE177D24460097E057 /* MallocBench */ = {
+                       isa = PBXGroup;
+                       children = (
+                               14976ECD177E3D67006B819A /* Benchmark.cpp */,
+                               14976EC9177E3B4A006B819A /* Benchmark.h */,
+                               14976ECB177E3C87006B819A /* CommandLine.cpp */,
+                               14976ECA177E3C05006B819A /* CommandLine.h */,
+                               14E11930177ECC8B003A8D15 /* CPUCount.cpp */,
+                               14E11931177ECC8B003A8D15 /* CPUCount.h */,
+                               14C5009118403DA0007A531D /* Interpreter.cpp */,
+                               14C5009218403DA0007A531D /* Interpreter.h */,
+                               14452CAF177D24460097E057 /* main.cpp */,
+                       );
+                       path = MallocBench;
+                       sourceTree = "<group>";
+               };
+               14CC391B18EA6722004AFE34 /* mbmalloc */ = {
+                       isa = PBXGroup;
+                       children = (
+                               14CC391C18EA6759004AFE34 /* mbmalloc.cpp */,
+                               14E11934177F5219003A8D15 /* mbmalloc.h */,
+                       );
+                       name = mbmalloc;
+                       sourceTree = "<group>";
+               };
+               14E11933177F51AC003A8D15 /* Benchmarks */ = {
+                       isa = PBXGroup;
+                       children = (
+                               14105E7D18DF7D73003A106E /* balloon.cpp */,
+                               14105E7E18DF7D73003A106E /* balloon.h */,
+                               14CE4A5E17BD355800288DAA /* big.cpp */,
+                               14CE4A5F17BD355800288DAA /* big.h */,
+                               14452CED177D47110097E057 /* churn.cpp */,
+                               14452CEE177D47110097E057 /* churn.h */,
+                               14C5008B184016CF007A531D /* facebook.cpp */,
+                               14C5008C184016CF007A531D /* facebook.h */,
+                               14C5008E18401726007A531D /* facebook.ops */,
+                               1444AE91177E79BB00F8030A /* fragment.cpp */,
+                               1444AE92177E79BB00F8030A /* fragment.h */,
+                               14976EC6177E3649006B819A /* list.cpp */,
+                               14976EC7177E3649006B819A /* list.h */,
+                               1451FAEB18B14B7100DB6D47 /* medium.cpp */,
+                               1451FAEC18B14B7100DB6D47 /* medium.h */,
+                               1444AE94177E8DF200F8030A /* message.cpp */,
+                               1444AE95177E8DF200F8030A /* message.h */,
+                               14105E8018E13EEC003A106E /* realloc.cpp */,
+                               14105E8118E13EEC003A106E /* realloc.h */,
+                               14976ECF177E4AF7006B819A /* tree.cpp */,
+                               14976ED0177E4AF7006B819A /* tree.h */,
+                       );
+                       name = Benchmarks;
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+               14CC393618EA811F004AFE34 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+               14452CA8177D24460097E057 /* MallocBench */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 14452CB7177D24460097E057 /* Build configuration list for PBXNativeTarget "MallocBench" */;
+                       buildPhases = (
+                               14452CA5177D24460097E057 /* Sources */,
+                               14452CA6177D24460097E057 /* Frameworks */,
+                               14452CA7177D24460097E057 /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               14CC393E18EA813F004AFE34 /* PBXTargetDependency */,
+                       );
+                       name = MallocBench;
+                       productName = MallocBench;
+                       productReference = 14452CA9177D24460097E057 /* MallocBench */;
+                       productType = "com.apple.product-type.tool";
+               };
+               14CC393718EA811F004AFE34 /* mbmalloc */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 14CC393918EA811F004AFE34 /* Build configuration list for PBXNativeTarget "mbmalloc" */;
+                       buildPhases = (
+                               14CC393418EA811F004AFE34 /* Sources */,
+                               14CC393518EA811F004AFE34 /* Frameworks */,
+                               14CC393618EA811F004AFE34 /* Headers */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = mbmalloc;
+                       productName = mbmalloc;
+                       productReference = 14CC393818EA811F004AFE34 /* libmbmalloc.dylib */;
+                       productType = "com.apple.product-type.library.dynamic";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               14452CA1177D24460097E057 /* Project object */ = {
+                       isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0600;
+                               ORGANIZATIONNAME = "Geoffrey Garen";
+                       };
+                       buildConfigurationList = 14452CA4177D24460097E057 /* Build configuration list for PBXProject "MallocBench" */;
+                       compatibilityVersion = "Xcode 3.2";
+                       developmentRegion = English;
+                       hasScannedForEncodings = 0;
+                       knownRegions = (
+                               en,
+                       );
+                       mainGroup = 14452CA0177D24460097E057;
+                       productRefGroup = 14452CAA177D24460097E057 /* Products */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               14452CA8177D24460097E057 /* MallocBench */,
+                               14CC393718EA811F004AFE34 /* mbmalloc */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+               14452CA5177D24460097E057 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               14CE4A6017BD355800288DAA /* big.cpp in Sources */,
+                               14976ED1177E4AF7006B819A /* tree.cpp in Sources */,
+                               1444AE96177E8DF200F8030A /* message.cpp in Sources */,
+                               14452CEF177D47110097E057 /* churn.cpp in Sources */,
+                               14452CB0177D24460097E057 /* main.cpp in Sources */,
+                               14C5008D184016CF007A531D /* facebook.cpp in Sources */,
+                               14976EC8177E3649006B819A /* list.cpp in Sources */,
+                               14976ECC177E3C87006B819A /* CommandLine.cpp in Sources */,
+                               1451FAED18B14B7100DB6D47 /* medium.cpp in Sources */,
+                               14C5009318403DA0007A531D /* Interpreter.cpp in Sources */,
+                               14E11932177ECC8B003A8D15 /* CPUCount.cpp in Sources */,
+                               1444AE93177E79BB00F8030A /* fragment.cpp in Sources */,
+                               14105E8218E13EEC003A106E /* realloc.cpp in Sources */,
+                               14105E7F18DF7D73003A106E /* balloon.cpp in Sources */,
+                               14976ECE177E3D67006B819A /* Benchmark.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               14CC393418EA811F004AFE34 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               14CC393F18EA8184004AFE34 /* mbmalloc.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               14CC393E18EA813F004AFE34 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 14CC393718EA811F004AFE34 /* mbmalloc */;
+                       targetProxy = 14CC393D18EA813F004AFE34 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+               14452CB5177D24460097E057 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               COPY_PHASE_STRIP = NO;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               ONLY_ACTIVE_ARCH = YES;
+                               SDKROOT = macosx;
+                       };
+                       name = Debug;
+               };
+               14452CB6177D24460097E057 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               SDKROOT = macosx;
+                       };
+                       name = Release;
+               };
+               14452CB8177D24460097E057 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               14452CB9177D24460097E057 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_PRECOMPILE_PREFIX_HEADER = NO;
+                               ONLY_ACTIVE_ARCH = YES;
+                               "OTHER_CFLAGS[arch=*]" = "";
+                               "OTHER_CPLUSPLUSFLAGS[arch=*]" = (
+                                       "-fno-optimize-sibling-calls",
+                                       "-fno-omit-frame-pointer",
+                               );
+                               PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
+               14CC393A18EA811F004AFE34 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               14CC393B18EA811F004AFE34 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               14452CA4177D24460097E057 /* Build configuration list for PBXProject "MallocBench" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               14452CB5177D24460097E057 /* Debug */,
+                               14452CB6177D24460097E057 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               14452CB7177D24460097E057 /* Build configuration list for PBXNativeTarget "MallocBench" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               14452CB8177D24460097E057 /* Debug */,
+                               14452CB9177D24460097E057 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               14CC393918EA811F004AFE34 /* Build configuration list for PBXNativeTarget "mbmalloc" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               14CC393A18EA811F004AFE34 /* Debug */,
+                               14CC393B18EA811F004AFE34 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 14452CA1177D24460097E057 /* Project object */;
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/Benchmark.cpp b/PerformanceTests/MallocBench/MallocBench/Benchmark.cpp
new file mode 100644 (file)
index 0000000..0767a55
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "Benchmark.h"
+#include "CPUCount.h"
+#include "balloon.h"
+#include "big.h"
+#include "churn.h"
+#include "facebook.h"
+#include "fragment.h"
+#include "list.h"
+#include "medium.h"
+#include "message.h"
+#include "tree.h"
+#include <dispatch/dispatch.h>
+#include <iostream>
+#include <mach/mach.h>
+#include <mach/task_info.h>
+#include <map>
+#include <string>
+#include <sys/time.h>
+#include <thread>
+#include <unistd.h>
+
+#include "mbmalloc.h"
+
+using namespace std;
+
+struct BenchmarkPair {
+    const char* const name;
+    const BenchmarkFunction function;
+};
+
+static const BenchmarkPair benchmarkPairs[] = {
+    { "churn", benchmark_churn },
+    { "list_allocate", benchmark_list_allocate },
+    { "list_traverse", benchmark_list_traverse },
+    { "tree_allocate", benchmark_tree_allocate },
+    { "tree_traverse", benchmark_tree_traverse },
+    { "tree_churn", benchmark_tree_churn },
+    { "fragment", benchmark_fragment },
+    { "fragment_iterate", benchmark_fragment_iterate },
+    { "message_one", benchmark_message_one },
+    { "message_many", benchmark_message_many },
+    { "medium", benchmark_medium },
+    { "big", benchmark_big },
+    { "facebook", benchmark_facebook },
+    { "balloon", benchmark_balloon },
+};
+
+static const size_t benchmarksPairsCount = sizeof(benchmarkPairs) / sizeof(BenchmarkPair);
+
+static inline bool operator==(const BenchmarkPair& benchmarkPair, const string& string)
+{
+    return string == benchmarkPair.name;
+}
+
+static void*** allocateHeap(size_t heapSize, size_t chunkSize, size_t objectSize)
+{
+    if (!heapSize)
+        return 0;
+
+    size_t chunkCount = heapSize / chunkSize;
+    size_t objectCount = chunkSize / objectSize;
+    void*** chunks = (void***)mbmalloc(chunkCount * sizeof(void**));
+    for (size_t i = 0; i < chunkCount; ++i) {
+        chunks[i] = (void**)mbmalloc(objectCount * sizeof(void*));
+        for (size_t j = 0; j < objectCount; ++j) {
+            chunks[i][j] = (void*)mbmalloc(objectSize);
+            bzero(chunks[i][j], objectSize);
+        }
+    }
+    return chunks;
+}
+
+static void deallocateHeap(void*** chunks, size_t heapSize, size_t chunkSize, size_t objectSize)
+{
+    if (!heapSize)
+        return;
+
+    size_t chunkCount = heapSize / chunkSize;
+    size_t objectCount = chunkSize / objectSize;
+    for (size_t i = 0; i < chunkCount; ++i) {
+        for (size_t j = 0; j < objectCount; ++j)
+            mbfree(chunks[i][j], objectSize);
+        mbfree(chunks[i], objectCount * sizeof(void*));
+    }
+    mbfree(chunks, chunkCount * sizeof(void**));
+}
+
+Benchmark::Benchmark(const string& benchmarkName, bool isParallel, bool measureHeap, size_t heapSize)
+    : m_benchmarkPair()
+    , m_elapsedTime()
+    , m_isParallel(isParallel)
+    , m_heapSize(heapSize)
+    , m_measureHeap(measureHeap)
+{
+    const BenchmarkPair* benchmarkPair = std::find(
+        benchmarkPairs, benchmarkPairs + benchmarksPairsCount, benchmarkName);
+    if (benchmarkPair == benchmarkPairs + benchmarksPairsCount)
+        return;
+    
+    m_benchmarkPair = benchmarkPair;
+}
+    
+void Benchmark::printBenchmarks()
+{
+    cout << "Benchmarks: " << endl;
+    for (size_t i = 0; i < benchmarksPairsCount; ++i)
+        cout << "\t" << benchmarkPairs[i].name << endl;
+}
+
+void Benchmark::runOnce()
+{
+    if (!m_isParallel) {
+        m_benchmarkPair->function(m_isParallel);
+        return;
+    }
+
+    dispatch_group_t group = dispatch_group_create();
+
+    for (size_t i = 0; i < cpuCount(); ++i) {
+        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
+            m_benchmarkPair->function(m_isParallel);
+        });
+    }
+
+    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+
+    dispatch_release(group);
+}
+
+void Benchmark::run()
+{
+    static const size_t count = 4;
+    static const size_t objectSize = 32;
+    static const size_t chunkSize = 1024 * 1024;
+    
+    void*** heap = allocateHeap(m_heapSize, chunkSize, objectSize);
+
+    runOnce(); // Warmup run.
+
+    for (size_t i = 0; i < count; ++i) {
+        double start = currentTimeMS();
+        runOnce();
+        double end = currentTimeMS();
+        double elapsed = end - start;
+        m_elapsedTime += elapsed;
+    }
+    m_elapsedTime /= count;
+
+    deallocateHeap(heap, m_heapSize, chunkSize, objectSize);
+    
+    if (!m_measureHeap)
+        return;
+
+    // Wait a bit for any async freeing to finish.
+    size_t last;
+    do {
+        last = currentMemoryBytes().resident;
+        std::this_thread::sleep_for(std::chrono::seconds(2));
+    } while (currentMemoryBytes().resident < last);
+
+    m_memory = currentMemoryBytes();
+}
+
+void Benchmark::printReport()
+{
+    size_t kB = 1024;
+
+    cout << "Time:       \t" << m_elapsedTime << "ms" << endl;
+    if (!m_measureHeap)
+        return;
+
+    cout << "Memory:     \t" << m_memory.resident / kB << "kB" << endl;
+    cout << "Peak Memory:\t" << m_memory.residentMax / kB << "kB" << endl;
+}
+
+double Benchmark::currentTimeMS()
+{
+    struct timeval now;
+    gettimeofday(&now, 0);
+    return (now.tv_sec * 1000.0) + now.tv_usec / 1000.0;
+}
+
+Benchmark::Memory Benchmark::currentMemoryBytes()
+{
+    Memory memory;
+
+    task_vm_info_data_t vm_info;
+    mach_msg_type_number_t vm_size = TASK_VM_INFO_COUNT;
+    if (KERN_SUCCESS != task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)(&vm_info), &vm_size)) {
+        cout << "Failed to get mach task info" << endl;
+        exit(1);
+    }
+
+    memory.resident = vm_info.internal - vm_info.purgeable_volatile_pmap;
+    memory.residentMax = vm_info.resident_size_peak;
+    return memory;
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/Benchmark.h b/PerformanceTests/MallocBench/MallocBench/Benchmark.h
new file mode 100644 (file)
index 0000000..cf9781e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef Benchmark_h
+#define Benchmark_h
+
+#include <map>
+#include <string>
+
+typedef void (*BenchmarkFunction)(bool isParallel);
+struct BenchmarkPair;
+
+class Benchmark {
+public:
+    struct Memory {
+        Memory()
+            : resident()
+            , residentMax()
+        {
+        }
+        
+        Memory(size_t resident, size_t residentMax)
+            : resident(resident)
+            , residentMax(residentMax)
+        {
+        }
+
+        Memory operator-(const Memory& other)
+        {
+            return Memory(resident - other.resident, residentMax - other.residentMax);
+        }
+    
+        size_t resident;
+        size_t residentMax;
+    };
+
+    static double currentTimeMS();
+    static Memory currentMemoryBytes();
+
+    Benchmark(const std::string&, bool isParallel, bool measureHeap, size_t heapSize);
+    
+    bool isValid() { return m_benchmarkPair; }
+    
+    void printBenchmarks();
+    void run();
+    void printReport();
+
+private:
+    typedef std::map<std::string, BenchmarkFunction> MapType;
+    
+    void runOnce();
+
+    MapType m_map;
+
+    const BenchmarkPair* m_benchmarkPair;
+    bool m_isParallel;
+    bool m_measureHeap;
+    size_t m_heapSize;
+
+    Memory m_memory;
+    double m_elapsedTime;
+};
+
+#endif // Benchmark_h
diff --git a/PerformanceTests/MallocBench/MallocBench/CPUCount.cpp b/PerformanceTests/MallocBench/MallocBench/CPUCount.cpp
new file mode 100644 (file)
index 0000000..0f20160
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+static size_t count;
+
+size_t cpuCount()
+{
+    if (count)
+        return count;
+
+    size_t length = sizeof(count);
+    int name[] = {
+            CTL_HW,
+            HW_NCPU
+    };
+    int sysctlResult = sysctl(name, sizeof(name) / sizeof(int), &count, &length, 0, 0);
+    if (sysctlResult < 0)
+        abort();
+
+    return count;
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/CPUCount.h b/PerformanceTests/MallocBench/MallocBench/CPUCount.h
new file mode 100644 (file)
index 0000000..542e824
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef CPUCount_h
+#define CPUCount_h
+
+#include <stddef.h>
+
+size_t cpuCount();
+
+#endif // CPUCount_h
diff --git a/PerformanceTests/MallocBench/MallocBench/CommandLine.cpp b/PerformanceTests/MallocBench/MallocBench/CommandLine.cpp
new file mode 100644 (file)
index 0000000..9d3f886
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CommandLine.h"
+#include <getopt.h>
+#include <iostream>
+
+struct option CommandLine::longOptions[] =
+{
+    {"benchmark", required_argument, 0, 'b'},
+    {"parallel", no_argument, 0, 'p'},
+    {"heap", required_argument, 0, 'h'},
+    {"measure-heap", no_argument, 0, 'm'},
+    {0, 0, 0, 0}
+};
+
+CommandLine::CommandLine(int argc, char** argv)
+    : m_argc(argc)
+    , m_argv(argv)
+    , m_isParallel()
+    , m_heapSize()
+    , m_measureHeap()
+{
+    int optionIndex = 0;
+    int ch;
+    while ((ch = getopt_long(argc, argv, "b:p:h:m", longOptions, &optionIndex)) != -1) {
+        switch (ch)
+        {
+            case 'b':
+                m_benchmarkName = optarg;
+                break;
+
+            case 'p':
+                m_isParallel = true;
+                break;
+
+            case 'h':
+                m_heapSize = atoi(optarg) * 1024 * 1024;
+                break;
+
+            case 'm':
+                m_measureHeap = true;
+                break;
+
+            default:
+                break;
+        }
+    }
+}
+
+void CommandLine::printUsage()
+{
+    std::string fullPath(m_argv[0]);
+    size_t pos = fullPath.find_last_of("/") + 1;
+    std::string program = fullPath.substr(pos);
+    std::cout << "Usage: " << program << " --benchmark benchmark_name [ --parallel ] [ --measure-heap ] [ --heap MB ]" << std::endl;
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/CommandLine.h b/PerformanceTests/MallocBench/MallocBench/CommandLine.h
new file mode 100644 (file)
index 0000000..29242bd
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include <string>
+
+class CommandLine {
+public:
+    CommandLine(int argc, char** argv);
+
+    bool isValid() { return m_benchmarkName.size(); }
+    const std::string& benchmarkName() { return m_benchmarkName; }
+    bool isParallel() { return m_isParallel; }
+    size_t heapSize() { return m_heapSize; }
+    bool measureHeap() { return m_measureHeap; }
+
+    void printUsage();
+
+private:
+    static struct option longOptions[];
+
+    int m_argc;
+    char** m_argv;
+    std::string m_benchmarkName;
+    bool m_isParallel;
+    size_t m_heapSize;
+    bool m_measureHeap;
+};
diff --git a/PerformanceTests/MallocBench/MallocBench/Interpreter.cpp b/PerformanceTests/MallocBench/MallocBench/Interpreter.cpp
new file mode 100644 (file)
index 0000000..4d76c13
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "Interpreter.h"
+#include <assert.h>
+#include <cstddef>
+#include <cstdlib>
+#include <errno.h>
+#include <fcntl.h>
+#include <string>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <vector>
+
+#include "mbmalloc.h"
+
+Interpreter::Interpreter(const char* fileName)
+{
+    m_fd = open(fileName, O_RDWR, S_IRUSR | S_IWUSR);
+    if (m_fd == -1)
+        fprintf(stderr, "failed to open\n");
+
+    struct stat buf;
+    fstat(m_fd, &buf);
+
+    m_opCount = buf.st_size / sizeof(Op);
+    assert(m_opCount * sizeof(Op) == buf.st_size);
+
+    size_t maxSlot = 0;
+
+    std::vector<Op> ops(1024);
+    size_t remaining = m_opCount * sizeof(Op);
+    while (remaining) {
+        size_t bytes = std::min(remaining, ops.size() * sizeof(Op));
+        remaining -= bytes;
+        read(m_fd, ops.data(), bytes);
+
+        size_t opCount = bytes / sizeof(Op);
+        for (size_t i = 0; i < opCount; ++i) {
+            Op op = ops[i];
+            if (op.slot > maxSlot)
+                maxSlot = op.slot;
+        }
+    }
+
+    m_objects.resize(maxSlot + 1);
+}
+
+Interpreter::~Interpreter()
+{
+    int result = close(m_fd);
+    if (result == -1)
+        fprintf(stderr, "failed to close\n");
+}
+
+void Interpreter::run()
+{
+    std::vector<Op> ops(1024);
+    lseek(m_fd, 0, SEEK_SET);
+    size_t remaining = m_opCount * sizeof(Op);
+    while (remaining) {
+        size_t bytes = std::min(remaining, ops.size() * sizeof(Op));
+        remaining -= bytes;
+        read(m_fd, ops.data(), bytes);
+
+        size_t opCount = bytes / sizeof(Op);
+        for (size_t i = 0; i < opCount; ++i) {
+            Op op = ops[i];
+            switch (op.opcode) {
+            case op_a: {
+                m_objects[op.slot] = { mbmalloc(op.size), op.size };
+                assert(m_objects[op.slot].object);
+                bzero(m_objects[op.slot].object, op.size);
+                break;
+            }
+            case op_d: {
+                assert(m_objects[op.slot].object);
+                assert(m_objects[op.slot].size);
+                mbfree(m_objects[op.slot].object, m_objects[op.slot].size);
+                m_objects[op.slot] = { 0, 0 };
+                break;
+            }
+            default: {
+                fprintf(stderr, "bad opcode: %d\n", op.opcode);
+                abort();
+                break;
+            }
+            }
+        }
+    }
+
+    // A recording might not free all of its allocations.
+    for (size_t i = 0; i < m_objects.size(); ++i) {
+        if (!m_objects[i].object)
+            continue;
+        mbfree(m_objects[i].object, m_objects[i].size);
+        m_objects[i] = { 0, 0 };
+    }
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/Interpreter.h b/PerformanceTests/MallocBench/MallocBench/Interpreter.h
new file mode 100644 (file)
index 0000000..61a161a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef Interpreter_h
+#define Interpreter_h
+
+#include <vector>
+
+class Interpreter {
+public:
+    Interpreter(const char* fileName);
+    ~Interpreter();
+
+    void run();
+
+private:
+    enum Opcode { op_a, op_d };
+    struct Op { Opcode opcode; size_t slot; size_t size; };
+    struct Record { void* object; size_t size; };
+
+    int m_fd;
+    size_t m_opCount;
+    std::vector<Record> m_objects;
+};
+
+#endif // Interpreter_h
diff --git a/PerformanceTests/MallocBench/MallocBench/balloon.cpp b/PerformanceTests/MallocBench/MallocBench/balloon.cpp
new file mode 100644 (file)
index 0000000..62b449f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "Benchmark.h"
+#include "CPUCount.h"
+#include "balloon.h"
+#include <array>
+#include <chrono>
+#include <memory>
+#include <stddef.h>
+
+#include "mbmalloc.h"
+
+void benchmark_balloon(bool isParallel)
+{
+    const size_t chunkSize = 1 * 1024;
+    const size_t balloonSize = 100 * 1024 * 1024;
+    const size_t steadySize = 10 * 1024 * 1024;
+    
+    std::array<void*, balloonSize / chunkSize> balloon;
+    std::array<void*, balloonSize / chunkSize> steady;
+
+    auto start = std::chrono::steady_clock::now();
+
+    for (size_t i = 0; i < balloon.size(); ++i) {
+        balloon[i] = mbmalloc(chunkSize);
+        bzero(balloon[i], chunkSize);
+    }
+
+    for (size_t i = 0; i < balloon.size(); ++i)
+        mbfree(balloon[i], chunkSize);
+
+    auto stop = std::chrono::steady_clock::now();
+    
+    auto benchmarkTime = stop - start;
+
+    start = std::chrono::steady_clock::now();
+
+    // Converts bytes to time -- for reporting's sake -- by waiting a while until
+    // the heap shrinks back down. This isn't great for pooling with other
+    // benchmarks in a geometric mean of throughput, but it's OK for basic testing.
+    while (Benchmark::currentMemoryBytes().resident > 2 * steadySize
+        && std::chrono::steady_clock::now() - start < 8 * benchmarkTime) {
+        for (size_t i = 0; i < steady.size(); ++i) {
+            steady[i] = mbmalloc(chunkSize);
+            bzero(steady[i], chunkSize);
+        }
+
+        for (size_t i = 0; i < steady.size(); ++i)
+            mbfree(steady[i], chunkSize);
+    }
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/balloon.h b/PerformanceTests/MallocBench/MallocBench/balloon.h
new file mode 100644 (file)
index 0000000..bb8671c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef balloon_h
+#define balloon_h
+
+void benchmark_balloon(bool isParallel);
+
+#endif // balloon_h
+
diff --git a/PerformanceTests/MallocBench/MallocBench/big.cpp b/PerformanceTests/MallocBench/MallocBench/big.cpp
new file mode 100644 (file)
index 0000000..bbc3531
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "big.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdlib>
+#include <strings.h>
+
+#include "mbmalloc.h"
+
+using namespace std;
+
+struct Object {
+    double* p;
+    size_t size;
+};
+
+void benchmark_big(bool isParallel)
+{
+    size_t times = 1;
+
+    size_t vmSize = 1ul * 1024 * 1024 * 1024;
+    size_t objectSizeMin = 4 * 1024;
+    size_t objectSizeMax = 64 * 1024;
+    if (isParallel)
+        vmSize /= cpuCount();
+
+    size_t objectCount = vmSize / objectSizeMin;
+
+    srandom(0); // For consistency between runs.
+
+    for (size_t i = 0; i < times; ++i) {
+        Object* objects = (Object*)mbmalloc(objectCount * sizeof(Object));
+        bzero(objects, objectCount * sizeof(Object));
+
+        for (size_t i = 0, remaining = vmSize; remaining > objectSizeMin; ++i) {
+            size_t size = min(remaining, max(objectSizeMin, random() % objectSizeMax));
+            objects[i] = { (double*)mbmalloc(size), size };
+            bzero(objects[i].p, size);
+            remaining -= size;
+        }
+
+        for (size_t i = 0; i < objectCount && objects[i].p; ++i)
+            mbfree(objects[i].p, objects[i].size);
+
+        mbfree(objects, objectCount * sizeof(Object));
+    }
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/big.h b/PerformanceTests/MallocBench/MallocBench/big.h
new file mode 100644 (file)
index 0000000..56bf565
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef big_h
+#define big_h
+
+void benchmark_big(bool isParallel);
+
+#endif // big_h
+
diff --git a/PerformanceTests/MallocBench/MallocBench/churn.cpp b/PerformanceTests/MallocBench/MallocBench/churn.cpp
new file mode 100644 (file)
index 0000000..56cdf96
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "churn.h"
+#include <memory>
+#include <stddef.h>
+
+#include "mbmalloc.h"
+
+struct HeapDouble {
+    void* operator new(size_t size) { return mbmalloc(size); }
+    void operator delete(void* p, size_t size) { mbfree(p, size); }
+
+    HeapDouble(double d) : value(d) { }
+    const HeapDouble& operator+=(const HeapDouble& other) { value += other.value; return *this; }
+    double value;
+};
+
+void benchmark_churn(bool isParallel)
+{
+    size_t times = 10000000;
+    if (isParallel)
+        times /= cpuCount();
+
+    auto total = std::unique_ptr<HeapDouble>(new HeapDouble(0.0));
+    for (size_t i = 0; i < times; ++i) {
+        auto heapDouble = std::unique_ptr<HeapDouble>(new HeapDouble(i));
+        *total += *heapDouble;
+    }
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/churn.h b/PerformanceTests/MallocBench/MallocBench/churn.h
new file mode 100644 (file)
index 0000000..2047a04
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef churn_h
+#define churn_h
+
+void benchmark_churn(bool isParallel);
+
+#endif // churn_h
+
diff --git a/PerformanceTests/MallocBench/MallocBench/facebook.cpp b/PerformanceTests/MallocBench/MallocBench/facebook.cpp
new file mode 100644 (file)
index 0000000..37cb4da
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "Interpreter.h"
+#include "facebook.h"
+#include <assert.h>
+#include <cstddef>
+#include <cstddef>
+#include <cstdlib>
+#include <errno.h>
+#include <fcntl.h>
+#include <string>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <vector>
+
+#include "mbmalloc.h"
+
+void benchmark_facebook(bool isParallel)
+{
+    size_t times = 1;
+
+    Interpreter interpreter("facebook.ops");
+    for (size_t i = 0; i < times; ++i)
+        interpreter.run();
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/facebook.h b/PerformanceTests/MallocBench/MallocBench/facebook.h
new file mode 100644 (file)
index 0000000..e7976de
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef facebook_h
+#define facebook_h
+
+void benchmark_facebook(bool isParallel);
+
+#endif // facebook_h
+
diff --git a/PerformanceTests/MallocBench/MallocBench/facebook.ops b/PerformanceTests/MallocBench/MallocBench/facebook.ops
new file mode 100644 (file)
index 0000000..512af90
Binary files /dev/null and b/PerformanceTests/MallocBench/MallocBench/facebook.ops differ
diff --git a/PerformanceTests/MallocBench/MallocBench/fragment.cpp b/PerformanceTests/MallocBench/MallocBench/fragment.cpp
new file mode 100644 (file)
index 0000000..1e0c725
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "fragment.h"
+#include <stdlib.h>
+#include <strings.h>
+
+#include "mbmalloc.h"
+
+namespace {
+
+class Node {
+public:
+    void* operator new(size_t size)
+    {
+        return mbmalloc(size);
+    }
+
+    void operator delete(void* p, size_t size)
+    {
+        mbfree(p, size);
+    }
+
+    Node()
+        : m_next(0)
+        , m_payload()
+    {
+    }
+
+    Node(Node* next)
+        : m_next(next)
+        , m_payload()
+    {
+    }
+    
+    Node* next() { return m_next; }
+    
+    void validate()
+    {
+        for (size_t i = 0; i < sizeof(m_payload); ++i) {
+            if (m_payload[i])
+                abort();
+        }
+    }
+
+private:
+    Node* m_next;
+    char m_payload[32 - sizeof(Node*)];
+};
+
+} // namespace
+
+void validate(Node* head)
+{
+    for (Node* node = head; node; node = node->next())
+        node->validate();
+}
+
+void benchmark_fragment(bool isParallel)
+{
+    size_t nodeCount = 128 * 1024;
+    if (isParallel)
+        nodeCount /= cpuCount();
+    size_t replaceCount = nodeCount / 4;
+    size_t times = 25;
+
+    srandom(0); // For consistency between runs.
+
+    for (size_t i = 0; i < times; ++i) {
+        Node** nodes = static_cast<Node**>(mbmalloc(nodeCount * sizeof(Node*)));
+        for (size_t i = 0; i < nodeCount; ++i)
+            nodes[i] = new Node;
+
+        for (size_t i = 0; i < replaceCount; ++i) {
+            size_t node = random() % nodeCount;
+
+            delete nodes[node];
+            nodes[node] = new Node;
+        }
+
+        for (size_t node = 0; node < nodeCount; ++node)
+            delete nodes[node];
+        mbfree(nodes, nodeCount * sizeof(Node*));
+    }
+}
+
+void benchmark_fragment_iterate(bool isParallel)
+{
+    size_t nodeCount = 512 * 1024;
+    size_t times = 32;
+    if (isParallel)
+        nodeCount /= cpuCount();
+    size_t replaceCount = nodeCount / 4;
+
+    srandom(0); // For consistency between runs.
+
+    Node** nodes = static_cast<Node**>(mbmalloc(nodeCount * sizeof(Node*)));
+    for (size_t i = 0; i < nodeCount; ++i)
+        nodes[i] = new Node;
+
+    Node* head = 0;
+    for (size_t i = 0; i < replaceCount; ++i) {
+        size_t node = random() % nodeCount;
+
+        delete nodes[node];
+        nodes[node] = 0;
+        head = new Node(head);
+    }
+    
+    for (size_t i = 0; i < times; ++i)
+        validate(head);
+
+    for (Node* next ; head; head = next) {
+        next = head->next();
+        delete head;
+    }
+
+    for (size_t node = 0; node < nodeCount; ++node) {
+        if (!nodes[node])
+            continue;
+        delete nodes[node];
+    }
+    mbfree(nodes, nodeCount * sizeof(Node*));
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/fragment.h b/PerformanceTests/MallocBench/MallocBench/fragment.h
new file mode 100644 (file)
index 0000000..d479f2d
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef fragment_h
+#define fragment_h
+
+void benchmark_fragment(bool isParallel);
+void benchmark_fragment_iterate(bool isParallel);
+
+#endif // fragment_h
diff --git a/PerformanceTests/MallocBench/MallocBench/list.cpp b/PerformanceTests/MallocBench/MallocBench/list.cpp
new file mode 100644 (file)
index 0000000..e39de79
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "list.h"
+#include <stdlib.h>
+#include <strings.h>
+
+#include "mbmalloc.h"
+
+namespace {
+
+struct Node {
+    void* operator new(size_t size)
+    {
+        return mbmalloc(size);
+    }
+
+    void operator delete(void* p, size_t size)
+    {
+        mbfree(p, size);
+    }
+
+    Node(Node* next, size_t payloadSize)
+        : m_refCount(1)
+        , m_next(next)
+        , m_payload(static_cast<char*>(mbmalloc(payloadSize)))
+        , m_payloadSize(payloadSize)
+    {
+        if (m_next)
+            m_next->ref();
+        bzero(m_payload, payloadSize);
+    }
+
+    ~Node()
+    {
+        if (m_next)
+            m_next->deref();
+        mbfree(m_payload, m_payloadSize);
+    }
+
+    void ref()
+    {
+        ++m_refCount;
+    }
+
+    void deref()
+    {
+        if (m_refCount == 1)
+            delete this;
+        else
+            --m_refCount;
+    }
+
+    Node* takeNext()
+    {
+        Node* tmp = m_next;
+        m_next = 0;
+        return tmp;
+    }
+    
+    bool validate()
+    {
+        if (m_payload[0])
+            return false;
+        return true;
+    }
+
+    unsigned m_refCount;
+    Node* m_next;
+    char* m_payload;
+    size_t m_payloadSize;
+};
+
+} // namespace
+
+void benchmark_list_allocate(bool isParallel)
+{
+    Node* head = 0;
+    size_t times = 96;
+    size_t nodes = 32 * 1024;
+    if (isParallel) {
+        nodes /= cpuCount();
+        times *= 2;
+    }
+    
+    for (size_t time = 0; time < times; ++time) {
+        // Construct a list of nodes.
+        for (size_t node = 0; node < nodes; ++node) {
+            Node* oldHead = head;
+            head = new Node(oldHead, (nodes & (64 - 1)) | 1);
+            if (oldHead)
+                oldHead->deref();
+        }
+
+        // Tear down the list.
+        while (head) {
+            Node* tmp = head->takeNext();
+            head->deref();
+            head = tmp;
+        }
+    }
+}
+
+void benchmark_list_traverse(bool isParallel)
+{
+    Node* head = 0;
+    size_t times = 1 * 1024;
+    size_t nodes = 32 * 1024;
+    if (isParallel) {
+        nodes /= cpuCount();
+        times *= 4;
+    }
+
+    // Construct a list of nodes.
+    for (size_t node = 0; node < nodes; ++node) {
+        Node* oldHead = head;
+        head = new Node(oldHead, (nodes & (64 - 1)) | 1);
+        if (oldHead)
+            oldHead->deref();
+    }
+
+    // Validate the list.
+    for (size_t time = 0; time < times; ++time) {
+        for (Node* node = head; node; node = node->m_next) {
+            if (!node->validate())
+                abort();
+        }
+    }
+
+    // Tear down the list.
+    while (head) {
+        Node* tmp = head->takeNext();
+        head->deref();
+        head = tmp;
+    }
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/list.h b/PerformanceTests/MallocBench/MallocBench/list.h
new file mode 100644 (file)
index 0000000..212d217
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef list_h
+#define list_h
+
+void benchmark_list_allocate(bool isParallel);
+void benchmark_list_traverse(bool isParallel);
+
+#endif // list_h
diff --git a/PerformanceTests/MallocBench/MallocBench/main.cpp b/PerformanceTests/MallocBench/MallocBench/main.cpp
new file mode 100644 (file)
index 0000000..53781e0
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "Benchmark.h"
+#include "CommandLine.h"
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+
+using namespace std;
+
+int main(int argc, char** argv)
+{
+    CommandLine commandLine(argc, argv);
+    if (!commandLine.isValid()) {
+        commandLine.printUsage();
+        exit(1);
+    }
+
+    Benchmark benchmark(commandLine.benchmarkName(), commandLine.isParallel(), commandLine.measureHeap(), commandLine.heapSize());
+    if (!benchmark.isValid()) {
+        cout << "Invalid benchmark: " << commandLine.benchmarkName() << endl << endl;
+        benchmark.printBenchmarks();
+        exit(1);
+    }
+
+    string parallel = commandLine.isParallel() ? string(" [ parallel ]") : string(" [ not parallel ]");
+    stringstream heapSize;
+    if (commandLine.heapSize())
+        heapSize << " [ heap: " << commandLine.heapSize() / 1024 / 1024 << "MB ]";
+    else
+        heapSize << " [ heap: 0MB ]";
+    cout << "Running " << commandLine.benchmarkName() << parallel << heapSize.str() << "..." << endl;
+    benchmark.run();
+    benchmark.printReport();
+        
+    return 0;
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/mbmalloc.cpp b/PerformanceTests/MallocBench/MallocBench/mbmalloc.cpp
new file mode 100644 (file)
index 0000000..1f40c5d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include <limits>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" {
+
+void* mbmalloc(size_t size)
+{
+    return malloc(size);
+}
+
+void mbfree(void* p, size_t)
+{
+    return free(p);
+}
+
+void* mbrealloc(void* p, size_t, size_t newSize)
+{
+    return realloc(p, newSize);
+}
+
+} // extern "C"
diff --git a/PerformanceTests/MallocBench/MallocBench/mbmalloc.h b/PerformanceTests/MallocBench/MallocBench/mbmalloc.h
new file mode 100644 (file)
index 0000000..7a0db28
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef mbmalloc_h
+#define mbmalloc_h
+
+#include <stddef.h>
+
+// This file defines a default implementation of the mbmalloc API, using system
+// malloc. To test with another malloc, supply an override .dylib that exports
+// these symbols.
+
+extern "C" {
+
+void* mbmalloc(size_t);
+void mbfree(void*, size_t);
+void* mbrealloc(void*, size_t, size_t);
+
+}
+
+// Catch accidental benchmark allocation through malloc and free. All benchmark
+// code should use mbmalloc / mbfree, to call the instrumented malloc we're
+// benchmarking against.
+
+#define malloc error
+#define free error
+#define realloc error
+
+#endif // mbmalloc_h
diff --git a/PerformanceTests/MallocBench/MallocBench/medium.cpp b/PerformanceTests/MallocBench/MallocBench/medium.cpp
new file mode 100644 (file)
index 0000000..61c43fd
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "medium.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdlib>
+#include <strings.h>
+
+#include "mbmalloc.h"
+
+using namespace std;
+
+struct Object {
+    double* p;
+    size_t size;
+};
+
+void benchmark_medium(bool isParallel)
+{
+    size_t times = 1;
+
+    size_t vmSize = 1ul * 1024 * 1024 * 1024;
+    size_t objectSizeMin = 2 * 1024;
+    size_t objectSizeMax = 8 * 1024;
+    if (isParallel)
+        vmSize /= cpuCount();
+
+    size_t objectCount = vmSize / objectSizeMin;
+
+    srandom(0); // For consistency between runs.
+
+    for (size_t i = 0; i < times; ++i) {
+        Object* objects = (Object*)mbmalloc(objectCount * sizeof(Object));
+        bzero(objects, objectCount * sizeof(Object));
+
+        for (size_t i = 0, remaining = vmSize; remaining > objectSizeMin; ++i) {
+            size_t size = min(remaining, max(objectSizeMin, random() % objectSizeMax));
+            objects[i] = { (double*)mbmalloc(size), size };
+            bzero(objects[i].p, size);
+            remaining -= size;
+        }
+
+        for (size_t i = 0; i < objectCount && objects[i].p; ++i)
+            mbfree(objects[i].p, objects[i].size);
+
+        mbfree(objects, objectCount * sizeof(Object));
+    }
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/medium.h b/PerformanceTests/MallocBench/MallocBench/medium.h
new file mode 100644 (file)
index 0000000..038141a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef medium_h
+#define medium_h
+
+void benchmark_medium(bool isParallel);
+
+#endif // medium_h
+
diff --git a/PerformanceTests/MallocBench/MallocBench/message.cpp b/PerformanceTests/MallocBench/MallocBench/message.cpp
new file mode 100644 (file)
index 0000000..daccdd4
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "CPUCount.h"
+#include "message.h"
+#include <dispatch/dispatch.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "mbmalloc.h"
+
+namespace {
+
+size_t hash(size_t hash, unsigned short a, unsigned short b)
+{
+    hash += a ^ b;
+    return hash;
+}
+
+class Node {
+    static const size_t payloadCount = 128;
+public:
+    void* operator new(size_t size)
+    {
+        return mbmalloc(size);
+    }
+
+    void operator delete(void* p, size_t size)
+    {
+        mbfree(p, size);
+    }
+
+    Node()
+        : m_payload()
+    {
+    }
+
+    size_t hash(size_t hash)
+    {
+        for (size_t i = 0; i < payloadCount; i += 2)
+            hash = ::hash(hash, m_payload[i], m_payload[i + 1]);
+        return hash;
+    }
+
+private:
+    unsigned short m_payload[payloadCount];
+};
+
+class Message {
+    static const size_t nodeCount = 1 * 1024;
+
+public:
+    void* operator new(size_t size)
+    {
+        return mbmalloc(size);
+    }
+
+    void operator delete(void* p, size_t size)
+    {
+        mbfree(p, size);
+    }
+
+    Message()
+        : m_buffer(static_cast<Node**>(mbmalloc(nodeCount * sizeof(Node**))))
+    {
+        for (size_t i = 0; i < nodeCount; ++i)
+            m_buffer[i] = new Node;
+    }
+    
+    ~Message()
+    {
+        for (size_t i = 0; i < nodeCount; ++i)
+            delete m_buffer[i];
+        mbfree(m_buffer, nodeCount * sizeof(Node**));
+    }
+
+    size_t hash()
+    {
+        size_t hash = 0;
+        for (size_t i = 0; i < nodeCount; ++i)
+            hash = m_buffer[i]->hash(hash);
+        return hash;
+    }
+
+private:
+    Node** m_buffer;
+};
+
+} // namespace
+
+void benchmark_message_one(bool isParallel)
+{
+    if (isParallel)
+        abort();
+
+    const size_t times = 2048;
+    const size_t quantum = 16;
+
+    dispatch_queue_t queue = dispatch_queue_create("message", 0);
+
+    for (size_t i = 0; i < times; i += quantum) {
+        for (size_t j = 0; j < quantum; ++j) {
+            Message* message = new Message;
+            dispatch_async(queue, ^{
+                size_t hash = message->hash();
+                if (hash)
+                    abort();
+                delete message;
+            });
+        }
+        dispatch_sync(queue, ^{ });
+    }
+
+    dispatch_sync(queue, ^{ });
+
+    dispatch_release(queue);
+}
+
+void benchmark_message_many(bool isParallel)
+{
+    if (isParallel)
+        abort();
+
+    const size_t times = 768;
+    const size_t quantum = 16;
+
+    const size_t queueCount = cpuCount() - 1;
+    dispatch_queue_t queues[queueCount];
+    for (size_t i = 0; i < queueCount; ++i)
+        queues[i] = dispatch_queue_create("message", 0);
+
+    for (size_t i = 0; i < times; i += quantum) {
+        for (size_t j = 0; j < quantum; ++j) {
+            for (size_t k = 0; k < queueCount; ++k) {
+                Message* message = new Message;
+                dispatch_async(queues[k], ^{
+                    size_t hash = message->hash();
+                    if (hash)
+                        abort();
+                    delete message;
+                });
+            }
+        }
+
+        for (size_t i = 0; i < queueCount; ++i)
+            dispatch_sync(queues[i], ^{ });
+    }
+
+    for (size_t i = 0; i < queueCount; ++i)
+        dispatch_sync(queues[i], ^{ });
+
+    for (size_t i = 0; i < queueCount; ++i)
+        dispatch_release(queues[i]);
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/message.h b/PerformanceTests/MallocBench/MallocBench/message.h
new file mode 100644 (file)
index 0000000..ffc96cc
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef message_h
+#define message_h
+
+void benchmark_message_one(bool isParallel);
+void benchmark_message_many(bool isParallel);
+
+#endif // message_h
diff --git a/PerformanceTests/MallocBench/MallocBench/realloc.cpp b/PerformanceTests/MallocBench/MallocBench/realloc.cpp
new file mode 100644 (file)
index 0000000..530b101
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "realloc.h"
+#include <memory>
+#include <stddef.h>
+
+#include "mbmalloc.h"
+
+void benchmark_realloc(bool isParallel)
+{
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/realloc.h b/PerformanceTests/MallocBench/MallocBench/realloc.h
new file mode 100644 (file)
index 0000000..d85251d
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef realloc_h
+#define realloc_h
+
+void benchmark_realloc(bool isParallel);
+
+#endif // realloc_h
+
diff --git a/PerformanceTests/MallocBench/MallocBench/tree.cpp b/PerformanceTests/MallocBench/MallocBench/tree.cpp
new file mode 100644 (file)
index 0000000..dc69cab
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "tree.h"
+#include <limits>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "mbmalloc.h"
+
+namespace {
+
+struct Node {
+    void* operator new(size_t size)
+    {
+        return mbmalloc(size);
+    }
+
+    void operator delete(void* p, size_t size)
+    {
+        mbfree(p, size);
+    }
+
+    Node(Node* left, Node* right, size_t payloadSize, size_t id)
+        : m_refCount(1)
+        , m_left(left)
+        , m_right(right)
+        , m_payload(static_cast<char*>(mbmalloc(payloadSize)))
+        , m_payloadSize(payloadSize)
+        , m_id(id)
+    {
+        if (m_left)
+            m_left->ref();
+        if (m_right)
+            m_right->ref();
+        bzero(m_payload, payloadSize);
+    }
+
+    ~Node()
+    {
+        if (m_left)
+            m_left->deref();
+        if (m_right)
+            m_right->deref();
+        mbfree(m_payload, m_payloadSize);
+    }
+
+    void ref()
+    {
+        ++m_refCount;
+    }
+
+    void deref()
+    {
+        if (m_refCount == 1)
+            delete this;
+        else
+            --m_refCount;
+    }
+    
+    size_t id() { return m_id; }
+    Node* left() { return m_left; }
+    Node* right() { return m_right; }
+
+    void setLeft(Node* left)
+    {
+        left->ref();
+        if (m_left)
+            m_left->deref();
+        
+        m_left = left;
+    }
+
+    void setRight(Node* right)
+    {
+        right->ref();
+        if (m_right)
+            m_right->deref();
+        
+        m_right = right;
+    }
+
+    unsigned m_refCount;
+    Node* m_left;
+    Node* m_right;
+    char* m_payload;
+    size_t m_payloadSize;
+    size_t m_id;
+};
+
+void verify(Node* node, Node* left, Node* right)
+{
+    if (left && left->id() >= node->id())
+        abort();
+
+    if (right && right->id() <= node->id())
+        abort();
+}
+
+Node* createTree(size_t depth, size_t& counter)
+{
+    if (!depth)
+        return 0;
+
+    Node* left = createTree(depth - 1, counter);
+    size_t id = counter++;
+    Node* right = createTree(depth - 1, counter);
+
+    Node* result = new Node(left, right, ((depth * 8) & (64 - 1)) | 1, id);
+
+    verify(result, left, right);
+
+    if (left)
+        left->deref();
+    if (right)
+        right->deref();
+    return result;
+}
+
+Node* createTree(size_t depth)
+{
+    size_t counter = 0;
+    return createTree(depth, counter);
+}
+
+void churnTree(Node* node, size_t stride, size_t& counter)
+{
+    if (!node)
+        return;
+    
+    churnTree(node->left(), stride, counter);
+
+    if (node->left() && !(counter % stride)) {
+        Node* left = new Node(node->left()->left(), node->left()->right(), (counter & (64 - 1)) | 1, node->left()->id());
+        Node* right = new Node(node->right()->left(), node->right()->right(), (counter & (64 - 1)) | 1, node->right()->id());
+        node->setLeft(left);
+        node->setRight(right);
+        left->deref();
+        right->deref();
+    }
+    ++counter;
+
+    churnTree(node->right(), stride, counter);
+
+    verify(node, node->left(), node->right());
+}
+
+void churnTree(Node* tree, size_t stride)
+{
+    size_t counter;
+    churnTree(tree, stride, counter);
+}
+
+} // namespace
+
+void benchmark_tree_allocate(bool isParallel)
+{
+    size_t times = 24;
+    size_t depth = 16;
+    if (isParallel) {
+        times *= 4;
+        depth = 13;
+    }
+
+    for (size_t time = 0; time < times; ++time) {
+        Node* tree = createTree(depth);
+        tree->deref();
+    }
+}
+
+void benchmark_tree_traverse(bool isParallel)
+{
+    size_t times = 256;
+    size_t depth = 15;
+    if (isParallel) {
+        times = 512;
+        depth = 13;
+    }
+
+    Node* tree = createTree(depth);
+    for (size_t time = 0; time < times; ++time)
+        churnTree(tree, std::numeric_limits<size_t>::max()); // Reuse this to iterate and validate.
+    tree->deref();
+}
+
+void benchmark_tree_churn(bool isParallel)
+{
+    size_t times = 160;
+    size_t depth = 15;
+    if (isParallel) {
+        times *= 4;
+        depth = 12;
+    }
+
+    Node* tree = createTree(depth);
+    for (size_t time = 0; time < times; ++time)
+        churnTree(tree, 8);
+    tree->deref();
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/tree.h b/PerformanceTests/MallocBench/MallocBench/tree.h
new file mode 100644 (file)
index 0000000..cfe74af
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef tree_h
+#define tree_h
+
+void benchmark_tree_allocate(bool isParallel);
+void benchmark_tree_traverse(bool isParallel);
+void benchmark_tree_churn(bool isParallel);
+
+#endif // tree_h
diff --git a/PerformanceTests/MallocBench/run-malloc-benchmarks b/PerformanceTests/MallocBench/run-malloc-benchmarks
new file mode 100755 (executable)
index 0000000..240e13b
--- /dev/null
@@ -0,0 +1,347 @@
+#!/usr/bin/env ruby
+
+require 'getoptlong'
+require 'pathname'
+
+$binDir = "#{File.expand_path(File.dirname(__FILE__))}"
+$productDir = `perl -e 'use lib \"#{$binDir}/../../Tools/Scripts\"; use webkitdirs; print productDir()'`
+
+$benchmarks = [
+    "churn",
+    "churn --parallel",
+    "list_allocate",
+    "list_allocate --parallel",
+    "tree_allocate",
+    "tree_allocate --parallel",
+    "tree_churn",
+    "tree_churn --parallel",
+    "facebook",
+    "facebook --parallel",
+    "fragment",
+    "fragment --parallel",
+    "fragment_iterate",
+    "fragment_iterate --parallel",
+    "message_one",
+    "message_many",
+    "medium",
+    "medium --parallel",
+    "big",
+    "big --parallel",
+]
+
+$heap = 0
+$measureHeap = false
+
+def usage
+       puts "run-malloc-benchmarks [options] <Name:/path/to/dylib> [<Name:/path/to/dylib>]"
+       puts
+       puts "    Runs a suite of memory allocation and access benchmarks."
+    puts
+    puts "    <Name:/path/to/dylib> is a symbolic name followed by a folder containing a libmbmalloc.dylib."
+    puts
+    puts "    Specify \"SystemMalloc\" to test the built-in libc malloc."
+    puts "    Specify \"NanoMalloc\" to test the built-in libc malloc using the NanoMalloc zone."
+    puts
+    puts "    Example usage:"
+    puts
+    puts "        run-malloc-benchmarks SystemMalloc NanoMalloc"
+    puts "        run-malloc-benchmarks FastMalloc:/path/to/FastMalloc/Build/Products/Release/"
+    puts "        run-malloc-benchmarks --benchmark churn SystemMalloc FastMalloc:/path/to/FastMalloc/Build/Products/Release/"
+    puts
+       puts "Options:"
+    puts
+    puts "    --benchmark <benchmark>      Select a single benchmark to run instead of the full suite."
+    puts "    --heap <heap>           Set a baseline heap size."
+    puts
+end
+
+class Dylib
+    attr_reader :name
+    attr_reader :path
+
+    def initialize(name, path)
+        @name = name
+        @path = File.join(path, "libmbmalloc.dylib")
+    end
+end
+
+class Results
+    attr_reader :executionTime
+    attr_reader :peakMemory
+    attr_reader :memoryAtEnd
+
+    def initialize(executionTime, peakMemory, memoryAtEnd)
+        @executionTime = executionTime
+        @peakMemory = peakMemory
+        @memoryAtEnd = memoryAtEnd
+    end
+end
+
+class Stat
+    attr_reader :benchmark
+    attr_reader :result
+
+    def initialize(benchmark, result)
+        @benchmark = benchmark
+        @result = result[/\d+/].to_i
+    end
+end
+
+class TimeStat < Stat
+    def to_s
+       @result + "ms"
+    end
+end
+
+class MemoryStat < Stat
+    def to_s
+       @result + "kB"
+    end
+end
+
+class PeakMemoryStat < Stat
+    def to_s
+       @result + "kB"
+    end
+end
+
+def lpad(str, chars)
+    if str.length > chars
+        str
+    else
+        "%#{chars}s"%(str)
+    end
+end
+
+def rpad(str, chars)
+    while str.length < chars
+        str += " "
+    end
+    str
+end
+
+def computeArithmeticMean(array)
+  sum = 0.0
+  array.each {
+    | value |
+    sum += value
+  }
+  (sum / array.length)
+end
+
+def computeGeometricMean(array)
+  mult = 1.0
+  array.each {
+    | value |
+    mult *= value ? value : 1.0
+  }
+  (mult ** (1.0 / array.length))
+end
+
+def computeHarmonicMean(array)
+  1.0 / computeArithmeticMean(array.collect{ | value | 1.0 / value })
+end
+
+def lowerIsBetter(a, b, better, worse)
+    if b < a
+        return "^ " + (a.to_f / b.to_f).round(2).to_s + "x " + better
+    end
+
+    if b == a
+        return ""
+    end
+
+    "! " + (b.to_f / a.to_f).round(2).to_s + "x " + worse
+end
+
+
+def lowerIsFaster(a, b)
+    lowerIsBetter(a, b, "faster", "slower")
+end
+
+def lowerIsSmaller(a, b)
+    lowerIsBetter(a, b, "smaller", "bigger")
+end
+
+def numberWithDelimiter(number)
+    number.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse
+end
+
+def prettify(number, suffix)
+    numberWithDelimiter(number) + suffix
+end
+
+def parseOptions
+    GetoptLong.new(
+        ['--benchmark', GetoptLong::REQUIRED_ARGUMENT],
+        ['--heap', GetoptLong::REQUIRED_ARGUMENT],
+        ['--measure-heap', GetoptLong::NO_ARGUMENT],
+        ['--help', GetoptLong::NO_ARGUMENT],
+    ).each {
+        | opt, arg |
+        case opt
+        when '--benchmark'
+            $benchmarks = [ arg ]
+        when '--heap'
+            $heap = arg
+        when '--measure-heap'
+            $measureHeap = true
+        when '--help'
+            usage
+            exit 1
+        else
+          raise "bad option: #{opt}"
+        end
+    }
+
+    if ARGV.length < 1
+        puts "Error: No dylib specified."
+        exit 1
+    end
+
+    dylibs = []
+    ARGV.each {
+        | arg |
+        if arg == "SystemMalloc"
+            dylib = Dylib.new("SystemMalloc", $productDir)
+        elsif arg == "NanoMalloc"
+            dylib = Dylib.new("NanoMalloc", $productDir)
+        else
+            name = arg.split(":")[0]
+            path = arg.split(":")[1]
+            if !name || name.length < 1 ||
+                !path || path.length < 1
+                puts "Invalid <Name:/path/to/dylib>: '#{arg}'."
+                exit 1
+            end
+
+            dylib = Dylib.new(name, File.expand_path(path))
+        end
+
+        if !File.exists?(dylib.path)
+            puts "File not found: #{dylib.path}."
+            exit 1
+        end
+
+        dylibs.push(dylib)
+    }
+    dylibs
+end
+
+def runBenchmarks(dylibs)
+    executionTime = []
+    peakMemory = []
+    memoryAtEnd = []
+
+    $benchmarks.each {
+        | benchmark |
+
+        executionTime.push([])
+        peakMemory.push([])
+        memoryAtEnd.push([])
+
+        dylibs.each {
+            | dylib |
+
+            $stderr.print "\rRUNNING #{dylib.name}: #{benchmark}...                "
+            env = "DYLD_LIBRARY_PATH='#{Pathname.new(dylib.path).dirname}' "
+            if dylib.name == "NanoMalloc"
+                env += "MallocNanoZone=1 "
+            end
+            input = "cd '#{$productDir}'; #{env} '#{$productDir}/MallocBench' --benchmark #{benchmark} --heap #{$heap} #{$measureHeap ? '--measure-heap' : ''}"
+            output =`#{input}`
+            splitOutput = output.split("\n")
+
+            executionTime[-1].push(TimeStat.new(benchmark, splitOutput[1]))
+            peakMemory[-1].push(PeakMemoryStat.new(benchmark, splitOutput.length > 3 ? splitOutput[3] : "0"))
+            memoryAtEnd[-1].push(MemoryStat.new(benchmark, splitOutput.length > 2 ? splitOutput[2] : "0"))
+        }
+    }
+    $stderr.print "\r                                                                                \n"
+
+    Results.new(executionTime, peakMemory, memoryAtEnd)
+end
+
+def printResults(dylibs, results)
+    def printHeader(dylibs, fieldSize)
+        print
+        print lpad("", fieldSize)
+        print lpad(dylibs[0].name, fieldSize)
+        if dylibs[1]
+            print lpad(dylibs[1].name, fieldSize)
+            print lpad("Δ", fieldSize * 1.25)
+        end
+        print "\n"
+    end
+
+    def printMetric(name, results, compareFunction, suffix, fieldSize)
+        def printMean(name, results, meanFunction, compareFunction, suffix, fieldSize)
+            means = []
+
+            means.push(meanFunction.call(results.collect { | stats | stats[0].result }))
+            print rpad("    " + name, fieldSize)
+            print lpad("#{prettify(means[0].round, suffix)}", fieldSize)
+
+            if results[0][1]
+                means.push(meanFunction.call(results.collect { | stats | stats[1].result }))
+                print lpad("#{prettify(means[1].round, suffix)}", fieldSize)
+                print lpad(compareFunction.call(means[0], means[1]), fieldSize * 1.25)
+            end
+
+            print "\n"
+        end
+
+        if results[0][0].result == 0
+            return
+        end
+
+        print name + ":\n"
+        results.each {
+            | stats |
+
+            print rpad("    " + stats[0].benchmark, fieldSize)
+            print lpad("#{prettify(stats[0].result, suffix)}", fieldSize)
+
+            if stats[1]
+                print lpad("#{prettify(stats[1].result, suffix)}", fieldSize)
+                print lpad(compareFunction.call(stats[0].result, stats[1].result), fieldSize * 1.25)
+            end
+
+            print "\n"
+        }
+
+        print "\n"
+
+        printMean("<geometric mean>", results, method(:computeGeometricMean), compareFunction, suffix, fieldSize)
+        printMean("<arithmetic mean>", results, method(:computeArithmeticMean), compareFunction, suffix, fieldSize)
+        printMean("<harmonic mean>", results, method(:computeHarmonicMean), compareFunction, suffix, fieldSize)
+
+        print "\n"
+    end
+
+    fieldSize = ($benchmarks + ["<arithmetic mean>"]).collect {
+        | benchmark |
+        benchmark.size
+    }.max + 4
+
+    printHeader(dylibs, fieldSize)
+    printMetric("Execution Time", results.executionTime, method(:lowerIsFaster), "ms", fieldSize)
+    printMetric("Peak Memory", results.peakMemory, method(:lowerIsSmaller), "kB", fieldSize)
+    printMetric("Memory at End", results.memoryAtEnd, method(:lowerIsSmaller), "kB", fieldSize)
+end
+
+def main
+    begin
+        dylibs = parseOptions()
+        results = runBenchmarks(dylibs)
+        printResults(dylibs, results)
+    rescue => exception
+        puts
+        puts
+        puts exception
+        puts exception.backtrace
+        puts
+    end
+end
+
+main()