8cd4bd30f3b0a0ab2dc5d88371385aeba9c7e5bc
[WebKit-https.git] / Source / WTF / benchmarks / LockSpeedTest.cpp
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 // On Mac, you can build this like so:
27 // clang++ -o LockSpeedTest Source/WTF/benchmarks/LockSpeedTest.cpp -O3 -W -ISource/WTF -LWebKitBuild/Release -lWTF -framework Foundation -licucore -std=c++11
28
29 #include "config.h"
30
31 #include <unistd.h>
32 #include <wtf/CurrentTime.h>
33 #include <wtf/Lock.h>
34 #include <wtf/SpinLock.h>
35 #include <wtf/StdLibExtras.h>
36 #include <wtf/Threading.h>
37 #include <wtf/ThreadingPrimitives.h>
38 #include <wtf/WordLock.h>
39
40 namespace {
41
42 unsigned numThreadGroups;
43 unsigned numThreadsPerGroup;
44 unsigned workPerCriticalSection;
45 unsigned numNoiseThreads;
46 unsigned numIterations;
47     
48 NO_RETURN void usage()
49 {
50     printf("Usage: LockSpeedTest spinlock|wordlock|lock|mutex|all <num thread groups> <num threads per group> <work per critical section> <num noise threads> <num iterations>\n");
51     exit(1);
52 }
53
54 template<typename LockType>
55 void runBenchmark(const char* name)
56 {
57     std::unique_ptr<LockType[]> locks = std::make_unique<LockType[]>(numThreadGroups);
58     std::unique_ptr<double[]> words = std::make_unique<double[]>(numThreadGroups);
59     std::unique_ptr<ThreadIdentifier[]> threads = std::make_unique<ThreadIdentifier[]>(numThreadGroups * numThreadsPerGroup);
60     std::unique_ptr<ThreadIdentifier[]> noiseThreads = std::make_unique<ThreadIdentifier[]>(numNoiseThreads);
61     std::unique_ptr<double[]> noiseCounts = std::make_unique<double[]>(numNoiseThreads);
62
63     volatile bool shouldStop = false;
64     for (unsigned threadIndex = numNoiseThreads; threadIndex--;) {
65         noiseCounts[threadIndex] = 0;
66         noiseThreads[threadIndex] = createThread(
67             "Noise Thread",
68             [&shouldStop, &noiseCounts, threadIndex] () {
69                 while (!shouldStop)
70                     noiseCounts[threadIndex]++;
71             });
72     }
73
74     double before = monotonicallyIncreasingTimeMS();
75     
76     for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
77         words[threadGroupIndex] = 0;
78
79         for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
80             threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = createThread(
81                 "Benchmark thread",
82                 [threadGroupIndex, &locks, &words] () {
83                     for (unsigned i = numIterations; i--;) {
84                         locks[threadGroupIndex].lock();
85                         for (unsigned j = workPerCriticalSection; j--;) {
86                             words[threadGroupIndex]++;
87                             words[threadGroupIndex] *= 1.01;
88                         }
89                         locks[threadGroupIndex].unlock();
90                     }
91                 });
92         }
93     }
94
95     for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
96         waitForThreadCompletion(threads[threadIndex]);
97     shouldStop = true;
98     double noiseCount = 0;
99     for (unsigned threadIndex = numNoiseThreads; threadIndex--;) {
100         waitForThreadCompletion(noiseThreads[threadIndex]);
101         noiseCount += noiseCounts[threadIndex];
102     }
103
104     double after = monotonicallyIncreasingTimeMS();
105
106     printf("%s: %.3lf ms, %.0lf noise.\n", name, after - before, noiseCount);
107 }
108
109 } // anonymous namespace
110
111 int main(int argc, char** argv)
112 {
113     WTF::initializeThreading();
114     
115     if (argc != 7
116         || sscanf(argv[2], "%u", &numThreadGroups) != 1
117         || sscanf(argv[3], "%u", &numThreadsPerGroup) != 1
118         || sscanf(argv[4], "%u", &workPerCriticalSection) != 1
119         || sscanf(argv[5], "%u", &numNoiseThreads) != 1
120         || sscanf(argv[6], "%u", &numIterations) != 1)
121         usage();
122
123     bool didRun = false;
124     if (!strcmp(argv[1], "spinlock") || !strcmp(argv[1], "all")) {
125         runBenchmark<SpinLock>("SpinLock");
126         didRun = true;
127     }
128     if (!strcmp(argv[1], "wordlock") || !strcmp(argv[1], "all")) {
129         runBenchmark<WordLock>("WTF WordLock");
130         didRun = true;
131     }
132     if (!strcmp(argv[1], "lock") || !strcmp(argv[1], "all")) {
133         runBenchmark<Lock>("WTF Lock");
134         didRun = true;
135     }
136     if (!strcmp(argv[1], "mutex") || !strcmp(argv[1], "all")) {
137         runBenchmark<Mutex>("Platform Mutex");
138         didRun = true;
139     }
140
141     if (!didRun)
142         usage();
143
144     return 0;
145 }