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