Improve WebKitLegacy video fullscreen animation begin and end rects.
[WebKit-https.git] / Source / WTF / benchmarks / LockSpeedTest.cpp
1 /*
2  * Copyright (C) 2015-2017 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 // 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
28
29 #include "config.h"
30
31 #include "ToyLocks.h"
32 #include <thread>
33 #include <unistd.h>
34 #include <wtf/CurrentTime.h>
35 #include <wtf/DataLog.h>
36 #include <wtf/HashMap.h>
37 #include <wtf/Lock.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>
45
46 namespace {
47
48 unsigned numThreadGroups;
49 unsigned numThreadsPerGroup;
50 unsigned workPerCriticalSection;
51 unsigned workBetweenCriticalSections;
52 double secondsPerTest;
53     
54 NO_RETURN void usage()
55 {
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");
57     exit(1);
58 }
59
60 template<typename Type>
61 struct WithPadding {
62     Type value;
63     char buf[300]; // It's best if this isn't perfect to avoid false sharing.
64 };
65
66 HashMap<CString, Vector<double>> results;
67
68 void reportResult(const char* name, double value)
69 {
70     dataLogF("%s: %.3lf KHz\n", name, value);
71     results.add(name, Vector<double>()).iterator->value.append(value);
72 }
73
74 struct Benchmark {
75     template<typename LockType>
76     static void run(const char* name)
77     {
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);
81
82         volatile bool keepGoing = true;
83
84         double before = monotonicallyIncreasingTime();
85     
86         Lock numIterationsLock;
87         uint64_t numIterations = 0;
88     
89         for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
90             words[threadGroupIndex].value = 0;
91
92             for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
93                 threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = Thread::create(
94                     "Benchmark thread",
95                     [threadGroupIndex, &locks, &words, &keepGoing, &numIterationsLock, &numIterations] () {
96                         double localWord = 0;
97                         double value = 1;
98                         unsigned myNumIterations = 0;
99                         while (keepGoing) {
100                             locks[threadGroupIndex].value.lock();
101                             for (unsigned j = workPerCriticalSection; j--;) {
102                                 words[threadGroupIndex].value += value;
103                                 value = words[threadGroupIndex].value;
104                             }
105                             locks[threadGroupIndex].value.unlock();
106                             for (unsigned j = workBetweenCriticalSections; j--;) {
107                                 localWord += value;
108                                 value = localWord;
109                             }
110                             myNumIterations++;
111                         }
112                         LockHolder locker(numIterationsLock);
113                         numIterations += myNumIterations;
114                     });
115             }
116         }
117
118         sleep(secondsPerTest);
119         keepGoing = false;
120     
121         for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
122             threads[threadIndex]->waitForCompletion();
123
124         double after = monotonicallyIncreasingTime();
125     
126         reportResult(name, numIterations / (after - before) / 1000);
127     }
128 };
129
130 unsigned rangeMin;
131 unsigned rangeMax;
132 unsigned rangeStep;
133 unsigned* rangeVariable;
134
135 bool parseValue(const char* string, unsigned* variable)
136 {
137     unsigned myRangeMin;
138     unsigned myRangeMax;
139     unsigned myRangeStep;
140     if (sscanf(string, "%u-%u:%u", &myRangeMin, &myRangeMax, &myRangeStep) == 3) {
141         if (rangeVariable) {
142             fprintf(stderr, "Can only have one variable with a range.\n");
143             return false;
144         }
145         
146         rangeMin = myRangeMin;
147         rangeMax = myRangeMax;
148         rangeStep = myRangeStep;
149         rangeVariable = variable;
150         return true;
151     }
152     
153     if (sscanf(string, "%u", variable) == 1)
154         return true;
155     
156     return false;
157 }
158
159 } // anonymous namespace
160
161 int main(int argc, char** argv)
162 {
163     WTF::initializeThreading();
164     
165     if (argc != 8
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)
172         usage();
173     
174     if (rangeVariable) {
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]);
180         }
181     } else
182         runEverything<Benchmark>(argv[1]);
183     
184     for (auto& entry : results) {
185         printf("%s = {", entry.key.data());
186         bool first = true;
187         for (double value : entry.value) {
188             if (first)
189                 first = false;
190             else
191                 printf(", ");
192             printf("%.3lf", value);
193         }
194         printf("};\n");
195     }
196
197     return 0;
198 }