• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 // unique thread id stored in thread local storage
41 extern THREAD UINT tlsThreadId;
42 
43 //////////////////////////////////////////////////////////////////////////
44 /// @brief BucketManager encapsulates a single instance of the buckets
45 ///        functionality. There can be one or many bucket managers active
46 ///        at any time.  The manager owns all the threads and
47 ///        bucket information that have been registered to it.
48 class BucketManager
49 {
50 public:
BucketManager()51     BucketManager() { }
52     ~BucketManager();
53 
54     // removes all registered thread data
ClearThreads()55     void ClearThreads()
56     {
57         mThreadMutex.lock();
58         mThreads.clear();
59         mThreadMutex.unlock();
60     }
61 
62     // removes all registered buckets
ClearBuckets()63     void ClearBuckets()
64     {
65         mThreadMutex.lock();
66         mBuckets.clear();
67         mThreadMutex.unlock();
68     }
69 
70     /// Registers a new thread with the manager.
71     /// @param name - name of thread, used for labels in reports and threadviz
72     void RegisterThread(const std::string& name);
73 
74     /// Registers a new bucket type with the manager.  Returns a unique
75     /// id which should be used in subsequent calls to start/stop the bucket
76     /// @param desc - description of the bucket
77     /// @return unique id
78     UINT RegisterBucket(const BUCKET_DESC& desc);
79 
80     // print report
81     void PrintReport(const std::string& filename);
82 
83 
84     // start capturing
85     void StartCapture();
86 
87     // stop capturing
StopCapture()88     INLINE void StopCapture()
89     {
90         mCapturing = false;
91 
92         // wait for all threads to pop back to root bucket
93         bool stillCapturing = true;
94         while (stillCapturing)
95         {
96             stillCapturing = false;
97             for (const BUCKET_THREAD& t : mThreads)
98             {
99                 if (t.level > 0)
100                 {
101                     stillCapturing = true;
102                     continue;
103                 }
104             }
105         }
106 
107         mDoneCapturing = true;
108         printf("Capture Stopped\n");
109     }
110 
111     // start a bucket
112     // @param id generated by RegisterBucket
StartBucket(UINT id)113     INLINE void StartBucket(UINT id)
114     {
115         if (!mCapturing) return;
116 
117         SWR_ASSERT(tlsThreadId < mThreads.size());
118 
119         BUCKET_THREAD& bt = mThreads[tlsThreadId];
120 
121         uint64_t tsc = __rdtsc();
122 
123         {
124             if (bt.pCurrent->children.size() < mBuckets.size())
125             {
126                 bt.pCurrent->children.resize(mBuckets.size());
127             }
128             BUCKET &child = bt.pCurrent->children[id];
129             child.pParent = bt.pCurrent;
130             child.id = id;
131             child.start = tsc;
132 
133             // update thread's currently executing bucket
134             bt.pCurrent = &child;
135         }
136 
137 
138         bt.level++;
139     }
140 
141     // stop the currently executing bucket
StopBucket(UINT id)142     INLINE void StopBucket(UINT id)
143     {
144         SWR_ASSERT(tlsThreadId < mThreads.size());
145         BUCKET_THREAD &bt = mThreads[tlsThreadId];
146 
147         if (bt.level == 0)
148         {
149             return;
150         }
151 
152         uint64_t tsc = __rdtsc();
153 
154         {
155             if (bt.pCurrent->start == 0) return;
156             SWR_ASSERT(bt.pCurrent->id == id, "Mismatched buckets detected");
157 
158             bt.pCurrent->elapsed += (tsc - bt.pCurrent->start);
159             bt.pCurrent->count++;
160 
161             // pop to parent
162             bt.pCurrent = bt.pCurrent->pParent;
163         }
164 
165         bt.level--;
166     }
167 
AddEvent(uint32_t id,uint32_t count)168     INLINE void AddEvent(uint32_t id, uint32_t count)
169     {
170         if (!mCapturing) return;
171 
172         SWR_ASSERT(tlsThreadId < mThreads.size());
173 
174         BUCKET_THREAD& bt = mThreads[tlsThreadId];
175 
176         // don't record events for threadviz
177         {
178             if (bt.pCurrent->children.size() < mBuckets.size())
179             {
180                 bt.pCurrent->children.resize(mBuckets.size());
181             }
182             BUCKET &child = bt.pCurrent->children[id];
183             child.pParent = bt.pCurrent;
184             child.id = id;
185             child.count += count;
186         }
187     }
188 
189 private:
190     void PrintBucket(FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket);
191     void PrintThread(FILE* f, const BUCKET_THREAD& thread);
192 
193     // list of active threads that have registered with this manager
194     std::vector<BUCKET_THREAD> mThreads;
195 
196     // list of buckets registered with this manager
197     std::vector<BUCKET_DESC> mBuckets;
198 
199     // is capturing currently enabled
200     volatile bool mCapturing{ false };
201 
202     // has capturing completed
203     volatile bool mDoneCapturing{ false };
204 
205     std::mutex mThreadMutex;
206 
207     std::string mThreadVizDir;
208 
209 };
210 
211 
212 // C helpers for jitter
213 void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id);
214 void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id);
215