9dfa7f694d0e87b567c30b8943567874fe221a02
[mesa.git] / src / gallium / drivers / swr / rasterizer / common / rdtsc_buckets.h
1 /****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * @file rdtsc_buckets.h
24 *
25 * @brief declaration for rdtsc buckets.
26 *
27 * Notes:
28 *
29 ******************************************************************************/
30 #pragma once
31
32 #include "os.h"
33 #include <vector>
34 #include <mutex>
35 #include <sstream>
36
37 #include "rdtsc_buckets_shared.h"
38
39 // unique thread id stored in thread local storage
40 extern THREAD UINT tlsThreadId;
41
42 //////////////////////////////////////////////////////////////////////////
43 /// @brief BucketManager encapsulates a single instance of the buckets
44 /// functionality. There can be one or many bucket managers active
45 /// at any time. The manager owns all the threads and
46 /// bucket information that have been registered to it.
47 class BucketManager
48 {
49 public:
50 BucketManager(bool enableThreadViz) : mThreadViz(enableThreadViz)
51 {
52 if (mThreadViz)
53 {
54 uint32_t pid = GetCurrentProcessId();
55 std::stringstream str;
56 str << "threadviz." << pid;
57 mThreadVizDir = str.str();
58 CreateDirectory(mThreadVizDir.c_str(), NULL);
59 }
60 }
61
62 // removes all registered thread data
63 void ClearThreads()
64 {
65 mThreadMutex.lock();
66 mThreads.clear();
67 mThreadMutex.unlock();
68 }
69
70 // removes all registered buckets
71 void ClearBuckets()
72 {
73 mThreadMutex.lock();
74 mBuckets.clear();
75 mThreadMutex.unlock();
76 }
77
78 /// Registers a new thread with the manager.
79 /// @param name - name of thread, used for labels in reports and threadviz
80 void RegisterThread(const std::string& name);
81
82 /// Registers a new bucket type with the manager. Returns a unique
83 /// id which should be used in subsequent calls to start/stop the bucket
84 /// @param desc - description of the bucket
85 /// @return unique id
86 UINT RegisterBucket(const BUCKET_DESC& desc);
87
88 // dump threadviz data
89 void DumpThreadViz();
90
91 // print report
92 void PrintReport(const std::string& filename);
93
94 // start capturing
95 INLINE void StartCapture()
96 {
97 mCapturing = true;
98 }
99
100 // stop capturing
101 INLINE void StopCapture()
102 {
103 mCapturing = false;
104
105 // wait for all threads to pop back to root bucket
106 bool stillCapturing = true;
107 while (stillCapturing)
108 {
109 stillCapturing = false;
110 for (const BUCKET_THREAD& t : mThreads)
111 {
112 if (t.pCurrent != &t.root)
113 {
114 stillCapturing = true;
115 continue;
116 }
117 }
118 }
119 }
120
121 // start a bucket
122 // @param id generated by RegisterBucket
123 INLINE void StartBucket(UINT id)
124 {
125 if (!mCapturing) return;
126
127 SWR_ASSERT(tlsThreadId < mThreads.size());
128
129 BUCKET_THREAD& bt = mThreads[tlsThreadId];
130
131 // if threadviz is enabled, only need to dump start info to threads viz file
132 if (mThreadViz)
133 {
134 SWR_ASSERT(bt.vizFile != nullptr);
135 if (mBuckets[id].enableThreadViz)
136 {
137 VIZ_START_DATA data{ VIZ_START, id, __rdtsc() };
138 Serialize(bt.vizFile, data);
139 }
140 }
141 else
142 {
143 if (bt.pCurrent->children.size() < mBuckets.size())
144 {
145 bt.pCurrent->children.resize(mBuckets.size());
146 }
147 BUCKET &child = bt.pCurrent->children[id];
148 child.pParent = bt.pCurrent;
149 child.id = id;
150 child.start = __rdtsc();
151
152 // update thread's currently executing bucket
153 bt.pCurrent = &child;
154 }
155
156 bt.level++;
157 }
158
159 // stop the currently executing bucket
160 INLINE void StopBucket(UINT id)
161 {
162 SWR_ASSERT(tlsThreadId < mThreads.size());
163 BUCKET_THREAD &bt = mThreads[tlsThreadId];
164
165 if (bt.level == 0) return;
166
167 if (mThreadViz)
168 {
169 SWR_ASSERT(bt.vizFile != nullptr);
170 if (mBuckets[id].enableThreadViz)
171 {
172 VIZ_STOP_DATA data{ VIZ_STOP, __rdtsc() };
173 Serialize(bt.vizFile, data);
174 }
175 }
176 else
177 {
178 if (bt.pCurrent->start == 0) return;
179 SWR_ASSERT(bt.pCurrent->id == id, "Mismatched buckets detected");
180
181 bt.pCurrent->elapsed += (__rdtsc() - bt.pCurrent->start);
182 bt.pCurrent->count++;
183
184 // pop to parent
185 bt.pCurrent = bt.pCurrent->pParent;
186 }
187
188 bt.level--;
189 }
190
191 INLINE void AddEvent(uint32_t id, uint32_t count)
192 {
193 if (!mCapturing) return;
194
195 SWR_ASSERT(tlsThreadId < mThreads.size());
196
197 BUCKET_THREAD& bt = mThreads[tlsThreadId];
198
199 // don't record events for threadviz
200 if (!mThreadViz)
201 {
202 if (bt.pCurrent->children.size() < mBuckets.size())
203 {
204 bt.pCurrent->children.resize(mBuckets.size());
205 }
206 BUCKET &child = bt.pCurrent->children[id];
207 child.pParent = bt.pCurrent;
208 child.id = id;
209 child.count += count;
210 }
211 }
212
213 private:
214 void PrintBucket(FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket);
215 void PrintThread(FILE* f, const BUCKET_THREAD& thread);
216
217 // list of active threads that have registered with this manager
218 std::vector<BUCKET_THREAD> mThreads;
219
220 // list of buckets registered with this manager
221 std::vector<BUCKET_DESC> mBuckets;
222
223 // is capturing currently enabled
224 volatile bool mCapturing{ false };
225
226 std::mutex mThreadMutex;
227
228 // enable threadviz
229 bool mThreadViz{ false };
230 std::string mThreadVizDir;
231 };
232
233
234 // C helpers for jitter
235 void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id);
236 void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id);