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