MallocBench: Added recording for nimlang website, new recording details and added...
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Feb 2016 22:02:24 +0000 (22:02 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 22 Feb 2016 22:02:24 +0000 (22:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=154485

Reviewed by Geoff Garen.

Added new capabilities to MallocBench.  These include:
    Added a recording of http://nim-lang.org/docs/lib.html.
    Added thread id to the recording and the ability to playback switching threads in MallocBench
    Added aligned allocations to recordings and the ability to playback
    Added --use-thread-id option to honor recorded thread ids
    Added --detailed-report to output remaining allocations by size after playback
    Added --no-warmup to not run the warm up iteration

Changed the way that options are passed down to the benchmarks.  Instead of passing individual
boolean or numeric option values, just pass a reference the CommandLine itself.  Each benchmark
can access the options that are appropriate.  The Benchmark class also uses the options for
is parallel, run counts and warm up.

Added thread id and aligned malloc to the Op by noticing that structure padding and Opcode allowed
for another 32 bits of data.  Breaking that unused 32 bits into a 16 bit thread id value and a
16 bit log base 2 of the alignment for aligned malloc allowed for existing recordings to playback
without any incompatibilities.

Threaded operation is simulated by creating threads as needed.  As long as the next Op's thread id
is the same as the last, operation continues as normal.  When the next Op has a different thread id,
we switch to that thread using the shared Op stream to continue playing back.  There is a mutex to
assure that only one thread is really running at a time and a condition variable used to wait
that the current thread id matches each block thread's thread id.  This doesn't simulate true
concurrent threading, but is instead plays back Ops recorded for multiple thread faithfully.

* MallocBench/MallocBench.xcodeproj/project.pbxproj:
* MallocBench/MallocBench/Benchmark.cpp:
(deallocateHeap):
(Benchmark::Benchmark):
(Benchmark::runOnce):
(Benchmark::run):
* MallocBench/MallocBench/Benchmark.h:
(Benchmark::isValid):
* MallocBench/MallocBench/CommandLine.cpp:
(CommandLine::printUsage):
* MallocBench/MallocBench/CommandLine.h:
(CommandLine::isValid):
(CommandLine::benchmarkName):
(CommandLine::isParallel):
(CommandLine::useThreadID):
(CommandLine::detailedReport):
(CommandLine::warmUp):
(CommandLine::heapSize):
(CommandLine::runs):
* MallocBench/MallocBench/Interpreter.cpp:
(Interpreter::Interpreter):
(Interpreter::run):
(Interpreter::readOps):
(Interpreter::doOnSameThread):
(Interpreter::switchToThread):
(Interpreter::detailedReport):
(compute2toPower):
(writeData):
(Interpreter::doMallocOp):
(Interpreter::Thread::Thread):
(Interpreter::Thread::stop):
(Interpreter::Thread::~Thread):
(Interpreter::Thread::runThread):
(Interpreter::Thread::waitToRun):
(Interpreter::Thread::switchTo):
* MallocBench/MallocBench/Interpreter.h:
(Interpreter::Thread::isMainThread):
* MallocBench/MallocBench/alloc_free.cpp: Added.
(benchmark_alloc_free):
* MallocBench/MallocBench/alloc_free.h: Added.
* MallocBench/MallocBench/balloon.cpp:
(benchmark_balloon):
* MallocBench/MallocBench/balloon.h:
* MallocBench/MallocBench/big.cpp:
(benchmark_big):
* MallocBench/MallocBench/big.h:
* MallocBench/MallocBench/churn.cpp:
(benchmark_churn):
* MallocBench/MallocBench/churn.h:
* MallocBench/MallocBench/facebook.cpp:
(benchmark_facebook):
* MallocBench/MallocBench/facebook.h:
* MallocBench/MallocBench/flickr.cpp:
(benchmark_flickr):
(benchmark_flickr_memory_warning):
* MallocBench/MallocBench/flickr.h:
* MallocBench/MallocBench/fragment.cpp:
(validate):
(benchmark_fragment):
(benchmark_fragment_iterate):
* MallocBench/MallocBench/fragment.h:
* MallocBench/MallocBench/list.cpp:
(benchmark_list_allocate):
(benchmark_list_traverse):
* MallocBench/MallocBench/list.h:
* MallocBench/MallocBench/main.cpp:
(main):
* MallocBench/MallocBench/medium.cpp:
(benchmark_medium):
* MallocBench/MallocBench/medium.h:
* MallocBench/MallocBench/memalign.cpp:
(test):
(benchmark_memalign):
* MallocBench/MallocBench/memalign.h:
* MallocBench/MallocBench/message.cpp:
(benchmark_message_one):
(benchmark_message_many):
* MallocBench/MallocBench/message.h:
* MallocBench/MallocBench/nimlang.cpp: Added.
(benchmark_nimlang):
* MallocBench/MallocBench/nimlang.h: Added.
* MallocBench/MallocBench/nimlang.ops: Added.
* MallocBench/MallocBench/realloc.cpp:
(benchmark_realloc):
* MallocBench/MallocBench/realloc.h:
* MallocBench/MallocBench/reddit.cpp:
(benchmark_reddit):
(benchmark_reddit_memory_warning):
* MallocBench/MallocBench/reddit.h:
* MallocBench/MallocBench/stress.cpp:
(deallocate):
(benchmark_stress):
* MallocBench/MallocBench/stress.h:
* MallocBench/MallocBench/stress_aligned.cpp:
(benchmark_stress_aligned):
* MallocBench/MallocBench/stress_aligned.h:
* MallocBench/MallocBench/theverge.cpp:
(benchmark_theverge):
(benchmark_theverge_memory_warning):
* MallocBench/MallocBench/theverge.h:
* MallocBench/MallocBench/tree.cpp:
(benchmark_tree_allocate):
(benchmark_tree_traverse):
(benchmark_tree_churn):
* MallocBench/MallocBench/tree.h:
* MallocBench/run-malloc-benchmarks:

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

47 files changed:
PerformanceTests/ChangeLog
PerformanceTests/MallocBench/MallocBench.xcodeproj/project.pbxproj
PerformanceTests/MallocBench/MallocBench/Benchmark.cpp
PerformanceTests/MallocBench/MallocBench/Benchmark.h
PerformanceTests/MallocBench/MallocBench/CommandLine.cpp
PerformanceTests/MallocBench/MallocBench/CommandLine.h
PerformanceTests/MallocBench/MallocBench/Interpreter.cpp
PerformanceTests/MallocBench/MallocBench/Interpreter.h
PerformanceTests/MallocBench/MallocBench/alloc_free.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/alloc_free.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/balloon.cpp
PerformanceTests/MallocBench/MallocBench/balloon.h
PerformanceTests/MallocBench/MallocBench/big.cpp
PerformanceTests/MallocBench/MallocBench/big.h
PerformanceTests/MallocBench/MallocBench/churn.cpp
PerformanceTests/MallocBench/MallocBench/churn.h
PerformanceTests/MallocBench/MallocBench/facebook.cpp
PerformanceTests/MallocBench/MallocBench/facebook.h
PerformanceTests/MallocBench/MallocBench/flickr.cpp
PerformanceTests/MallocBench/MallocBench/flickr.h
PerformanceTests/MallocBench/MallocBench/fragment.cpp
PerformanceTests/MallocBench/MallocBench/fragment.h
PerformanceTests/MallocBench/MallocBench/list.cpp
PerformanceTests/MallocBench/MallocBench/list.h
PerformanceTests/MallocBench/MallocBench/main.cpp
PerformanceTests/MallocBench/MallocBench/medium.cpp
PerformanceTests/MallocBench/MallocBench/medium.h
PerformanceTests/MallocBench/MallocBench/memalign.cpp
PerformanceTests/MallocBench/MallocBench/memalign.h
PerformanceTests/MallocBench/MallocBench/message.cpp
PerformanceTests/MallocBench/MallocBench/message.h
PerformanceTests/MallocBench/MallocBench/nimlang.cpp [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/nimlang.h [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/nimlang.ops [new file with mode: 0644]
PerformanceTests/MallocBench/MallocBench/realloc.cpp
PerformanceTests/MallocBench/MallocBench/realloc.h
PerformanceTests/MallocBench/MallocBench/reddit.cpp
PerformanceTests/MallocBench/MallocBench/reddit.h
PerformanceTests/MallocBench/MallocBench/stress.cpp
PerformanceTests/MallocBench/MallocBench/stress.h
PerformanceTests/MallocBench/MallocBench/stress_aligned.cpp
PerformanceTests/MallocBench/MallocBench/stress_aligned.h
PerformanceTests/MallocBench/MallocBench/theverge.cpp
PerformanceTests/MallocBench/MallocBench/theverge.h
PerformanceTests/MallocBench/MallocBench/tree.cpp
PerformanceTests/MallocBench/MallocBench/tree.h
PerformanceTests/MallocBench/run-malloc-benchmarks

index 1329959..bc8651e 100644 (file)
@@ -1,3 +1,142 @@
+2016-02-19  Michael Saboff  <msaboff@apple.com>
+
+        MallocBench: Added recording for nimlang website, new recording details and added new options
+        https://bugs.webkit.org/show_bug.cgi?id=154485
+
+        Reviewed by Geoff Garen.
+
+        Added new capabilities to MallocBench.  These include:
+            Added a recording of http://nim-lang.org/docs/lib.html.
+            Added thread id to the recording and the ability to playback switching threads in MallocBench
+            Added aligned allocations to recordings and the ability to playback 
+            Added --use-thread-id option to honor recorded thread ids
+            Added --detailed-report to output remaining allocations by size after playback
+            Added --no-warmup to not run the warm up iteration
+
+        Changed the way that options are passed down to the benchmarks.  Instead of passing individual
+        boolean or numeric option values, just pass a reference the CommandLine itself.  Each benchmark
+        can access the options that are appropriate.  The Benchmark class also uses the options for
+        is parallel, run counts and warm up.
+
+        Added thread id and aligned malloc to the Op by noticing that structure padding and Opcode allowed
+        for another 32 bits of data.  Breaking that unused 32 bits into a 16 bit thread id value and a
+        16 bit log base 2 of the alignment for aligned malloc allowed for existing recordings to playback
+        without any incompatibilities.
+
+        Threaded operation is simulated by creating threads as needed.  As long as the next Op's thread id
+        is the same as the last, operation continues as normal.  When the next Op has a different thread id,
+        we switch to that thread using the shared Op stream to continue playing back.  There is a mutex to
+        assure that only one thread is really running at a time and a condition variable used to wait
+        that the current thread id matches each block thread's thread id.  This doesn't simulate true
+        concurrent threading, but is instead plays back Ops recorded for multiple thread faithfully.
+
+        * MallocBench/MallocBench.xcodeproj/project.pbxproj:
+        * MallocBench/MallocBench/Benchmark.cpp:
+        (deallocateHeap):
+        (Benchmark::Benchmark):
+        (Benchmark::runOnce):
+        (Benchmark::run):
+        * MallocBench/MallocBench/Benchmark.h:
+        (Benchmark::isValid):
+        * MallocBench/MallocBench/CommandLine.cpp:
+        (CommandLine::printUsage):
+        * MallocBench/MallocBench/CommandLine.h:
+        (CommandLine::isValid):
+        (CommandLine::benchmarkName):
+        (CommandLine::isParallel):
+        (CommandLine::useThreadID):
+        (CommandLine::detailedReport):
+        (CommandLine::warmUp):
+        (CommandLine::heapSize):
+        (CommandLine::runs):
+        * MallocBench/MallocBench/Interpreter.cpp:
+        (Interpreter::Interpreter):
+        (Interpreter::run):
+        (Interpreter::readOps):
+        (Interpreter::doOnSameThread):
+        (Interpreter::switchToThread):
+        (Interpreter::detailedReport):
+        (compute2toPower):
+        (writeData):
+        (Interpreter::doMallocOp):
+        (Interpreter::Thread::Thread):
+        (Interpreter::Thread::stop):
+        (Interpreter::Thread::~Thread):
+        (Interpreter::Thread::runThread):
+        (Interpreter::Thread::waitToRun):
+        (Interpreter::Thread::switchTo):
+        * MallocBench/MallocBench/Interpreter.h:
+        (Interpreter::Thread::isMainThread):
+        * MallocBench/MallocBench/alloc_free.cpp: Added.
+        (benchmark_alloc_free):
+        * MallocBench/MallocBench/alloc_free.h: Added.
+        * MallocBench/MallocBench/balloon.cpp:
+        (benchmark_balloon):
+        * MallocBench/MallocBench/balloon.h:
+        * MallocBench/MallocBench/big.cpp:
+        (benchmark_big):
+        * MallocBench/MallocBench/big.h:
+        * MallocBench/MallocBench/churn.cpp:
+        (benchmark_churn):
+        * MallocBench/MallocBench/churn.h:
+        * MallocBench/MallocBench/facebook.cpp:
+        (benchmark_facebook):
+        * MallocBench/MallocBench/facebook.h:
+        * MallocBench/MallocBench/flickr.cpp:
+        (benchmark_flickr):
+        (benchmark_flickr_memory_warning):
+        * MallocBench/MallocBench/flickr.h:
+        * MallocBench/MallocBench/fragment.cpp:
+        (validate):
+        (benchmark_fragment):
+        (benchmark_fragment_iterate):
+        * MallocBench/MallocBench/fragment.h:
+        * MallocBench/MallocBench/list.cpp:
+        (benchmark_list_allocate):
+        (benchmark_list_traverse):
+        * MallocBench/MallocBench/list.h:
+        * MallocBench/MallocBench/main.cpp:
+        (main):
+        * MallocBench/MallocBench/medium.cpp:
+        (benchmark_medium):
+        * MallocBench/MallocBench/medium.h:
+        * MallocBench/MallocBench/memalign.cpp:
+        (test):
+        (benchmark_memalign):
+        * MallocBench/MallocBench/memalign.h:
+        * MallocBench/MallocBench/message.cpp:
+        (benchmark_message_one):
+        (benchmark_message_many):
+        * MallocBench/MallocBench/message.h:
+        * MallocBench/MallocBench/nimlang.cpp: Added.
+        (benchmark_nimlang):
+        * MallocBench/MallocBench/nimlang.h: Added.
+        * MallocBench/MallocBench/nimlang.ops: Added.
+        * MallocBench/MallocBench/realloc.cpp:
+        (benchmark_realloc):
+        * MallocBench/MallocBench/realloc.h:
+        * MallocBench/MallocBench/reddit.cpp:
+        (benchmark_reddit):
+        (benchmark_reddit_memory_warning):
+        * MallocBench/MallocBench/reddit.h:
+        * MallocBench/MallocBench/stress.cpp:
+        (deallocate):
+        (benchmark_stress):
+        * MallocBench/MallocBench/stress.h:
+        * MallocBench/MallocBench/stress_aligned.cpp:
+        (benchmark_stress_aligned):
+        * MallocBench/MallocBench/stress_aligned.h:
+        * MallocBench/MallocBench/theverge.cpp:
+        (benchmark_theverge):
+        (benchmark_theverge_memory_warning):
+        * MallocBench/MallocBench/theverge.h:
+        * MallocBench/MallocBench/tree.cpp:
+        (benchmark_tree_allocate):
+        (benchmark_tree_traverse):
+        (benchmark_tree_churn):
+        * MallocBench/MallocBench/tree.h:
+        * MallocBench/run-malloc-benchmarks:
+
 2016-02-11  Jon Lee  <jonlee@apple.com>
 
         Fix a missing refactoring.
index e6f8980..d847fc1 100644 (file)
@@ -38,6 +38,8 @@
                14D6322E1A69BE0B00A8F84F /* memalign.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14D6322C1A69BE0B00A8F84F /* memalign.cpp */; };
                14E11932177ECC8B003A8D15 /* CPUCount.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14E11930177ECC8B003A8D15 /* CPUCount.cpp */; };
                14FCA36119A7C917001CFDA9 /* stress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14FCA35F19A7C917001CFDA9 /* stress.cpp */; };
+               65E401A61C657A87003C6E9C /* nimlang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65E401A41C657A87003C6E9C /* nimlang.cpp */; };
+               65E401AC1C73B068003C6E9C /* alloc_free.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65E401AA1C73B068003C6E9C /* alloc_free.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
                14E11934177F5219003A8D15 /* mbmalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mbmalloc.h; path = MallocBench/mbmalloc.h; sourceTree = "<group>"; };
                14FCA35F19A7C917001CFDA9 /* stress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stress.cpp; path = MallocBench/stress.cpp; sourceTree = "<group>"; };
                14FCA36019A7C917001CFDA9 /* stress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stress.h; path = MallocBench/stress.h; sourceTree = "<group>"; };
+               65E401A41C657A87003C6E9C /* nimlang.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nimlang.cpp; path = MallocBench/nimlang.cpp; sourceTree = "<group>"; };
+               65E401A51C657A87003C6E9C /* nimlang.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nimlang.h; path = MallocBench/nimlang.h; sourceTree = "<group>"; };
+               65E401AA1C73B068003C6E9C /* alloc_free.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = alloc_free.cpp; path = MallocBench/alloc_free.cpp; sourceTree = "<group>"; };
+               65E401AB1C73B068003C6E9C /* alloc_free.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = alloc_free.h; path = MallocBench/alloc_free.h; sourceTree = "<group>"; };
+               65E401AD1C77E7C8003C6E9C /* nimlang.ops */ = {isa = PBXFileReference; lastKnownFileType = file; name = nimlang.ops; path = MallocBench/nimlang.ops; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                14E11933177F51AC003A8D15 /* Benchmarks */ = {
                        isa = PBXGroup;
                        children = (
+                               65E401AA1C73B068003C6E9C /* alloc_free.cpp */,
+                               65E401AB1C73B068003C6E9C /* alloc_free.h */,
                                14105E7D18DF7D73003A106E /* balloon.cpp */,
                                14105E7E18DF7D73003A106E /* balloon.h */,
                                14CE4A5E17BD355800288DAA /* big.cpp */,
                                1444AE94177E8DF200F8030A /* message.cpp */,
                                1444AE95177E8DF200F8030A /* message.h */,
                                14105E8018E13EEC003A106E /* realloc.cpp */,
+                               65E401A41C657A87003C6E9C /* nimlang.cpp */,
+                               65E401AD1C77E7C8003C6E9C /* nimlang.ops */,
+                               65E401A51C657A87003C6E9C /* nimlang.h */,
                                14105E8118E13EEC003A106E /* realloc.h */,
                                1447AE9718FB59D900B3D7FF /* reddit_memory_warning.ops */,
                                1447AE8A18FB584200B3D7FF /* reddit.cpp */,
                                14CE4A6017BD355800288DAA /* big.cpp in Sources */,
                                14976ED1177E4AF7006B819A /* tree.cpp in Sources */,
                                1444AE96177E8DF200F8030A /* message.cpp in Sources */,
+                               65E401AC1C73B068003C6E9C /* alloc_free.cpp in Sources */,
                                14452CEF177D47110097E057 /* churn.cpp in Sources */,
                                14452CB0177D24460097E057 /* main.cpp in Sources */,
                                14FCA36119A7C917001CFDA9 /* stress.cpp in Sources */,
                                1447AE9018FB584200B3D7FF /* flickr.cpp in Sources */,
                                14976EC8177E3649006B819A /* list.cpp in Sources */,
                                14976ECC177E3C87006B819A /* CommandLine.cpp in Sources */,
+                               65E401A61C657A87003C6E9C /* nimlang.cpp in Sources */,
                                1447AE9218FB584200B3D7FF /* theverge.cpp in Sources */,
                                14D0BFF31A6F4D3B00109F31 /* stress_aligned.cpp in Sources */,
                                1451FAED18B14B7100DB6D47 /* medium.cpp in Sources */,
index 701c3b0..23cf3dd 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "Benchmark.h"
 #include "CPUCount.h"
+#include "alloc_free.h"
 #include "balloon.h"
 #include "big.h"
 #include "churn.h"
 #include "medium.h"
 #include "memalign.h"
 #include "message.h"
+#include "nimlang.h"
 #include "reddit.h"
 #include "realloc.h"
+#include "simple.h"
 #include "stress.h"
 #include "stress_aligned.h"
 #include "theverge.h"
@@ -61,6 +64,7 @@ struct BenchmarkPair {
 };
 
 static const BenchmarkPair benchmarkPairs[] = {
+    { "alloc_free", benchmark_alloc_free },
     { "balloon", benchmark_balloon },
     { "big", benchmark_big },
     { "churn", benchmark_churn },
@@ -75,6 +79,7 @@ static const BenchmarkPair benchmarkPairs[] = {
     { "memalign", benchmark_memalign },
     { "message_many", benchmark_message_many },
     { "message_one", benchmark_message_one },
+    { "nimlang", benchmark_nimlang },
     { "realloc", benchmark_realloc },
     { "reddit", benchmark_reddit },
     { "reddit_memory_warning", benchmark_reddit_memory_warning },
@@ -127,15 +132,13 @@ static void deallocateHeap(void*** chunks, size_t heapSize, size_t chunkSize, si
     mbfree(chunks, chunkCount * sizeof(void**));
 }
 
-Benchmark::Benchmark(const string& benchmarkName, bool isParallel, size_t runs, size_t heapSize)
+Benchmark::Benchmark(CommandLine& commandLine)
     : m_benchmarkPair()
     , m_elapsedTime()
-    , m_isParallel(isParallel)
-    , m_heapSize(heapSize)
-    , m_runs(runs)
+    , m_commandLine(commandLine)
 {
     const BenchmarkPair* benchmarkPair = std::find(
-        benchmarkPairs, benchmarkPairs + benchmarksPairsCount, benchmarkName);
+        benchmarkPairs, benchmarkPairs + benchmarksPairsCount, m_commandLine.benchmarkName());
     if (benchmarkPair == benchmarkPairs + benchmarksPairsCount)
         return;
     
@@ -151,8 +154,8 @@ void Benchmark::printBenchmarks()
 
 void Benchmark::runOnce()
 {
-    if (!m_isParallel) {
-        m_benchmarkPair->function(m_isParallel);
+    if (!m_commandLine.isParallel()) {
+        m_benchmarkPair->function(m_commandLine);
         return;
     }
 
@@ -160,7 +163,7 @@ void Benchmark::runOnce()
 
     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);
+            m_benchmarkPair->function(m_commandLine);
         });
     }
 
@@ -174,20 +177,23 @@ void Benchmark::run()
     static const size_t objectSize = 32;
     static const size_t chunkSize = 1024 * 1024;
     
-    void*** heap = allocateHeap(m_heapSize, chunkSize, objectSize);
+    void*** heap = allocateHeap(m_commandLine.heapSize(), chunkSize, objectSize);
 
-    runOnce(); // Warmup run.
+    if (m_commandLine.warmUp())
+        runOnce(); // Warmup run.
 
-    for (size_t i = 0; i < m_runs; ++i) {
+    size_t runs = m_commandLine.runs();
+
+    for (size_t i = 0; i < runs; ++i) {
         double start = currentTimeMS();
         runOnce();
         double end = currentTimeMS();
         double elapsed = end - start;
         m_elapsedTime += elapsed;
     }
-    m_elapsedTime /= m_runs;
+    m_elapsedTime /= runs;
 
-    deallocateHeap(heap, m_heapSize, chunkSize, objectSize);
+    deallocateHeap(heap, m_commandLine.heapSize(), chunkSize, objectSize);
     
     mbscavenge();
     m_memory = currentMemoryBytes();
index 1aee7a9..9a449b9 100644 (file)
 #ifndef Benchmark_h
 #define Benchmark_h
 
+#include "CommandLine.h"
 #include <map>
 #include <string>
 
-typedef void (*BenchmarkFunction)(bool isParallel);
+typedef void (*BenchmarkFunction)(CommandLine& commandLine);
 struct BenchmarkPair;
 
 class Benchmark {
@@ -59,7 +60,7 @@ public:
     static double currentTimeMS();
     static Memory currentMemoryBytes();
 
-    Benchmark(const std::string&, bool isParallel, size_t runs, size_t heapSize);
+    Benchmark(CommandLine&);
     
     bool isValid() { return m_benchmarkPair; }
     
@@ -75,9 +76,8 @@ private:
     MapType m_map;
 
     const BenchmarkPair* m_benchmarkPair;
-    bool m_isParallel;
-    size_t m_runs;
-    size_t m_heapSize;
+
+    CommandLine& m_commandLine;
 
     Memory m_memory;
     double m_elapsedTime;
index b2ad0a3..26a7463 100644 (file)
 struct option CommandLine::longOptions[] =
 {
     {"benchmark", required_argument, 0, 'b'},
+    {"detailed-report", no_argument, 0, 'd'},
+    {"no-warmup", no_argument, 0, 'n' },
     {"parallel", no_argument, 0, 'p'},
     {"heap", required_argument, 0, 'h'},
     {"runs", required_argument, 0, 'r'},
+    {"use-thread-id", no_argument, 0, 't'},
     {0, 0, 0, 0}
 };
 
 CommandLine::CommandLine(int argc, char** argv)
     : m_argc(argc)
     , m_argv(argv)
+    , m_detailedReport(false)
     , m_isParallel(false)
+    , m_useThreadID(false)
+    , m_warmUp(true)
     , m_heapSize(0)
     , m_runs(4)
 {
     int optionIndex = 0;
     int ch;
-    while ((ch = getopt_long(argc, argv, "b:p:h:r", longOptions, &optionIndex)) != -1) {
+    while ((ch = getopt_long(argc, argv, "b:dnph:r:t", longOptions, &optionIndex)) != -1) {
         switch (ch)
         {
             case 'b':
                 m_benchmarkName = optarg;
                 break;
 
+            case 'd':
+                m_detailedReport = true;
+                break;
+                
+            case 'n':
+                m_warmUp = false;
+                break;
+
             case 'p':
                 m_isParallel = true;
                 break;
-
+                
             case 'h':
                 m_heapSize = atoi(optarg) * 1024 * 1024;
                 break;
@@ -64,6 +78,10 @@ CommandLine::CommandLine(int argc, char** argv)
                 m_runs = atoi(optarg);
                 break;
 
+            case 't':
+                m_useThreadID = true;
+                break;
+                
             default:
                 break;
         }
@@ -75,5 +93,5 @@ 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 ] [ --heap MB ]" << std::endl;
+    std::cout << "Usage: " << program << " --benchmark benchmark_name [--parallel ] [--use-thread-id ] [--detailed-report] [--no-warmup] [--runs count] [--heap MB ]" << std::endl;
 }
index 192c93e..3617951 100644 (file)
@@ -23,6 +23,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
+#ifndef CommandLine_h
+#define CommandLine_h
+
 #include <string>
 
 class CommandLine {
@@ -32,6 +35,9 @@ public:
     bool isValid() { return m_benchmarkName.size(); }
     const std::string& benchmarkName() { return m_benchmarkName; }
     bool isParallel() { return m_isParallel; }
+    bool useThreadID() { return m_useThreadID; }
+    bool detailedReport() { return m_detailedReport; }
+    bool warmUp() { return m_warmUp; }
     size_t heapSize() { return m_heapSize; }
     size_t runs() { return m_runs; }
 
@@ -43,7 +49,12 @@ private:
     int m_argc;
     char** m_argv;
     std::string m_benchmarkName;
+    bool m_detailedReport;
     bool m_isParallel;
+    bool m_useThreadID;
+    bool m_warmUp;
     size_t m_heapSize;
     size_t m_runs;
 };
+
+#endif // CommandLine_h
\ No newline at end of file
index d9ea0ed..726e502 100644 (file)
@@ -30,7 +30,9 @@
 #include <cstdlib>
 #include <errno.h>
 #include <fcntl.h>
+#include <iostream>
 #include <string>
+#include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #include "mbmalloc.h"
 
-Interpreter::Interpreter(const char* fileName, bool shouldFreeAllObjects)
+Interpreter::Interpreter(const char* fileName, bool shouldFreeAllObjects, bool useThreadId)
     : m_shouldFreeAllObjects(shouldFreeAllObjects)
+    , m_useThreadId(useThreadId)
+    , m_currentThreadId(0)
+    , m_ops(1024)
 {
     m_fd = open(fileName, O_RDWR, S_IRUSR | S_IWUSR);
     if (m_fd == -1)
@@ -84,43 +89,17 @@ 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_malloc: {
-                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_free: {
-                if (!m_objects[op.slot].object)
-                    continue;
-                mbfree(m_objects[op.slot].object, m_objects[op.slot].size);
-                m_objects[op.slot] = { 0, 0 };
-                break;
-            }
-            case op_realloc: {
-                if (!m_objects[op.slot].object)
-                    continue;
-                m_objects[op.slot] = { mbrealloc(m_objects[op.slot].object, m_objects[op.slot].size, op.size), op.size };
-                break;
-            }
-            default: {
-                fprintf(stderr, "bad opcode: %d\n", op.opcode);
-                abort();
-                break;
-            }
-            }
-        }
-    }
+    m_remaining = m_opCount * sizeof(Op);
+    m_opsCursor = m_opsInBuffer = 0;
+    doOnSameThread(0);
+
+    fprintf(stderr, "Done running\n");
+    for (auto thread : m_threads)
+        thread->stop();
+
+    for (auto thread : m_threads)
+        delete thread;
 
     // A recording might not free all of its allocations.
     if (!m_shouldFreeAllObjects)
@@ -133,3 +112,204 @@ void Interpreter::run()
         m_objects[i] = { 0, 0 };
     }
 }
+
+bool Interpreter::readOps()
+{
+    if (!m_remaining)
+        return false;
+
+    size_t bytes = std::min(m_remaining, m_ops.size() * sizeof(Op));
+    m_remaining -= bytes;
+    read(m_fd, m_ops.data(), bytes);
+    m_opsCursor = 0;
+    m_opsInBuffer = bytes / sizeof(Op);
+    
+    if (!m_opsInBuffer)
+        return false;
+
+    return true;
+}
+
+void Interpreter::doOnSameThread(ThreadId runThreadId)
+{
+    while (true) {
+        if ((m_opsCursor >= m_opsInBuffer) && (!readOps())) {
+            if (runThreadId)
+                switchToThread(0);
+            return;
+        }
+
+        for (; m_opsCursor < m_opsInBuffer; ++m_opsCursor) {
+            Op op = m_ops[m_opsCursor];
+            ThreadId threadId = op.threadId;
+            if (m_useThreadId && (runThreadId != threadId)) {
+                switchToThread(threadId);
+                break;
+            }
+
+            doMallocOp(op, m_currentThreadId);
+        }
+    }
+}
+
+void Interpreter::switchToThread(ThreadId threadId)
+{
+    if (m_currentThreadId == threadId)
+        return;
+
+    for (ThreadId threadIndex = static_cast<ThreadId>(m_threads.size());
+         threadIndex < threadId; ++threadIndex)
+        m_threads.push_back(new Thread(this, threadId));
+
+    ThreadId currentThreadId = m_currentThreadId;
+
+    if (threadId == 0) {
+        std::unique_lock<std::mutex> lock(m_threadMutex);
+        m_currentThreadId = threadId;
+        m_shouldRun.notify_one();
+    } else
+        m_threads[threadId - 1]->switchTo();
+    
+    if (currentThreadId == 0) {
+        std::unique_lock<std::mutex> lock(m_threadMutex);
+        m_shouldRun.wait(lock, [this](){return m_currentThreadId == 0; });
+    } else
+        m_threads[currentThreadId - 1]->waitToRun();
+}
+
+void Interpreter::detailedReport()
+{
+    size_t totalInUse = 0;
+    size_t smallInUse = 0;
+    size_t mediumInUse = 0;
+    size_t largeInUse = 0;
+    size_t extraLargeInUse = 0;
+    size_t memoryAllocated = 0;
+
+    for (size_t i = 0; i < m_objects.size(); ++i) {
+        if (!m_objects[i].object)
+            continue;
+        size_t objectSize = m_objects[i].size;
+        memoryAllocated += objectSize;
+        totalInUse++;
+
+        if (objectSize <= 256)
+            smallInUse++;
+        else if (objectSize <= 1024)
+            mediumInUse++;
+        else if (objectSize <= 1032192)
+            largeInUse++;
+        else
+            extraLargeInUse++;
+    }
+
+    std::cout << "0B-256B objects in use: " << smallInUse << std::endl;
+    std::cout << "257B-1K objects in use: " << mediumInUse << std::endl;
+    std::cout << "  1K-1M objects in use: " << largeInUse << std::endl;
+    std::cout << "    1M+ objects in use: " << extraLargeInUse << std::endl;
+    std::cout << "  Total objects in use: " << totalInUse << std::endl;
+    std::cout << "Total allocated memory: " << memoryAllocated / 1024 << "kB" << std::endl;
+}
+static size_t compute2toPower(unsigned log2n)
+{
+    // Check for bad alignment log2 value and return a bad alignment.
+    if (log2n > 64)
+        return 0xff00;
+
+    size_t result = 1;
+    while (log2n--)
+        result <<= 1;
+    
+    return result;
+}
+
+static void writeData(void* start, size_t size)
+{
+    char* writePtr = reinterpret_cast<char*>(start);
+
+    for (size_t sizeLeft = size; !!sizeLeft; ) {
+        size_t sizeThisIter = std::min(sizeLeft, 4096ul);
+        
+        writePtr[0] = random() & 0xff;
+        writePtr[1] = random() & 0xff;
+        writePtr[2] = random() & 0xff;
+        writePtr[3] = random() & 0xff;
+
+        writePtr += sizeThisIter;
+        sizeLeft -= sizeThisIter;
+    }
+}
+
+void Interpreter::doMallocOp(Op op, ThreadId threadId)
+{
+    switch (op.opcode) {
+        case op_malloc: {
+            m_objects[op.slot] = { mbmalloc(op.size), op.size };
+            assert(m_objects[op.slot].object);
+            writeData(m_objects[op.slot].object, op.size);
+            break;
+        }
+        case op_free: {
+            if (!m_objects[op.slot].object)
+                return;
+            mbfree(m_objects[op.slot].object, m_objects[op.slot].size);
+            m_objects[op.slot] = { 0, 0 };
+            break;
+        }
+        case op_realloc: {
+            if (!m_objects[op.slot].object)
+                return;
+            m_objects[op.slot] = { mbrealloc(m_objects[op.slot].object, m_objects[op.slot].size, op.size), op.size };
+            break;
+        }
+        case op_align_malloc: {
+            size_t alignment = compute2toPower(op.alignLog2);
+            m_objects[op.slot] = { mbmemalign(alignment, op.size), op.size };
+            assert(m_objects[op.slot].object);
+            writeData(m_objects[op.slot].object, op.size);
+            break;
+        }
+        default: {
+            fprintf(stderr, "bad opcode: %d\n", op.opcode);
+            abort();
+            break;
+        }
+    }
+}
+
+Interpreter::Thread::Thread(Interpreter* myInterpreter, ThreadId threadId)
+    : m_threadId(threadId)
+    , m_myInterpreter(myInterpreter)
+{
+    m_thread = std::thread(&Thread::runThread, this);
+}
+
+void Interpreter::Thread::stop()
+{
+    m_myInterpreter->switchToThread(m_threadId);
+}
+
+Interpreter::Thread::~Thread()
+{
+    switchTo();
+    m_thread.join();
+}
+
+void Interpreter::Thread::runThread()
+{
+    waitToRun();
+    m_myInterpreter->doOnSameThread(m_threadId);
+}
+
+void Interpreter::Thread::waitToRun()
+{
+    std::unique_lock<std::mutex> lock(m_myInterpreter->m_threadMutex);
+    m_shouldRun.wait(lock, [this](){return m_myInterpreter->m_currentThreadId == m_threadId; });
+}
+
+void Interpreter::Thread::switchTo()
+{
+    std::unique_lock<std::mutex> lock(m_myInterpreter->m_threadMutex);
+    m_myInterpreter->m_currentThreadId = m_threadId;
+    m_shouldRun.notify_one();
+}
\ No newline at end of file
index f406e91..b54a5a1 100644 (file)
 #ifndef Interpreter_h
 #define Interpreter_h
 
+#include <condition_variable>
+#include <mutex>
+#include <thread>
 #include <vector>
 
 class Interpreter {
 public:
-    Interpreter(const char* fileName, bool shouldFreeAllObjects = true);
+    Interpreter(const char* fileName, bool shouldFreeAllObjects = true, bool useThreadId = false);
     ~Interpreter();
 
     void run();
+    void detailedReport();
 
 private:
-    enum Opcode { op_malloc, op_free, op_realloc };
-    struct Op { Opcode opcode; size_t slot; size_t size; };
+    typedef unsigned short ThreadId; // 0 is the main thread
+    typedef unsigned short Log2Alignment; // log2(alignment) or ~0 for non power of 2.
+    enum Opcode { op_malloc, op_free, op_realloc, op_align_malloc };
+    struct Op { Opcode opcode; ThreadId threadId; Log2Alignment alignLog2; size_t slot; size_t size; };
     struct Record { void* object; size_t size; };
 
+    class Thread
+    {
+    public:
+        Thread(Interpreter*, ThreadId);
+        ~Thread();
+
+        void runThread();
+
+        void waitToRun();
+        void switchTo();
+        void stop();
+        
+        bool isMainThread() { return m_threadId == 0; }
+
+    private:
+        ThreadId m_threadId;
+        Interpreter* m_myInterpreter;
+        std::condition_variable m_shouldRun;
+        std::thread m_thread;
+    };
+
+    bool readOps();
+    void doOnSameThread(ThreadId);
+    void switchToThread(ThreadId);
+
+    void doMallocOp(Op, ThreadId);
+    
     bool m_shouldFreeAllObjects;
+    bool m_useThreadId;
     int m_fd;
     size_t m_opCount;
+    size_t m_remaining;
+    size_t m_opsCursor;
+    size_t m_opsInBuffer;
+    ThreadId m_currentThreadId;
+    std::vector<Op> m_ops;
+    std::mutex m_threadMutex;
+    std::condition_variable m_shouldRun;
+    std::vector<Thread*> m_threads;
     std::vector<Record> m_objects;
 };
 
diff --git a/PerformanceTests/MallocBench/MallocBench/alloc_free.cpp b/PerformanceTests/MallocBench/MallocBench/alloc_free.cpp
new file mode 100644 (file)
index 0000000..5dcf1e7
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 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 "alloc_free.h"
+
+#include "mbmalloc.h"
+#include <string.h>
+
+void benchmark_alloc_free(CommandLine&)
+{
+    size_t loops = 1000000;
+
+    size_t allocSize = 1030;
+    
+    char* dummy1 = (char*)mbmalloc(allocSize);
+    char* dummy2 = (char*)mbmalloc(allocSize);
+    dummy2[0] = 'a';
+    mbfree(dummy1, allocSize);
+
+    while (--loops) {
+        char* object = (char*)mbmalloc(allocSize);
+
+        memset(object, 'a', allocSize);
+
+        mbfree(object, allocSize);
+    }
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/alloc_free.h b/PerformanceTests/MallocBench/MallocBench/alloc_free.h
new file mode 100644 (file)
index 0000000..a85547f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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 alloc_free_h
+#define alloc_free_h
+
+#include "CommandLine.h"
+
+void benchmark_alloc_free(CommandLine&);
+
+#endif // alloc_free_h
+
index 62b449f..8c0d43f 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "mbmalloc.h"
 
-void benchmark_balloon(bool isParallel)
+void benchmark_balloon(CommandLine&)
 {
     const size_t chunkSize = 1 * 1024;
     const size_t balloonSize = 100 * 1024 * 1024;
index bb8671c..c9342a8 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef balloon_h
 #define balloon_h
 
-void benchmark_balloon(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_balloon(CommandLine&);
 
 #endif // balloon_h
 
index bbc3531..09ddcc3 100644 (file)
@@ -39,14 +39,14 @@ struct Object {
     size_t size;
 };
 
-void benchmark_big(bool isParallel)
+void benchmark_big(CommandLine& commandLine)
 {
     size_t times = 1;
 
     size_t vmSize = 1ul * 1024 * 1024 * 1024;
     size_t objectSizeMin = 4 * 1024;
     size_t objectSizeMax = 64 * 1024;
-    if (isParallel)
+    if (commandLine.isParallel())
         vmSize /= cpuCount();
 
     size_t objectCount = vmSize / objectSizeMin;
index 56bf565..92804ad 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef big_h
 #define big_h
 
-void benchmark_big(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_big(CommandLine&);
 
 #endif // big_h
 
index 3a3e0b3..cb85d2e 100644 (file)
@@ -39,10 +39,10 @@ struct HeapDouble {
     double value;
 };
 
-void benchmark_churn(bool isParallel)
+void benchmark_churn(CommandLine& commandLine)
 {
     size_t times = 7000000;
-    if (isParallel)
+    if (commandLine.isParallel())
         times /= cpuCount();
 
     auto total = std::unique_ptr<HeapDouble>(new HeapDouble(0.0));
index 2047a04..58d67ce 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef churn_h
 #define churn_h
 
-void benchmark_churn(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_churn(CommandLine&);
 
 #endif // churn_h
 
index 37cb4da..8bf548b 100644 (file)
 
 #include "mbmalloc.h"
 
-void benchmark_facebook(bool isParallel)
+void benchmark_facebook(CommandLine& commandLine)
 {
     size_t times = 1;
 
     Interpreter interpreter("facebook.ops");
     for (size_t i = 0; i < times; ++i)
         interpreter.run();
+
+    if (commandLine.detailedReport())
+        interpreter.detailedReport();
 }
index e7976de..55748f2 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef facebook_h
 #define facebook_h
 
-void benchmark_facebook(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_facebook(CommandLine&);
 
 #endif // facebook_h
 
index 59f5701..a3d1046 100644 (file)
 
 #include "mbmalloc.h"
 
-void benchmark_flickr(bool isParallel)
+void benchmark_flickr(CommandLine& commandLine)
 {
     size_t times = 3;
 
     Interpreter interpreter("flickr.ops");
     for (size_t i = 0; i < times; ++i)
         interpreter.run();
+
+    if (commandLine.detailedReport())
+        interpreter.detailedReport();
 }
 
-void benchmark_flickr_memory_warning(bool isParallel)
+void benchmark_flickr_memory_warning(CommandLine& commandLine)
 {
     size_t times = 1;
 
@@ -59,4 +62,7 @@ void benchmark_flickr_memory_warning(bool isParallel)
     Interpreter interpreter("flickr_memory_warning.ops", shouldFreeAllObjects);
     for (size_t i = 0; i < times; ++i)
         interpreter.run();
+
+    if (commandLine.detailedReport())
+        interpreter.detailedReport();
 }
index a53fefc..7b275ac 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef flickr_h
 #define flickr_h
 
-void benchmark_flickr(bool isParallel);
-void benchmark_flickr_memory_warning(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_flickr(CommandLine&);
+void benchmark_flickr_memory_warning(CommandLine&);
 
 #endif // flickr_h
index 0125796..e2685f3 100644 (file)
@@ -79,10 +79,10 @@ void validate(Node* head)
         node->validate();
 }
 
-void benchmark_fragment(bool isParallel)
+void benchmark_fragment(CommandLine& commandLine)
 {
     size_t nodeCount = 128 * 1024;
-    if (isParallel)
+    if (commandLine.isParallel())
         nodeCount /= cpuCount();
     size_t replaceCount = nodeCount / 4;
     size_t times = 25;
@@ -107,11 +107,11 @@ void benchmark_fragment(bool isParallel)
     }
 }
 
-void benchmark_fragment_iterate(bool isParallel)
+void benchmark_fragment_iterate(CommandLine& commandLine)
 {
     size_t nodeCount = 512 * 1024;
     size_t times = 20;
-    if (isParallel)
+    if (commandLine.isParallel())
         nodeCount /= cpuCount();
     size_t replaceCount = nodeCount / 4;
 
index d479f2d..5092c94 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef fragment_h
 #define fragment_h
 
-void benchmark_fragment(bool isParallel);
-void benchmark_fragment_iterate(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_fragment(CommandLine&);
+void benchmark_fragment_iterate(CommandLine&);
 
 #endif // fragment_h
index 487f4c3..01763c6 100644 (file)
@@ -96,12 +96,12 @@ struct Node {
 
 } // namespace
 
-void benchmark_list_allocate(bool isParallel)
+void benchmark_list_allocate(CommandLine& commandLine)
 {
     Node* head = 0;
     size_t times = 70;
     size_t nodes = 32 * 1024;
-    if (isParallel) {
+    if (commandLine.isParallel()) {
         nodes /= cpuCount();
         times *= 2;
     }
@@ -124,12 +124,12 @@ void benchmark_list_allocate(bool isParallel)
     }
 }
 
-void benchmark_list_traverse(bool isParallel)
+void benchmark_list_traverse(CommandLine& commandLine)
 {
     Node* head = 0;
     size_t times = 1 * 1024;
     size_t nodes = 32 * 1024;
-    if (isParallel) {
+    if (commandLine.isParallel()) {
         nodes /= cpuCount();
         times *= 4;
     }
index 212d217..319b9d2 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef list_h
 #define list_h
 
-void benchmark_list_allocate(bool isParallel);
-void benchmark_list_traverse(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_list_allocate(CommandLine&);
+void benchmark_list_traverse(CommandLine&);
 
 #endif // list_h
index e0b2120..bed944b 100644 (file)
@@ -40,7 +40,7 @@ int main(int argc, char** argv)
         exit(1);
     }
 
-    Benchmark benchmark(commandLine.benchmarkName(), commandLine.isParallel(), commandLine.runs(), commandLine.heapSize());
+    Benchmark benchmark(commandLine);
     if (!benchmark.isValid()) {
         cout << "Invalid benchmark: " << commandLine.benchmarkName() << endl << endl;
         benchmark.printBenchmarks();
@@ -48,6 +48,7 @@ int main(int argc, char** argv)
     }
 
     string parallel = commandLine.isParallel() ? string(" [ parallel ]") : string(" [ not parallel ]");
+    string threaded = commandLine.useThreadID() ? string(" [ use-thread-id ]") : string(" [ don't use-thread-id ]");
 
     stringstream runs;
     runs << " [ runs: " << commandLine.runs() << " ]";
@@ -58,7 +59,7 @@ int main(int argc, char** argv)
     else
         heapSize << " [ heap: 0MB ]";
 
-    cout << "Running " << commandLine.benchmarkName() << parallel << heapSize.str() << runs.str() << "..." << endl;
+    cout << "Running " << commandLine.benchmarkName() << parallel << threaded << heapSize.str() << runs.str() << "..." << endl;
     benchmark.run();
     benchmark.printReport();
         
index 61c43fd..b0d3a64 100644 (file)
@@ -39,14 +39,14 @@ struct Object {
     size_t size;
 };
 
-void benchmark_medium(bool isParallel)
+void benchmark_medium(CommandLine& commandLine)
 {
     size_t times = 1;
 
     size_t vmSize = 1ul * 1024 * 1024 * 1024;
     size_t objectSizeMin = 2 * 1024;
     size_t objectSizeMax = 8 * 1024;
-    if (isParallel)
+    if (commandLine.isParallel())
         vmSize /= cpuCount();
 
     size_t objectCount = vmSize / objectSizeMin;
index 038141a..98dd432 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef medium_h
 #define medium_h
 
-void benchmark_medium(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_medium(CommandLine&);
 
 #endif // medium_h
 
index 74835c5..34af059 100644 (file)
@@ -27,6 +27,7 @@
 #include "memalign.h"
 #include <memory>
 #include <stddef.h>
+#include "CommandLine.h"
 
 #include "mbmalloc.h"
 
@@ -40,7 +41,7 @@ void test(size_t alignment, size_t size)
     mbfree(result, size);
 }
 
-void benchmark_memalign(bool isParallel)
+void benchmark_memalign(CommandLine&)
 {
     for (size_t alignment = 2; alignment < 4096; alignment *= 2) {
         for (size_t size = 0; size < 4096; ++size)
index c805811..a392b82 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef memalign_h
 #define memalign_h
 
-void benchmark_memalign(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_memalign(CommandLine&);
 
 #endif // memalign_h
 
index daccdd4..1b5f9d0 100644 (file)
@@ -110,9 +110,9 @@ private:
 
 } // namespace
 
-void benchmark_message_one(bool isParallel)
+void benchmark_message_one(CommandLine& commandLine)
 {
-    if (isParallel)
+    if (commandLine.isParallel())
         abort();
 
     const size_t times = 2048;
@@ -138,9 +138,9 @@ void benchmark_message_one(bool isParallel)
     dispatch_release(queue);
 }
 
-void benchmark_message_many(bool isParallel)
+void benchmark_message_many(CommandLine& commandLine)
 {
-    if (isParallel)
+    if (commandLine.isParallel())
         abort();
 
     const size_t times = 768;
index ffc96cc..ddf9491 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef message_h
 #define message_h
 
-void benchmark_message_one(bool isParallel);
-void benchmark_message_many(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_message_one(CommandLine&);
+void benchmark_message_many(CommandLine&);
 
 #endif // message_h
diff --git a/PerformanceTests/MallocBench/MallocBench/nimlang.cpp b/PerformanceTests/MallocBench/MallocBench/nimlang.cpp
new file mode 100644 (file)
index 0000000..ae1eb37
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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 "nimlang.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_nimlang(CommandLine& commandLine)
+{
+    size_t times = 1;
+
+    bool shouldFreeAllObjects = false;
+    Interpreter interpreter("nimlang.ops", shouldFreeAllObjects, commandLine.useThreadID());
+    for (size_t i = 0; i < times; ++i)
+        interpreter.run();
+
+        if (commandLine.detailedReport())
+            interpreter.detailedReport();
+}
diff --git a/PerformanceTests/MallocBench/MallocBench/nimlang.h b/PerformanceTests/MallocBench/MallocBench/nimlang.h
new file mode 100644 (file)
index 0000000..39c5fb1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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 nimlang_h
+#define nimlang_h
+
+#include "CommandLine.h"
+
+void benchmark_nimlang(CommandLine&);
+
+#endif // nimlang_h
+
diff --git a/PerformanceTests/MallocBench/MallocBench/nimlang.ops b/PerformanceTests/MallocBench/MallocBench/nimlang.ops
new file mode 100644 (file)
index 0000000..5c7bd43
Binary files /dev/null and b/PerformanceTests/MallocBench/MallocBench/nimlang.ops differ
index 530b101..e256db2 100644 (file)
@@ -29,6 +29,6 @@
 
 #include "mbmalloc.h"
 
-void benchmark_realloc(bool isParallel)
+void benchmark_realloc(CommandLine&)
 {
 }
index d85251d..ac1a3c6 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef realloc_h
 #define realloc_h
 
-void benchmark_realloc(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_realloc(CommandLine&);
 
 #endif // realloc_h
 
index 87763db..bbf2d0b 100644 (file)
 
 #include "mbmalloc.h"
 
-void benchmark_reddit(bool isParallel)
+void benchmark_reddit(CommandLine& commandLine)
 {
     size_t times = 6;
 
     Interpreter interpreter("reddit.ops");
     for (size_t i = 0; i < times; ++i)
         interpreter.run();
+
+    if (commandLine.detailedReport())
+        interpreter.detailedReport();
 }
 
-void benchmark_reddit_memory_warning(bool isParallel)
+void benchmark_reddit_memory_warning(CommandLine& commandLine)
 {
     size_t times = 1;
 
@@ -59,4 +62,7 @@ void benchmark_reddit_memory_warning(bool isParallel)
     Interpreter interpreter("reddit_memory_warning.ops", shouldFreeAllObjects);
     for (size_t i = 0; i < times; ++i)
         interpreter.run();
+
+    if (commandLine.detailedReport())
+        interpreter.detailedReport();
 }
index 1ddf048..4696151 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef reddit_h
 #define reddit_h
 
-void benchmark_reddit(bool isParallel);
-void benchmark_reddit_memory_warning(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_reddit(CommandLine&);
+void benchmark_reddit_memory_warning(CommandLine&);
 
 #endif // reddit_h
index 5accaf2..dd6b765 100644 (file)
@@ -120,7 +120,7 @@ void deallocate(const Object& object)
     mbfree(object.pointer, object.size);
 }
 
-void benchmark_stress(bool isParallel)
+void benchmark_stress(CommandLine&)
 {
     const size_t heapSize = 100 * MB;
     const size_t churnSize = .05 * heapSize;
index 06f8c42..1c3e96a 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef stress_h
 #define stress_h
 
-void benchmark_stress(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_stress(CommandLine&);
 
 #endif // stress_h
index c896952..5b02fa8 100644 (file)
@@ -137,7 +137,7 @@ size_t randomAlignment()
 
 }
 
-void benchmark_stress_aligned(bool isParallel)
+void benchmark_stress_aligned(CommandLine&)
 {
     const size_t heapSize = 100 * MB;
     const size_t churnSize = .05 * heapSize;
index c064750..4d7df47 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef stress_aligned_h
 #define stress_aligned_h
 
-void benchmark_stress_aligned(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_stress_aligned(CommandLine&);
 
 #endif // stress_aligned_h
index 6a03672..c6a68ea 100644 (file)
 
 #include "mbmalloc.h"
 
-void benchmark_theverge(bool isParallel)
+void benchmark_theverge(CommandLine& commandLine)
 {
     size_t times = 3;
 
     Interpreter interpreter("theverge.ops");
     for (size_t i = 0; i < times; ++i)
         interpreter.run();
+
+    if (commandLine.detailedReport())
+        interpreter.detailedReport();
 }
 
-void benchmark_theverge_memory_warning(bool isParallel)
+void benchmark_theverge_memory_warning(CommandLine& commandLine)
 {
     size_t times = 1;
 
@@ -59,4 +62,7 @@ void benchmark_theverge_memory_warning(bool isParallel)
     Interpreter interpreter("theverge_memory_warning.ops", shouldFreeAllObjects);
     for (size_t i = 0; i < times; ++i)
         interpreter.run();
+
+    if (commandLine.detailedReport())
+        interpreter.detailedReport();
 }
index 6afeab0..60f36e5 100644 (file)
@@ -26,7 +26,9 @@
 #ifndef theverge_h
 #define theverge_h
 
-void benchmark_theverge(bool isParallel);
-void benchmark_theverge_memory_warning(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_theverge(CommandLine&);
+void benchmark_theverge_memory_warning(CommandLine&);
 
 #endif // theverge_h
index d9b7a57..56859b3 100644 (file)
@@ -175,11 +175,11 @@ void churnTree(Node* tree, size_t stride)
 
 } // namespace
 
-void benchmark_tree_allocate(bool isParallel)
+void benchmark_tree_allocate(CommandLine& commandLine)
 {
     size_t times = 24;
     size_t depth = 16;
-    if (isParallel) {
+    if (commandLine.isParallel()) {
         times *= 4;
         depth = 13;
     }
@@ -190,11 +190,11 @@ void benchmark_tree_allocate(bool isParallel)
     }
 }
 
-void benchmark_tree_traverse(bool isParallel)
+void benchmark_tree_traverse(CommandLine& commandLine)
 {
     size_t times = 256;
     size_t depth = 15;
-    if (isParallel) {
+    if (commandLine.isParallel()) {
         times = 512;
         depth = 13;
     }
@@ -205,11 +205,11 @@ void benchmark_tree_traverse(bool isParallel)
     tree->deref();
 }
 
-void benchmark_tree_churn(bool isParallel)
+void benchmark_tree_churn(CommandLine& commandLine)
 {
     size_t times = 130;
     size_t depth = 15;
-    if (isParallel) {
+    if (commandLine.isParallel()) {
         times *= 4;
         depth = 12;
     }
index cfe74af..4eec525 100644 (file)
 #ifndef tree_h
 #define tree_h
 
-void benchmark_tree_allocate(bool isParallel);
-void benchmark_tree_traverse(bool isParallel);
-void benchmark_tree_churn(bool isParallel);
+#include "CommandLine.h"
+
+void benchmark_tree_allocate(CommandLine&);
+void benchmark_tree_traverse(CommandLine&);
+void benchmark_tree_churn(CommandLine&);
 
 #endif // tree_h
index ff2b4ed..0b98b72 100755 (executable)
@@ -22,6 +22,7 @@ $benchmarks = [
     "reddit",
     "flickr",
     "theverge",
+    "nimlang",
 
     # Multi-threaded benchmark variants.
     "message_one",
@@ -34,6 +35,7 @@ $benchmarks = [
     # "reddit --parallel",
     # "flickr --parallel",
     # "theverge --parallel",
+    # "nimlang --use-thread-id",
     "fragment --parallel",
     "fragment_iterate --parallel",