2 * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 // On Mac, you can build this like so:
27 // xcrun clang++ -o LockSpeedTest Source/WTF/benchmarks/LockSpeedTest.cpp -O3 -W -ISource/WTF -ISource/WTF/icu -ISource/WTF/benchmarks -LWebKitBuild/Release -lWTF -framework Foundation -licucore -std=c++14 -fvisibility=hidden
34 #include <wtf/CurrentTime.h>
35 #include <wtf/DataLog.h>
36 #include <wtf/HashMap.h>
38 #include <wtf/ParkingLot.h>
39 #include <wtf/StdLibExtras.h>
40 #include <wtf/Threading.h>
41 #include <wtf/ThreadingPrimitives.h>
42 #include <wtf/Vector.h>
43 #include <wtf/WordLock.h>
44 #include <wtf/text/CString.h>
48 unsigned numThreadGroups;
49 unsigned numThreadsPerGroup;
50 unsigned workPerCriticalSection;
51 unsigned workBetweenCriticalSections;
52 double secondsPerTest;
54 NO_RETURN void usage()
56 printf("Usage: LockSpeedTest yieldspinlock|pausespinlock|wordlock|lock|barginglock|bargingwordlock|thunderlock|thunderwordlock|cascadelock|cascadewordlock|handofflock|unfairlock|mutex|all <num thread groups> <num threads per group> <work per critical section> <work between critical sections> <spin limit> <seconds per test>\n");
60 template<typename Type>
63 char buf[300]; // It's best if this isn't perfect to avoid false sharing.
66 HashMap<CString, Vector<double>> results;
68 void reportResult(const char* name, double value)
70 dataLogF("%s: %.3lf KHz\n", name, value);
71 results.add(name, Vector<double>()).iterator->value.append(value);
75 template<typename LockType>
76 static void run(const char* name)
78 std::unique_ptr<WithPadding<LockType>[]> locks = std::make_unique<WithPadding<LockType>[]>(numThreadGroups);
79 std::unique_ptr<WithPadding<double>[]> words = std::make_unique<WithPadding<double>[]>(numThreadGroups);
80 std::unique_ptr<RefPtr<Thread>[]> threads = std::make_unique<RefPtr<Thread>[]>(numThreadGroups * numThreadsPerGroup);
82 volatile bool keepGoing = true;
84 double before = monotonicallyIncreasingTime();
86 Lock numIterationsLock;
87 uint64_t numIterations = 0;
89 for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
90 words[threadGroupIndex].value = 0;
92 for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
93 threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = Thread::create(
95 [threadGroupIndex, &locks, &words, &keepGoing, &numIterationsLock, &numIterations] () {
98 unsigned myNumIterations = 0;
100 locks[threadGroupIndex].value.lock();
101 for (unsigned j = workPerCriticalSection; j--;) {
102 words[threadGroupIndex].value += value;
103 value = words[threadGroupIndex].value;
105 locks[threadGroupIndex].value.unlock();
106 for (unsigned j = workBetweenCriticalSections; j--;) {
112 LockHolder locker(numIterationsLock);
113 numIterations += myNumIterations;
118 sleep(secondsPerTest);
121 for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
122 threads[threadIndex]->waitForCompletion();
124 double after = monotonicallyIncreasingTime();
126 reportResult(name, numIterations / (after - before) / 1000);
133 unsigned* rangeVariable;
135 bool parseValue(const char* string, unsigned* variable)
139 unsigned myRangeStep;
140 if (sscanf(string, "%u-%u:%u", &myRangeMin, &myRangeMax, &myRangeStep) == 3) {
142 fprintf(stderr, "Can only have one variable with a range.\n");
146 rangeMin = myRangeMin;
147 rangeMax = myRangeMax;
148 rangeStep = myRangeStep;
149 rangeVariable = variable;
153 if (sscanf(string, "%u", variable) == 1)
159 } // anonymous namespace
161 int main(int argc, char** argv)
163 WTF::initializeThreading();
166 || !parseValue(argv[2], &numThreadGroups)
167 || !parseValue(argv[3], &numThreadsPerGroup)
168 || !parseValue(argv[4], &workPerCriticalSection)
169 || !parseValue(argv[5], &workBetweenCriticalSections)
170 || !parseValue(argv[6], &toyLockSpinLimit)
171 || sscanf(argv[7], "%lf", &secondsPerTest) != 1)
175 dataLog("Running with rangeMin = ", rangeMin, ", rangeMax = ", rangeMax, ", rangeStep = ", rangeStep, "\n");
176 for (unsigned value = rangeMin; value <= rangeMax; value += rangeStep) {
177 dataLog("Running with value = ", value, "\n");
178 *rangeVariable = value;
179 runEverything<Benchmark>(argv[1]);
182 runEverything<Benchmark>(argv[1]);
184 for (auto& entry : results) {
185 printf("%s = {", entry.key.data());
187 for (double value : entry.value) {
192 printf("%.3lf", value);