xref: /aosp_15_r20/external/angle/src/tests/perf_tests/ANGLEPerfTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ANGLEPerfTests:
7 //   Base class for google test performance tests
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #if defined(ANGLE_PLATFORM_ANDROID)
13 #    include <android/log.h>
14 #    include <dlfcn.h>
15 #endif
16 #include "ANGLEPerfTestArgs.h"
17 #include "common/base/anglebase/trace_event/trace_event.h"
18 #include "common/debug.h"
19 #include "common/gl_enum_utils.h"
20 #include "common/mathutil.h"
21 #include "common/platform.h"
22 #include "common/string_utils.h"
23 #include "common/system_utils.h"
24 #include "common/utilities.h"
25 #include "test_utils/runner/TestSuite.h"
26 #include "third_party/perf/perf_test.h"
27 #include "util/shader_utils.h"
28 #include "util/test_utils.h"
29 
30 #include <cassert>
31 #include <cmath>
32 #include <fstream>
33 #include <iostream>
34 #include <numeric>
35 #include <sstream>
36 #include <string>
37 
38 #include <rapidjson/document.h>
39 #include <rapidjson/filewritestream.h>
40 #include <rapidjson/istreamwrapper.h>
41 #include <rapidjson/prettywriter.h>
42 
43 #if defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
44 #    include "util/windows/WGLWindow.h"
45 #endif  // defined(ANGLE_USE_UTIL_LOADER) &&defined(ANGLE_PLATFORM_WINDOWS)
46 
47 using namespace angle;
48 namespace js = rapidjson;
49 
50 namespace
51 {
52 constexpr size_t kInitialTraceEventBufferSize            = 50000;
53 constexpr double kMilliSecondsPerSecond                  = 1e3;
54 constexpr double kMicroSecondsPerSecond                  = 1e6;
55 constexpr double kNanoSecondsPerSecond                   = 1e9;
56 constexpr size_t kNumberOfStepsPerformedToComputeGPUTime = 16;
57 constexpr char kPeakMemoryMetric[]                       = ".memory_max";
58 constexpr char kMedianMemoryMetric[]                     = ".memory_median";
59 
60 struct TraceCategory
61 {
62     unsigned char enabled;
63     const char *name;
64 };
65 
66 constexpr TraceCategory gTraceCategories[2] = {
67     {1, "gpu.angle"},
68     {1, "gpu.angle.gpu"},
69 };
70 
EmptyPlatformMethod(PlatformMethods *,const char *)71 void EmptyPlatformMethod(PlatformMethods *, const char *) {}
72 
CustomLogError(PlatformMethods * platform,const char * errorMessage)73 void CustomLogError(PlatformMethods *platform, const char *errorMessage)
74 {
75     auto *angleRenderTest = static_cast<ANGLERenderTest *>(platform->context);
76     angleRenderTest->onErrorMessage(errorMessage);
77 }
78 
AddPerfTraceEvent(PlatformMethods * platform,char phase,const unsigned char * categoryEnabledFlag,const char * name,unsigned long long id,double timestamp,int numArgs,const char ** argNames,const unsigned char * argTypes,const unsigned long long * argValues,unsigned char flags)79 TraceEventHandle AddPerfTraceEvent(PlatformMethods *platform,
80                                    char phase,
81                                    const unsigned char *categoryEnabledFlag,
82                                    const char *name,
83                                    unsigned long long id,
84                                    double timestamp,
85                                    int numArgs,
86                                    const char **argNames,
87                                    const unsigned char *argTypes,
88                                    const unsigned long long *argValues,
89                                    unsigned char flags)
90 {
91     if (!gEnableTrace)
92         return 0;
93 
94     // Discover the category name based on categoryEnabledFlag.  This flag comes from the first
95     // parameter of TraceCategory, and corresponds to one of the entries in gTraceCategories.
96     static_assert(offsetof(TraceCategory, enabled) == 0,
97                   "|enabled| must be the first field of the TraceCategory class.");
98     const TraceCategory *category = reinterpret_cast<const TraceCategory *>(categoryEnabledFlag);
99 
100     ANGLERenderTest *renderTest = static_cast<ANGLERenderTest *>(platform->context);
101 
102     std::lock_guard<std::mutex> lock(renderTest->getTraceEventMutex());
103 
104     uint32_t tid = renderTest->getCurrentThreadSerial();
105 
106     std::vector<TraceEvent> &buffer = renderTest->getTraceEventBuffer();
107     buffer.emplace_back(phase, category->name, name, timestamp, tid);
108     return buffer.size();
109 }
110 
GetPerfTraceCategoryEnabled(PlatformMethods * platform,const char * categoryName)111 const unsigned char *GetPerfTraceCategoryEnabled(PlatformMethods *platform,
112                                                  const char *categoryName)
113 {
114     if (gEnableTrace)
115     {
116         for (const TraceCategory &category : gTraceCategories)
117         {
118             if (strcmp(category.name, categoryName) == 0)
119             {
120                 return &category.enabled;
121             }
122         }
123     }
124 
125     constexpr static unsigned char kZero = 0;
126     return &kZero;
127 }
128 
UpdateTraceEventDuration(PlatformMethods * platform,const unsigned char * categoryEnabledFlag,const char * name,TraceEventHandle eventHandle)129 void UpdateTraceEventDuration(PlatformMethods *platform,
130                               const unsigned char *categoryEnabledFlag,
131                               const char *name,
132                               TraceEventHandle eventHandle)
133 {
134     // Not implemented.
135 }
136 
MonotonicallyIncreasingTime(PlatformMethods * platform)137 double MonotonicallyIncreasingTime(PlatformMethods *platform)
138 {
139     return GetHostTimeSeconds();
140 }
141 
WriteJsonFile(const std::string & outputFile,js::Document * doc)142 bool WriteJsonFile(const std::string &outputFile, js::Document *doc)
143 {
144     FILE *fp = fopen(outputFile.c_str(), "w");
145     if (!fp)
146     {
147         return false;
148     }
149 
150     constexpr size_t kBufferSize = 0xFFFF;
151     std::vector<char> writeBuffer(kBufferSize);
152     js::FileWriteStream os(fp, writeBuffer.data(), kBufferSize);
153     js::PrettyWriter<js::FileWriteStream> writer(os);
154     if (!doc->Accept(writer))
155     {
156         fclose(fp);
157         return false;
158     }
159     fclose(fp);
160     return true;
161 }
162 
DumpTraceEventsToJSONFile(const std::vector<TraceEvent> & traceEvents,const char * outputFileName)163 void DumpTraceEventsToJSONFile(const std::vector<TraceEvent> &traceEvents,
164                                const char *outputFileName)
165 {
166     js::Document doc(js::kObjectType);
167     js::Document::AllocatorType &allocator = doc.GetAllocator();
168 
169     js::Value events(js::kArrayType);
170 
171     for (const TraceEvent &traceEvent : traceEvents)
172     {
173         js::Value value(js::kObjectType);
174 
175         const uint64_t microseconds = static_cast<uint64_t>(traceEvent.timestamp * 1000.0 * 1000.0);
176 
177         js::Document::StringRefType eventName(traceEvent.name);
178         js::Document::StringRefType categoryName(traceEvent.categoryName);
179         js::Document::StringRefType pidName(
180             strcmp(traceEvent.categoryName, "gpu.angle.gpu") == 0 ? "GPU" : "ANGLE");
181 
182         value.AddMember("name", eventName, allocator);
183         value.AddMember("cat", categoryName, allocator);
184         value.AddMember("ph", std::string(1, traceEvent.phase), allocator);
185         value.AddMember("ts", microseconds, allocator);
186         value.AddMember("pid", pidName, allocator);
187         value.AddMember("tid", traceEvent.tid, allocator);
188 
189         events.PushBack(value, allocator);
190     }
191 
192     doc.AddMember("traceEvents", events, allocator);
193 
194     if (WriteJsonFile(outputFileName, &doc))
195     {
196         printf("Wrote trace file to %s\n", outputFileName);
197     }
198     else
199     {
200         printf("Error writing trace file to %s\n", outputFileName);
201     }
202 }
203 
PerfTestDebugCallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)204 [[maybe_unused]] void KHRONOS_APIENTRY PerfTestDebugCallback(GLenum source,
205                                                              GLenum type,
206                                                              GLuint id,
207                                                              GLenum severity,
208                                                              GLsizei length,
209                                                              const GLchar *message,
210                                                              const void *userParam)
211 {
212     // Early exit on non-errors.
213     if (type != GL_DEBUG_TYPE_ERROR || !userParam)
214     {
215         return;
216     }
217 
218     ANGLERenderTest *renderTest =
219         const_cast<ANGLERenderTest *>(reinterpret_cast<const ANGLERenderTest *>(userParam));
220     renderTest->onErrorMessage(message);
221 }
222 
ComputeMean(const std::vector<double> & values)223 double ComputeMean(const std::vector<double> &values)
224 {
225     double sum = std::accumulate(values.begin(), values.end(), 0.0);
226 
227     double mean = sum / static_cast<double>(values.size());
228     return mean;
229 }
230 
FinishAndCheckForContextLoss()231 void FinishAndCheckForContextLoss()
232 {
233     glFinish();
234     if (glGetError() == GL_CONTEXT_LOST)
235     {
236         FAIL() << "Context lost";
237     }
238 }
239 
240 #if defined(ANGLE_PLATFORM_ANDROID)
241 constexpr bool kHasATrace = true;
242 
243 void *gLibAndroid = nullptr;
244 bool (*gATraceIsEnabled)(void);
245 bool (*gATraceSetCounter)(const char *counterName, int64_t counterValue);
246 
SetupATrace()247 void SetupATrace()
248 {
249     if (gLibAndroid == nullptr)
250     {
251         gLibAndroid       = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL);
252         gATraceIsEnabled  = (decltype(gATraceIsEnabled))dlsym(gLibAndroid, "ATrace_isEnabled");
253         gATraceSetCounter = (decltype(gATraceSetCounter))dlsym(gLibAndroid, "ATrace_setCounter");
254     }
255 }
256 
ATraceEnabled()257 bool ATraceEnabled()
258 {
259     return gATraceIsEnabled();
260 }
261 #else
262 constexpr bool kHasATrace = false;
SetupATrace()263 void SetupATrace() {}
ATraceEnabled()264 bool ATraceEnabled()
265 {
266     return false;
267 }
268 #endif
269 }  // anonymous namespace
270 
TraceEvent(char phaseIn,const char * categoryNameIn,const char * nameIn,double timestampIn,uint32_t tidIn)271 TraceEvent::TraceEvent(char phaseIn,
272                        const char *categoryNameIn,
273                        const char *nameIn,
274                        double timestampIn,
275                        uint32_t tidIn)
276     : phase(phaseIn), categoryName(categoryNameIn), name{}, timestamp(timestampIn), tid(tidIn)
277 {
278     ASSERT(strlen(nameIn) < kMaxNameLen);
279     strcpy(name, nameIn);
280 }
281 
ANGLEPerfTest(const std::string & name,const std::string & backend,const std::string & story,unsigned int iterationsPerStep,const char * units)282 ANGLEPerfTest::ANGLEPerfTest(const std::string &name,
283                              const std::string &backend,
284                              const std::string &story,
285                              unsigned int iterationsPerStep,
286                              const char *units)
287     : mName(name),
288       mBackend(backend),
289       mStory(story),
290       mGPUTimeNs(0),
291       mSkipTest(false),
292       mStepsToRun(std::max(gStepsPerTrial, gMaxStepsPerformed)),
293       mTrialNumStepsPerformed(0),
294       mTotalNumStepsPerformed(0),
295       mIterationsPerStep(iterationsPerStep),
296       mRunning(true),
297       mPerfMonitor(0)
298 {
299     if (mStory == "")
300     {
301         mStory = "baseline_story";
302     }
303     if (mStory[0] == '_')
304     {
305         mStory = mStory.substr(1);
306     }
307     mReporter = std::make_unique<perf_test::PerfResultReporter>(mName + mBackend, mStory);
308     mReporter->RegisterImportantMetric(".wall_time", units);
309     mReporter->RegisterImportantMetric(".cpu_time", units);
310     mReporter->RegisterImportantMetric(".gpu_time", units);
311     mReporter->RegisterFyiMetric(".trial_steps", "count");
312     mReporter->RegisterFyiMetric(".total_steps", "count");
313 
314     if (kHasATrace)
315     {
316         SetupATrace();
317     }
318 }
319 
~ANGLEPerfTest()320 ANGLEPerfTest::~ANGLEPerfTest() {}
321 
run()322 void ANGLEPerfTest::run()
323 {
324     printf("running test name: \"%s\", backend: \"%s\", story: \"%s\"\n", mName.c_str(),
325            mBackend.c_str(), mStory.c_str());
326 #if defined(ANGLE_PLATFORM_ANDROID)
327     __android_log_print(ANDROID_LOG_INFO, "ANGLE",
328                         "running test name: \"%s\", backend: \"%s\", story: \"%s\"", mName.c_str(),
329                         mBackend.c_str(), mStory.c_str());
330 #endif
331     if (mSkipTest)
332     {
333         GTEST_SKIP() << mSkipTestReason;
334         // GTEST_SKIP returns.
335     }
336 
337     uint32_t numTrials = OneFrame() ? 1 : gTestTrials;
338     if (gVerboseLogging)
339     {
340         printf("Test Trials: %d\n", static_cast<int>(numTrials));
341     }
342 
343     atraceCounter("TraceStage", 3);
344 
345     for (uint32_t trial = 0; trial < numTrials; ++trial)
346     {
347         runTrial(gTrialTimeSeconds, mStepsToRun, RunTrialPolicy::RunContinuously);
348         processResults();
349         if (gVerboseLogging)
350         {
351             double trialTime = mTrialTimer.getElapsedWallClockTime();
352             printf("Trial %d time: %.2lf seconds.\n", trial + 1, trialTime);
353 
354             double secondsPerStep      = trialTime / static_cast<double>(mTrialNumStepsPerformed);
355             double secondsPerIteration = secondsPerStep / static_cast<double>(mIterationsPerStep);
356             mTestTrialResults.push_back(secondsPerIteration * 1000.0);
357         }
358     }
359 
360     atraceCounter("TraceStage", 0);
361 
362     if (gVerboseLogging && !mTestTrialResults.empty())
363     {
364         double numResults = static_cast<double>(mTestTrialResults.size());
365         double mean       = ComputeMean(mTestTrialResults);
366 
367         double variance = 0;
368         for (double trialResult : mTestTrialResults)
369         {
370             double difference = trialResult - mean;
371             variance += difference * difference;
372         }
373         variance /= numResults;
374 
375         double standardDeviation      = std::sqrt(variance);
376         double coefficientOfVariation = standardDeviation / mean;
377 
378         if (mean < 0.001)
379         {
380             printf("Mean result time: %.4lf ns.\n", mean * 1000.0);
381         }
382         else
383         {
384             printf("Mean result time: %.4lf ms.\n", mean);
385         }
386         printf("Coefficient of variation: %.2lf%%\n", coefficientOfVariation * 100.0);
387     }
388 }
389 
runTrial(double maxRunTime,int maxStepsToRun,RunTrialPolicy runPolicy)390 void ANGLEPerfTest::runTrial(double maxRunTime, int maxStepsToRun, RunTrialPolicy runPolicy)
391 {
392     mTrialNumStepsPerformed = 0;
393     mRunning                = true;
394     mGPUTimeNs              = 0;
395     int stepAlignment       = getStepAlignment();
396     mTrialTimer.start();
397     startTest();
398 
399     int loopStepsPerformed  = 0;
400     double lastLoopWallTime = 0;
401     while (mRunning)
402     {
403         // When ATrace enabled, track average frame time before the first frame of each trace loop.
404         if (ATraceEnabled() && stepAlignment > 1 && runPolicy == RunTrialPolicy::RunContinuously &&
405             mTrialNumStepsPerformed % stepAlignment == 0)
406         {
407             double wallTime = mTrialTimer.getElapsedWallClockTime();
408             if (loopStepsPerformed > 0)  // 0 at the first frame of the first loop
409             {
410                 int frameTimeAvgUs = int(1e6 * (wallTime - lastLoopWallTime) / loopStepsPerformed);
411                 atraceCounter("TraceLoopFrameTimeAvgUs", frameTimeAvgUs);
412                 loopStepsPerformed = 0;
413             }
414             lastLoopWallTime = wallTime;
415         }
416 
417         // Only stop on aligned steps or in a few special case modes
418         if (mTrialNumStepsPerformed % stepAlignment == 0 || gStepsPerTrial == 1 || gRunToKeyFrame ||
419             gMaxStepsPerformed != kDefaultMaxStepsPerformed)
420         {
421             if (gMaxStepsPerformed > 0 && mTotalNumStepsPerformed >= gMaxStepsPerformed)
422             {
423                 if (gVerboseLogging)
424                 {
425                     printf("Stopping test after %d total steps.\n", mTotalNumStepsPerformed);
426                 }
427                 mRunning = false;
428                 break;
429             }
430             if (mTrialTimer.getElapsedWallClockTime() > maxRunTime)
431             {
432                 if (gVerboseLogging)
433                 {
434                     printf("Stopping test after %.2lf seconds.\n",
435                            mTrialTimer.getElapsedWallClockTime());
436                 }
437                 mRunning = false;
438                 break;
439             }
440             if (mTrialNumStepsPerformed >= maxStepsToRun)
441             {
442                 if (gVerboseLogging)
443                 {
444                     printf("Stopping test after %d trial steps.\n", mTrialNumStepsPerformed);
445                 }
446                 mRunning = false;
447                 break;
448             }
449         }
450 
451         step();
452 
453         if (runPolicy == RunTrialPolicy::FinishEveryStep)
454         {
455             FinishAndCheckForContextLoss();
456         }
457 
458         if (mRunning)
459         {
460             mTrialNumStepsPerformed++;
461             mTotalNumStepsPerformed++;
462             loopStepsPerformed++;
463         }
464 
465         if ((mTotalNumStepsPerformed % kNumberOfStepsPerformedToComputeGPUTime) == 0)
466         {
467             computeGPUTime();
468         }
469     }
470 
471     if (runPolicy == RunTrialPolicy::RunContinuously)
472     {
473         atraceCounter("TraceLoopFrameTimeAvgUs", 0);
474     }
475     finishTest();
476     mTrialTimer.stop();
477     computeGPUTime();
478 }
479 
SetUp()480 void ANGLEPerfTest::SetUp()
481 {
482     if (gWarmup)
483     {
484         atraceCounter("TraceStage", 1);
485 
486         // Trace tests run with glFinish for a loop (getStepAlignment == frameCount).
487         int warmupSteps = getStepAlignment();
488         if (gVerboseLogging)
489         {
490             printf("Warmup: %d steps\n", warmupSteps);
491         }
492 
493         Timer warmupTimer;
494         warmupTimer.start();
495 
496         runTrial(gTrialTimeSeconds, warmupSteps, RunTrialPolicy::FinishEveryStep);
497 
498         if (warmupSteps > 1)  // trace tests only: getStepAlignment() is 1 otherwise
499         {
500             atraceCounter("TraceStage", 2);
501 
502             // Short traces (e.g. 10 frames) have some spikes after the first loop b/308975999
503             const double kMinWarmupTime = 1.5;
504             double remainingTime        = kMinWarmupTime - warmupTimer.getElapsedWallClockTime();
505             if (remainingTime > 0)
506             {
507                 printf("Warmup: Looping for remaining warmup time (%.2f seconds).\n",
508                        remainingTime);
509                 runTrial(remainingTime, std::numeric_limits<int>::max(),
510                          RunTrialPolicy::RunContinuouslyWarmup);
511             }
512         }
513 
514         if (gVerboseLogging)
515         {
516             printf("Warmup took %.2lf seconds.\n", warmupTimer.getElapsedWallClockTime());
517         }
518     }
519 }
520 
TearDown()521 void ANGLEPerfTest::TearDown() {}
522 
recordIntegerMetric(const char * metric,size_t value,const std::string & units)523 void ANGLEPerfTest::recordIntegerMetric(const char *metric, size_t value, const std::string &units)
524 {
525     // Prints "RESULT ..." to stdout
526     mReporter->AddResult(metric, value);
527 
528     // Saves results to file if enabled
529     TestSuite::GetMetricWriter().writeInfo(mName, mBackend, mStory, metric, units);
530     TestSuite::GetMetricWriter().writeIntegerValue(value);
531 }
532 
recordDoubleMetric(const char * metric,double value,const std::string & units)533 void ANGLEPerfTest::recordDoubleMetric(const char *metric, double value, const std::string &units)
534 {
535     // Prints "RESULT ..." to stdout
536     mReporter->AddResult(metric, value);
537 
538     // Saves results to file if enabled
539     TestSuite::GetMetricWriter().writeInfo(mName, mBackend, mStory, metric, units);
540     TestSuite::GetMetricWriter().writeDoubleValue(value);
541 }
542 
addHistogramSample(const char * metric,double value,const std::string & units)543 void ANGLEPerfTest::addHistogramSample(const char *metric, double value, const std::string &units)
544 {
545     std::string measurement = mName + mBackend + metric;
546     // Output histogram JSON set format if enabled.
547     TestSuite::GetInstance()->addHistogramSample(measurement, mStory, value, units);
548 }
549 
processResults()550 void ANGLEPerfTest::processResults()
551 {
552     processClockResult(".cpu_time", mTrialTimer.getElapsedCpuTime());
553     processClockResult(".wall_time", mTrialTimer.getElapsedWallClockTime());
554 
555     if (mGPUTimeNs > 0)
556     {
557         processClockResult(".gpu_time", mGPUTimeNs * 1e-9);
558     }
559 
560     if (gVerboseLogging)
561     {
562         double fps = static_cast<double>(mTrialNumStepsPerformed * mIterationsPerStep) /
563                      mTrialTimer.getElapsedWallClockTime();
564         printf("Ran %0.2lf iterations per second\n", fps);
565     }
566 
567     mReporter->AddResult(".trial_steps", static_cast<size_t>(mTrialNumStepsPerformed));
568     mReporter->AddResult(".total_steps", static_cast<size_t>(mTotalNumStepsPerformed));
569 
570     if (!mProcessMemoryUsageKBSamples.empty())
571     {
572         std::sort(mProcessMemoryUsageKBSamples.begin(), mProcessMemoryUsageKBSamples.end());
573 
574         // Compute median.
575         size_t medianIndex      = mProcessMemoryUsageKBSamples.size() / 2;
576         uint64_t medianMemoryKB = mProcessMemoryUsageKBSamples[medianIndex];
577         auto peakMemoryIterator = std::max_element(mProcessMemoryUsageKBSamples.begin(),
578                                                    mProcessMemoryUsageKBSamples.end());
579         uint64_t peakMemoryKB   = *peakMemoryIterator;
580 
581         processMemoryResult(kMedianMemoryMetric, medianMemoryKB);
582         processMemoryResult(kPeakMemoryMetric, peakMemoryKB);
583     }
584 
585     for (const auto &iter : mPerfCounterInfo)
586     {
587         const std::string &counterName = iter.second.name;
588         std::vector<GLuint64> samples  = iter.second.samples;
589 
590         // Median
591         {
592             size_t midpoint = samples.size() / 2;
593             std::nth_element(samples.begin(), samples.begin() + midpoint, samples.end());
594 
595             std::string medianName = "." + counterName + "_median";
596             recordIntegerMetric(medianName.c_str(), static_cast<size_t>(samples[midpoint]),
597                                 "count");
598             addHistogramSample(medianName.c_str(), static_cast<double>(samples[midpoint]), "count");
599         }
600 
601         // Maximum
602         {
603             const auto &maxIt = std::max_element(samples.begin(), samples.end());
604 
605             std::string maxName = "." + counterName + "_max";
606             recordIntegerMetric(maxName.c_str(), static_cast<size_t>(*maxIt), "count");
607             addHistogramSample(maxName.c_str(), static_cast<double>(*maxIt), "count");
608         }
609 
610         // Sum
611         {
612             GLuint64 sum =
613                 std::accumulate(samples.begin(), samples.end(), static_cast<GLuint64>(0));
614 
615             std::string sumName = "." + counterName + "_max";
616             recordIntegerMetric(sumName.c_str(), static_cast<size_t>(sum), "count");
617             addHistogramSample(sumName.c_str(), static_cast<double>(sum), "count");
618         }
619     }
620 }
621 
processClockResult(const char * metric,double resultSeconds)622 void ANGLEPerfTest::processClockResult(const char *metric, double resultSeconds)
623 {
624     double secondsPerStep      = resultSeconds / static_cast<double>(mTrialNumStepsPerformed);
625     double secondsPerIteration = secondsPerStep / static_cast<double>(mIterationsPerStep);
626 
627     perf_test::MetricInfo metricInfo;
628     std::string units;
629     bool foundMetric = mReporter->GetMetricInfo(metric, &metricInfo);
630     if (!foundMetric)
631     {
632         fprintf(stderr, "Error getting metric info for %s.\n", metric);
633         return;
634     }
635     units = metricInfo.units;
636 
637     double result;
638 
639     if (units == "ms")
640     {
641         result = secondsPerIteration * kMilliSecondsPerSecond;
642     }
643     else if (units == "us")
644     {
645         result = secondsPerIteration * kMicroSecondsPerSecond;
646     }
647     else
648     {
649         result = secondsPerIteration * kNanoSecondsPerSecond;
650     }
651     recordDoubleMetric(metric, result, units);
652     addHistogramSample(metric, secondsPerIteration * kMilliSecondsPerSecond,
653                        "msBestFitFormat_smallerIsBetter");
654 }
655 
processMemoryResult(const char * metric,uint64_t resultKB)656 void ANGLEPerfTest::processMemoryResult(const char *metric, uint64_t resultKB)
657 {
658     perf_test::MetricInfo metricInfo;
659     if (!mReporter->GetMetricInfo(metric, &metricInfo))
660     {
661         mReporter->RegisterImportantMetric(metric, "sizeInBytes");
662     }
663 
664     recordIntegerMetric(metric, static_cast<size_t>(resultKB * 1000), "sizeInBytes");
665     addHistogramSample(metric, static_cast<double>(resultKB) * 1000.0,
666                        "sizeInBytes_smallerIsBetter");
667 }
668 
normalizedTime(size_t value) const669 double ANGLEPerfTest::normalizedTime(size_t value) const
670 {
671     return static_cast<double>(value) / static_cast<double>(mTrialNumStepsPerformed);
672 }
673 
getStepAlignment() const674 int ANGLEPerfTest::getStepAlignment() const
675 {
676     // Default: No special alignment rules.
677     return 1;
678 }
679 
atraceCounter(const char * counterName,int64_t counterValue)680 void ANGLEPerfTest::atraceCounter(const char *counterName, int64_t counterValue)
681 {
682 #if defined(ANGLE_PLATFORM_ANDROID)
683     if (ATraceEnabled())
684     {
685         gATraceSetCounter(counterName, counterValue);
686     }
687 #endif
688 }
689 
RenderTestParams()690 RenderTestParams::RenderTestParams()
691 {
692 #if defined(ANGLE_DEBUG_LAYERS_ENABLED)
693     eglParameters.debugLayersEnabled = true;
694 #else
695     eglParameters.debugLayersEnabled = false;
696 #endif
697 }
698 
backend() const699 std::string RenderTestParams::backend() const
700 {
701     std::stringstream strstr;
702 
703     switch (driver)
704     {
705         case GLESDriverType::AngleEGL:
706             break;
707         case GLESDriverType::AngleVulkanSecondariesEGL:
708             strstr << "_vulkan_secondaries";
709             break;
710         case GLESDriverType::SystemWGL:
711         case GLESDriverType::SystemEGL:
712             strstr << "_native";
713             break;
714         case GLESDriverType::ZinkEGL:
715             strstr << "_zink";
716             break;
717         default:
718             assert(0);
719             return "_unk";
720     }
721 
722     switch (getRenderer())
723     {
724         case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
725             break;
726         case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
727             strstr << "_d3d11";
728             break;
729         case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
730             strstr << "_d3d9";
731             break;
732         case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
733             strstr << "_gl";
734             break;
735         case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
736             strstr << "_gles";
737             break;
738         case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
739             strstr << "_vulkan";
740             break;
741         case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
742             strstr << "_metal";
743             break;
744         default:
745             assert(0);
746             return "_unk";
747     }
748 
749     switch (eglParameters.deviceType)
750     {
751         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
752             strstr << "_null";
753             break;
754         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE:
755             strstr << "_swiftshader";
756             break;
757         default:
758             break;
759     }
760 
761     return strstr.str();
762 }
763 
story() const764 std::string RenderTestParams::story() const
765 {
766     std::stringstream strstr;
767 
768     switch (surfaceType)
769     {
770         case SurfaceType::Window:
771             break;
772         case SurfaceType::WindowWithVSync:
773             strstr << "_vsync";
774             break;
775         case SurfaceType::Offscreen:
776             strstr << "_offscreen";
777             break;
778         default:
779             UNREACHABLE();
780             return "";
781     }
782 
783     if (multisample)
784     {
785         strstr << "_" << samples << "_samples";
786     }
787 
788     return strstr.str();
789 }
790 
backendAndStory() const791 std::string RenderTestParams::backendAndStory() const
792 {
793     return backend() + story();
794 }
795 
ANGLERenderTest(const std::string & name,const RenderTestParams & testParams,const char * units)796 ANGLERenderTest::ANGLERenderTest(const std::string &name,
797                                  const RenderTestParams &testParams,
798                                  const char *units)
799     : ANGLEPerfTest(name,
800                     testParams.backend(),
801                     testParams.story(),
802                     OneFrame() ? 1 : testParams.iterationsPerStep,
803                     units),
804       mTestParams(testParams),
805       mIsTimestampQueryAvailable(false),
806       mGLWindow(nullptr),
807       mOSWindow(nullptr),
808       mSwapEnabled(true)
809 {
810     // Force fast tests to make sure our slowest bots don't time out.
811     if (OneFrame())
812     {
813         const_cast<RenderTestParams &>(testParams).iterationsPerStep = 1;
814     }
815 
816     // Try to ensure we don't trigger allocation during execution.
817     mTraceEventBuffer.reserve(kInitialTraceEventBufferSize);
818 
819     switch (testParams.driver)
820     {
821         case GLESDriverType::AngleEGL:
822             mGLWindow = EGLWindow::New(testParams.majorVersion, testParams.minorVersion);
823             mEntryPointsLib.reset(OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, SearchType::ModuleDir));
824             break;
825         case GLESDriverType::AngleVulkanSecondariesEGL:
826             mGLWindow = EGLWindow::New(testParams.majorVersion, testParams.minorVersion);
827             mEntryPointsLib.reset(OpenSharedLibrary(ANGLE_VULKAN_SECONDARIES_EGL_LIBRARY_NAME,
828                                                     SearchType::ModuleDir));
829             break;
830         case GLESDriverType::SystemEGL:
831 #if defined(ANGLE_USE_UTIL_LOADER) && !defined(ANGLE_PLATFORM_WINDOWS)
832             mGLWindow = EGLWindow::New(testParams.majorVersion, testParams.minorVersion);
833             mEntryPointsLib.reset(OpenSharedLibraryWithExtension(
834                 GetNativeEGLLibraryNameWithExtension(), SearchType::SystemDir));
835 #else
836             skipTest("Not implemented.");
837 #endif  // defined(ANGLE_USE_UTIL_LOADER) && !defined(ANGLE_PLATFORM_WINDOWS)
838             break;
839         case GLESDriverType::SystemWGL:
840 #if defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
841             mGLWindow = WGLWindow::New(testParams.majorVersion, testParams.minorVersion);
842             mEntryPointsLib.reset(OpenSharedLibrary("opengl32", SearchType::SystemDir));
843 #else
844             skipTest("WGL driver not available.");
845 #endif  // defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
846             break;
847         case GLESDriverType::ZinkEGL:
848             mGLWindow = EGLWindow::New(testParams.majorVersion, testParams.minorVersion);
849             mEntryPointsLib.reset(
850                 OpenSharedLibrary(ANGLE_MESA_EGL_LIBRARY_NAME, SearchType::ModuleDir));
851             break;
852         default:
853             skipTest("Error in switch.");
854             break;
855     }
856 }
857 
~ANGLERenderTest()858 ANGLERenderTest::~ANGLERenderTest()
859 {
860     OSWindow::Delete(&mOSWindow);
861     GLWindowBase::Delete(&mGLWindow);
862 }
863 
addExtensionPrerequisite(std::string extensionName)864 void ANGLERenderTest::addExtensionPrerequisite(std::string extensionName)
865 {
866     mExtensionPrerequisites.push_back(extensionName);
867 }
868 
addIntegerPrerequisite(GLenum target,int min)869 void ANGLERenderTest::addIntegerPrerequisite(GLenum target, int min)
870 {
871     mIntegerPrerequisites.push_back({target, min});
872 }
873 
SetUp()874 void ANGLERenderTest::SetUp()
875 {
876     if (mSkipTest)
877     {
878         return;
879     }
880 
881     // Set a consistent CPU core affinity and high priority.
882     StabilizeCPUForBenchmarking();
883 
884     mOSWindow = OSWindow::New();
885 
886     if (!mGLWindow)
887     {
888         skipTest("!mGLWindow");
889         return;
890     }
891 
892     mPlatformMethods.logError                    = CustomLogError;
893     mPlatformMethods.logWarning                  = EmptyPlatformMethod;
894     mPlatformMethods.logInfo                     = EmptyPlatformMethod;
895     mPlatformMethods.addTraceEvent               = AddPerfTraceEvent;
896     mPlatformMethods.getTraceCategoryEnabledFlag = GetPerfTraceCategoryEnabled;
897     mPlatformMethods.updateTraceEventDuration    = UpdateTraceEventDuration;
898     mPlatformMethods.monotonicallyIncreasingTime = MonotonicallyIncreasingTime;
899     mPlatformMethods.context                     = this;
900 
901     if (!mOSWindow->initialize(mName, mTestParams.windowWidth, mTestParams.windowHeight))
902     {
903         failTest("Failed initializing OSWindow");
904         return;
905     }
906 
907     // Override platform method parameter.
908     EGLPlatformParameters withMethods = mTestParams.eglParameters;
909     withMethods.platformMethods       = &mPlatformMethods;
910 
911     // Request a common framebuffer config
912     mConfigParams.redBits     = 8;
913     mConfigParams.greenBits   = 8;
914     mConfigParams.blueBits    = 8;
915     mConfigParams.alphaBits   = 8;
916     mConfigParams.depthBits   = 24;
917     mConfigParams.stencilBits = 8;
918     mConfigParams.colorSpace  = mTestParams.colorSpace;
919     mConfigParams.multisample = mTestParams.multisample;
920     mConfigParams.samples     = mTestParams.samples;
921     if (mTestParams.surfaceType != SurfaceType::WindowWithVSync)
922     {
923         mConfigParams.swapInterval = 0;
924     }
925 
926     if (gPrintExtensionsToFile != nullptr || gRequestedExtensions != nullptr)
927     {
928         mConfigParams.extensionsEnabled = false;
929     }
930 
931     GLWindowResult res = mGLWindow->initializeGLWithResult(
932         mOSWindow, mEntryPointsLib.get(), mTestParams.driver, withMethods, mConfigParams);
933     switch (res)
934     {
935         case GLWindowResult::NoColorspaceSupport:
936             skipTest("Missing support for color spaces.");
937             return;
938         case GLWindowResult::Error:
939             failTest("Failed initializing GL Window");
940             return;
941         default:
942             break;
943     }
944 
945     if (gPrintExtensionsToFile)
946     {
947         std::ofstream fout(gPrintExtensionsToFile);
948         if (fout.is_open())
949         {
950             int numExtensions = 0;
951             glGetIntegerv(GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE, &numExtensions);
952             for (int ext = 0; ext < numExtensions; ext++)
953             {
954                 fout << glGetStringi(GL_REQUESTABLE_EXTENSIONS_ANGLE, ext) << std::endl;
955             }
956             fout.close();
957             std::stringstream statusString;
958             statusString << "Wrote out to file: " << gPrintExtensionsToFile;
959             skipTest(statusString.str());
960         }
961         else
962         {
963             std::stringstream failStr;
964             failStr << "Failed to open file: " << gPrintExtensionsToFile;
965             failTest(failStr.str());
966         }
967         return;
968     }
969 
970     if (gRequestedExtensions != nullptr)
971     {
972         std::istringstream ss{gRequestedExtensions};
973         std::string ext;
974         while (std::getline(ss, ext, ' '))
975         {
976             glRequestExtensionANGLE(ext.c_str());
977         }
978     }
979 
980     // Disable vsync (if not done by the window init).
981     if (mTestParams.surfaceType != SurfaceType::WindowWithVSync)
982     {
983         if (!mGLWindow->setSwapInterval(0))
984         {
985             failTest("Failed setting swap interval");
986             return;
987         }
988     }
989 
990     if (mTestParams.trackGpuTime)
991     {
992         mIsTimestampQueryAvailable = EnsureGLExtensionEnabled("GL_EXT_disjoint_timer_query");
993     }
994 
995     skipTestIfMissingExtensionPrerequisites();
996     skipTestIfFailsIntegerPrerequisite();
997 
998     if (mSkipTest)
999     {
1000         GTEST_SKIP() << mSkipTestReason;
1001         // GTEST_SKIP returns.
1002     }
1003 
1004 #if defined(ANGLE_ENABLE_ASSERTS)
1005     if (IsGLExtensionEnabled("GL_KHR_debug") && mEnableDebugCallback)
1006     {
1007         EnableDebugCallback(&PerfTestDebugCallback, this);
1008     }
1009 #endif
1010 
1011     initializeBenchmark();
1012 
1013     if (mSkipTest)
1014     {
1015         GTEST_SKIP() << mSkipTestReason;
1016         // GTEST_SKIP returns.
1017     }
1018 
1019     if (mTestParams.iterationsPerStep == 0)
1020     {
1021         failTest("Please initialize 'iterationsPerStep'.");
1022         return;
1023     }
1024 
1025     if (gVerboseLogging)
1026     {
1027         printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
1028         printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
1029     }
1030 
1031     mTestTrialResults.reserve(gTestTrials);
1032 
1033     // Runs warmup if enabled
1034     ANGLEPerfTest::SetUp();
1035 
1036     initPerfCounters();
1037 }
1038 
TearDown()1039 void ANGLERenderTest::TearDown()
1040 {
1041     ASSERT(mTimestampQueries.empty());
1042 
1043     if (!mPerfCounterInfo.empty())
1044     {
1045         glDeletePerfMonitorsAMD(1, &mPerfMonitor);
1046         mPerfMonitor = 0;
1047     }
1048 
1049     if (!mSkipTest)
1050     {
1051         destroyBenchmark();
1052     }
1053 
1054     if (mGLWindow)
1055     {
1056         mGLWindow->destroyGL();
1057         mGLWindow = nullptr;
1058     }
1059 
1060     if (mOSWindow)
1061     {
1062         mOSWindow->destroy();
1063         mOSWindow = nullptr;
1064     }
1065 
1066     // Dump trace events to json file.
1067     if (gEnableTrace)
1068     {
1069         DumpTraceEventsToJSONFile(mTraceEventBuffer, gTraceFile);
1070     }
1071 
1072     ANGLEPerfTest::TearDown();
1073 }
1074 
initPerfCounters()1075 void ANGLERenderTest::initPerfCounters()
1076 {
1077     if (!gPerfCounters)
1078     {
1079         return;
1080     }
1081 
1082     if (!IsGLExtensionEnabled(kPerfMonitorExtensionName))
1083     {
1084         fprintf(stderr, "Cannot report perf metrics because %s is not available.\n",
1085                 kPerfMonitorExtensionName);
1086         return;
1087     }
1088 
1089     CounterNameToIndexMap indexMap = BuildCounterNameToIndexMap();
1090 
1091     std::vector<std::string> counters =
1092         angle::SplitString(gPerfCounters, ":", angle::WhitespaceHandling::TRIM_WHITESPACE,
1093                            angle::SplitResult::SPLIT_WANT_NONEMPTY);
1094     for (const std::string &counter : counters)
1095     {
1096         bool found = false;
1097 
1098         for (const auto &indexMapIter : indexMap)
1099         {
1100             const std::string &indexMapName = indexMapIter.first;
1101             if (NamesMatchWithWildcard(counter.c_str(), indexMapName.c_str()))
1102             {
1103                 {
1104                     std::stringstream medianStr;
1105                     medianStr << '.' << indexMapName << "_median";
1106                     std::string medianName = medianStr.str();
1107                     mReporter->RegisterImportantMetric(medianName, "count");
1108                 }
1109 
1110                 {
1111                     std::stringstream maxStr;
1112                     maxStr << '.' << indexMapName << "_max";
1113                     std::string maxName = maxStr.str();
1114                     mReporter->RegisterImportantMetric(maxName, "count");
1115                 }
1116 
1117                 {
1118                     std::stringstream sumStr;
1119                     sumStr << '.' << indexMapName << "_sum";
1120                     std::string sumName = sumStr.str();
1121                     mReporter->RegisterImportantMetric(sumName, "count");
1122                 }
1123 
1124                 GLuint index            = indexMapIter.second;
1125                 mPerfCounterInfo[index] = {indexMapName, {}};
1126 
1127                 found = true;
1128             }
1129         }
1130 
1131         if (!found)
1132         {
1133             fprintf(stderr, "'%s' does not match any available perf counters.\n", counter.c_str());
1134         }
1135     }
1136 
1137     if (!mPerfCounterInfo.empty())
1138     {
1139         glGenPerfMonitorsAMD(1, &mPerfMonitor);
1140         // Note: technically, glSelectPerfMonitorCountersAMD should be used to select the counters,
1141         // but currently ANGLE always captures all counters.
1142     }
1143 }
1144 
updatePerfCounters()1145 void ANGLERenderTest::updatePerfCounters()
1146 {
1147     if (mPerfCounterInfo.empty())
1148     {
1149         return;
1150     }
1151 
1152     std::vector<PerfMonitorTriplet> perfData = GetPerfMonitorTriplets();
1153     ASSERT(!perfData.empty());
1154 
1155     for (auto &iter : mPerfCounterInfo)
1156     {
1157         uint32_t counter               = iter.first;
1158         std::vector<GLuint64> &samples = iter.second.samples;
1159         samples.push_back(perfData[counter].value);
1160     }
1161 }
1162 
beginInternalTraceEvent(const char * name)1163 void ANGLERenderTest::beginInternalTraceEvent(const char *name)
1164 {
1165     if (gEnableTrace)
1166     {
1167         mTraceEventBuffer.emplace_back(TRACE_EVENT_PHASE_BEGIN, gTraceCategories[0].name, name,
1168                                        MonotonicallyIncreasingTime(&mPlatformMethods),
1169                                        getCurrentThreadSerial());
1170     }
1171 }
1172 
endInternalTraceEvent(const char * name)1173 void ANGLERenderTest::endInternalTraceEvent(const char *name)
1174 {
1175     if (gEnableTrace)
1176     {
1177         mTraceEventBuffer.emplace_back(TRACE_EVENT_PHASE_END, gTraceCategories[0].name, name,
1178                                        MonotonicallyIncreasingTime(&mPlatformMethods),
1179                                        getCurrentThreadSerial());
1180     }
1181 }
1182 
beginGLTraceEvent(const char * name,double hostTimeSec)1183 void ANGLERenderTest::beginGLTraceEvent(const char *name, double hostTimeSec)
1184 {
1185     if (gEnableTrace)
1186     {
1187         mTraceEventBuffer.emplace_back(TRACE_EVENT_PHASE_BEGIN, gTraceCategories[1].name, name,
1188                                        hostTimeSec, getCurrentThreadSerial());
1189     }
1190 }
1191 
endGLTraceEvent(const char * name,double hostTimeSec)1192 void ANGLERenderTest::endGLTraceEvent(const char *name, double hostTimeSec)
1193 {
1194     if (gEnableTrace)
1195     {
1196         mTraceEventBuffer.emplace_back(TRACE_EVENT_PHASE_END, gTraceCategories[1].name, name,
1197                                        hostTimeSec, getCurrentThreadSerial());
1198     }
1199 }
1200 
step()1201 void ANGLERenderTest::step()
1202 {
1203     beginInternalTraceEvent("step");
1204 
1205     // Clear events that the application did not process from this frame
1206     Event event;
1207     bool closed = false;
1208     while (popEvent(&event))
1209     {
1210         // If the application did not catch a close event, close now
1211         if (event.Type == Event::EVENT_CLOSED)
1212         {
1213             closed = true;
1214         }
1215     }
1216 
1217     if (closed)
1218     {
1219         abortTest();
1220     }
1221     else
1222     {
1223         drawBenchmark();
1224 
1225         // Swap is needed so that the GPU driver will occasionally flush its
1226         // internal command queue to the GPU. This is enabled for null back-end
1227         // devices because some back-ends (e.g. Vulkan) also accumulate internal
1228         // command queues.
1229         if (mSwapEnabled)
1230         {
1231             updatePerfCounters();
1232             mGLWindow->swap();
1233         }
1234         mOSWindow->messageLoop();
1235 
1236 #if defined(ANGLE_ENABLE_ASSERTS)
1237         if (!gRetraceMode)
1238         {
1239             EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
1240         }
1241 #endif  // defined(ANGLE_ENABLE_ASSERTS)
1242 
1243         // Sample system memory
1244         uint64_t processMemoryUsageKB = GetProcessMemoryUsageKB();
1245         if (processMemoryUsageKB)
1246         {
1247             mProcessMemoryUsageKBSamples.push_back(processMemoryUsageKB);
1248         }
1249     }
1250 
1251     endInternalTraceEvent("step");
1252 }
1253 
startGpuTimer()1254 void ANGLERenderTest::startGpuTimer()
1255 {
1256     if (mTestParams.trackGpuTime && mIsTimestampQueryAvailable)
1257     {
1258         glGenQueriesEXT(1, &mCurrentTimestampBeginQuery);
1259         glQueryCounterEXT(mCurrentTimestampBeginQuery, GL_TIMESTAMP_EXT);
1260     }
1261 }
1262 
stopGpuTimer()1263 void ANGLERenderTest::stopGpuTimer()
1264 {
1265     if (mTestParams.trackGpuTime && mIsTimestampQueryAvailable)
1266     {
1267         GLuint endQuery = 0;
1268         glGenQueriesEXT(1, &endQuery);
1269         glQueryCounterEXT(endQuery, GL_TIMESTAMP_EXT);
1270         mTimestampQueries.push({mCurrentTimestampBeginQuery, endQuery});
1271     }
1272 }
1273 
computeGPUTime()1274 void ANGLERenderTest::computeGPUTime()
1275 {
1276     if (mTestParams.trackGpuTime && mIsTimestampQueryAvailable)
1277     {
1278         while (!mTimestampQueries.empty())
1279         {
1280             const TimestampSample &sample = mTimestampQueries.front();
1281             GLuint available              = GL_FALSE;
1282             glGetQueryObjectuivEXT(sample.endQuery, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
1283             if (available != GL_TRUE)
1284             {
1285                 // query is not completed yet, bail out
1286                 break;
1287             }
1288 
1289             // frame's begin query must also completed.
1290             glGetQueryObjectuivEXT(sample.beginQuery, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
1291             ASSERT(available == GL_TRUE);
1292 
1293             // Retrieve query result
1294             uint64_t beginGLTimeNs = 0;
1295             uint64_t endGLTimeNs   = 0;
1296             glGetQueryObjectui64vEXT(sample.beginQuery, GL_QUERY_RESULT_EXT, &beginGLTimeNs);
1297             glGetQueryObjectui64vEXT(sample.endQuery, GL_QUERY_RESULT_EXT, &endGLTimeNs);
1298             glDeleteQueriesEXT(1, &sample.beginQuery);
1299             glDeleteQueriesEXT(1, &sample.endQuery);
1300             mTimestampQueries.pop();
1301 
1302             // compute GPU time
1303             mGPUTimeNs += endGLTimeNs - beginGLTimeNs;
1304         }
1305     }
1306 }
1307 
startTest()1308 void ANGLERenderTest::startTest()
1309 {
1310     if (!mPerfCounterInfo.empty())
1311     {
1312         glBeginPerfMonitorAMD(mPerfMonitor);
1313     }
1314 }
1315 
finishTest()1316 void ANGLERenderTest::finishTest()
1317 {
1318     if (mTestParams.eglParameters.deviceType != EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE &&
1319         !gNoFinish && !gRetraceMode)
1320     {
1321         FinishAndCheckForContextLoss();
1322     }
1323 
1324     if (!mPerfCounterInfo.empty())
1325     {
1326         glEndPerfMonitorAMD(mPerfMonitor);
1327     }
1328 }
1329 
popEvent(Event * event)1330 bool ANGLERenderTest::popEvent(Event *event)
1331 {
1332     return mOSWindow->popEvent(event);
1333 }
1334 
getWindow()1335 OSWindow *ANGLERenderTest::getWindow()
1336 {
1337     return mOSWindow;
1338 }
1339 
getGLWindow()1340 GLWindowBase *ANGLERenderTest::getGLWindow()
1341 {
1342     return mGLWindow;
1343 }
1344 
skipTestIfMissingExtensionPrerequisites()1345 void ANGLERenderTest::skipTestIfMissingExtensionPrerequisites()
1346 {
1347     for (std::string extension : mExtensionPrerequisites)
1348     {
1349         if (!CheckExtensionExists(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
1350                                   extension))
1351         {
1352             skipTest(std::string("Test skipped due to missing extension: ") + extension);
1353             return;
1354         }
1355     }
1356 }
1357 
skipTestIfFailsIntegerPrerequisite()1358 void ANGLERenderTest::skipTestIfFailsIntegerPrerequisite()
1359 {
1360     for (const auto [target, minRequired] : mIntegerPrerequisites)
1361     {
1362         GLint driverValue;
1363         glGetIntegerv(target, &driverValue);
1364         if (static_cast<int>(driverValue) < minRequired)
1365         {
1366             std::stringstream ss;
1367             ss << "Test skipped due to value (" << std::to_string(static_cast<int>(driverValue))
1368                << ") being less than the prerequisite minimum (" << std::to_string(minRequired)
1369                << ") for GL constant " << gl::GLenumToString(gl::GLESEnum::AllEnums, target);
1370             skipTest(ss.str());
1371         }
1372     }
1373 }
1374 
setWebGLCompatibilityEnabled(bool webglCompatibility)1375 void ANGLERenderTest::setWebGLCompatibilityEnabled(bool webglCompatibility)
1376 {
1377     mConfigParams.webGLCompatibility = webglCompatibility;
1378 }
1379 
setRobustResourceInit(bool enabled)1380 void ANGLERenderTest::setRobustResourceInit(bool enabled)
1381 {
1382     mConfigParams.robustResourceInit = enabled;
1383 }
1384 
getTraceEventBuffer()1385 std::vector<TraceEvent> &ANGLERenderTest::getTraceEventBuffer()
1386 {
1387     return mTraceEventBuffer;
1388 }
1389 
onErrorMessage(const char * errorMessage)1390 void ANGLERenderTest::onErrorMessage(const char *errorMessage)
1391 {
1392     abortTest();
1393     std::ostringstream err;
1394     err << "Failing test because of unexpected error:\n" << errorMessage << "\n";
1395     failTest(err.str());
1396 }
1397 
getCurrentThreadSerial()1398 uint32_t ANGLERenderTest::getCurrentThreadSerial()
1399 {
1400     uint64_t id = angle::GetCurrentThreadUniqueId();
1401 
1402     for (uint32_t serial = 0; serial < static_cast<uint32_t>(mThreadIDs.size()); ++serial)
1403     {
1404         if (mThreadIDs[serial] == id)
1405         {
1406             return serial + 1;
1407         }
1408     }
1409 
1410     mThreadIDs.push_back(id);
1411     return static_cast<uint32_t>(mThreadIDs.size());
1412 }
1413 
1414 namespace angle
1415 {
GetHostTimeSeconds()1416 double GetHostTimeSeconds()
1417 {
1418     // Move the time origin to the first call to this function, to avoid generating unnecessarily
1419     // large timestamps.
1420     static double origin = GetCurrentSystemTime();
1421     return GetCurrentSystemTime() - origin;
1422 }
1423 }  // namespace angle
1424