• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "tests/perf_tests/DawnPerfTestPlatform.h"
16 
17 #include <algorithm>
18 
19 #include "common/Assert.h"
20 #include "common/HashUtils.h"
21 #include "dawn_platform/tracing/TraceEvent.h"
22 #include "tests/perf_tests/DawnPerfTest.h"
23 #include "utils/Timer.h"
24 namespace {
25 
26     struct TraceCategoryInfo {
27         unsigned char enabled;
28         dawn_platform::TraceCategory category;
29     };
30 
31     constexpr TraceCategoryInfo gTraceCategories[4] = {
32         {1, dawn_platform::TraceCategory::General},
33         {1, dawn_platform::TraceCategory::Validation},
34         {1, dawn_platform::TraceCategory::Recording},
35         {1, dawn_platform::TraceCategory::GPUWork},
36     };
37 
38     static_assert(static_cast<uint32_t>(dawn_platform::TraceCategory::General) == 0, "");
39     static_assert(static_cast<uint32_t>(dawn_platform::TraceCategory::Validation) == 1, "");
40     static_assert(static_cast<uint32_t>(dawn_platform::TraceCategory::Recording) == 2, "");
41     static_assert(static_cast<uint32_t>(dawn_platform::TraceCategory::GPUWork) == 3, "");
42 
43 }  // anonymous namespace
44 
DawnPerfTestPlatform()45 DawnPerfTestPlatform::DawnPerfTestPlatform()
46     : dawn_platform::Platform(), mTimer(utils::CreateTimer()) {
47 }
48 
49 DawnPerfTestPlatform::~DawnPerfTestPlatform() = default;
50 
GetTraceCategoryEnabledFlag(dawn_platform::TraceCategory category)51 const unsigned char* DawnPerfTestPlatform::GetTraceCategoryEnabledFlag(
52     dawn_platform::TraceCategory category) {
53     switch (category) {
54         case dawn_platform::TraceCategory::General:
55         case dawn_platform::TraceCategory::Validation:
56         case dawn_platform::TraceCategory::Recording:
57         case dawn_platform::TraceCategory::GPUWork:
58             break;
59         default:
60             UNREACHABLE();
61     }
62     return &gTraceCategories[static_cast<uint32_t>(category)].enabled;
63 }
64 
MonotonicallyIncreasingTime()65 double DawnPerfTestPlatform::MonotonicallyIncreasingTime() {
66     // Move the time origin to the first call to this function, to avoid generating
67     // unnecessarily large timestamps.
68     static double origin = mTimer->GetAbsoluteTime();
69     return mTimer->GetAbsoluteTime() - origin;
70 }
71 
GetLocalTraceEventBuffer()72 std::vector<DawnPerfTestPlatform::TraceEvent>* DawnPerfTestPlatform::GetLocalTraceEventBuffer() {
73     // Cache the pointer to the vector in thread_local storage
74     thread_local std::vector<TraceEvent>* traceEventBuffer = nullptr;
75 
76     if (traceEventBuffer == nullptr) {
77         auto buffer = std::make_unique<std::vector<TraceEvent>>();
78         traceEventBuffer = buffer.get();
79 
80         // Add a new buffer to the map
81         std::lock_guard<std::mutex> guard(mTraceEventBufferMapMutex);
82         mTraceEventBuffers[std::this_thread::get_id()] = std::move(buffer);
83     }
84 
85     return traceEventBuffer;
86 }
87 
88 // TODO(enga): Simplify this API.
AddTraceEvent(char phase,const unsigned char * categoryGroupEnabled,const char * name,uint64_t id,double timestamp,int numArgs,const char ** argNames,const unsigned char * argTypes,const uint64_t * argValues,unsigned char flags)89 uint64_t DawnPerfTestPlatform::AddTraceEvent(char phase,
90                                              const unsigned char* categoryGroupEnabled,
91                                              const char* name,
92                                              uint64_t id,
93                                              double timestamp,
94                                              int numArgs,
95                                              const char** argNames,
96                                              const unsigned char* argTypes,
97                                              const uint64_t* argValues,
98                                              unsigned char flags) {
99     if (!mRecordTraceEvents) {
100         return 0;
101     }
102 
103     // Discover the category name based on categoryGroupEnabled.  This flag comes from the first
104     // parameter of TraceCategory, and corresponds to one of the entries in gTraceCategories.
105     static_assert(offsetof(TraceCategoryInfo, enabled) == 0,
106                   "|enabled| must be the first field of the TraceCategoryInfo class.");
107 
108     const TraceCategoryInfo* info =
109         reinterpret_cast<const TraceCategoryInfo*>(categoryGroupEnabled);
110 
111     std::vector<TraceEvent>* buffer = GetLocalTraceEventBuffer();
112     buffer->emplace_back(phase, info->category, name, id, timestamp);
113 
114     size_t hash = 0;
115     HashCombine(&hash, buffer->size());
116     HashCombine(&hash, std::this_thread::get_id());
117     return static_cast<uint64_t>(hash);
118 }
119 
EnableTraceEventRecording(bool enable)120 void DawnPerfTestPlatform::EnableTraceEventRecording(bool enable) {
121     mRecordTraceEvents = enable;
122 }
123 
AcquireTraceEventBuffer()124 std::vector<DawnPerfTestPlatform::TraceEvent> DawnPerfTestPlatform::AcquireTraceEventBuffer() {
125     std::vector<TraceEvent> traceEventBuffer;
126     {
127         // AcquireTraceEventBuffer should only be called when Dawn is completely idle. There should
128         // be no threads inserting trace events.
129         // Right now, this is safe because AcquireTraceEventBuffer is called after waiting on a
130         // fence for all GPU commands to finish executing. When Dawn has multiple background threads
131         // for other work (creation, validation, submission, residency, etc), we will need to ensure
132         // all work on those threads is stopped as well.
133         std::lock_guard<std::mutex> guard(mTraceEventBufferMapMutex);
134         for (auto it = mTraceEventBuffers.begin(); it != mTraceEventBuffers.end(); ++it) {
135             std::ostringstream stream;
136             stream << it->first;
137             std::string threadId = stream.str();
138 
139             std::transform(it->second->begin(), it->second->end(),
140                            std::back_inserter(traceEventBuffer), [&threadId](TraceEvent ev) {
141                                ev.threadId = threadId;
142                                return ev;
143                            });
144             it->second->clear();
145         }
146     }
147     return traceEventBuffer;
148 }
149