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 41extern 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. 48class BucketManager 49{ 50public: 51 BucketManager() {} 52 ~BucketManager(); 53 54 // removes all registered thread data 55 void ClearThreads() 56 { 57 mThreadMutex.lock(); 58 mThreads.clear(); 59 mThreadMutex.unlock(); 60 } 61 62 // removes all registered buckets 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 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 113 INLINE void StartBucket(UINT id) 114 { 115 if (!mCapturing) 116 return; 117 118 SWR_ASSERT(tlsThreadId < mThreads.size()); 119 120 BUCKET_THREAD& bt = mThreads[tlsThreadId]; 121 122 uint64_t tsc = __rdtsc(); 123 124 { 125 if (bt.pCurrent->children.size() < mBuckets.size()) 126 { 127 bt.pCurrent->children.resize(mBuckets.size()); 128 } 129 BUCKET& child = bt.pCurrent->children[id]; 130 child.pParent = bt.pCurrent; 131 child.id = id; 132 child.start = tsc; 133 134 // update thread's currently executing bucket 135 bt.pCurrent = &child; 136 } 137 138 139 bt.level++; 140 } 141 142 // stop the currently executing bucket 143 INLINE void StopBucket(UINT id) 144 { 145 SWR_ASSERT(tlsThreadId < mThreads.size()); 146 BUCKET_THREAD& bt = mThreads[tlsThreadId]; 147 148 if (bt.level == 0) 149 { 150 return; 151 } 152 153 uint64_t tsc = __rdtsc(); 154 155 { 156 if (bt.pCurrent->start == 0) 157 return; 158 SWR_ASSERT(bt.pCurrent->id == id, "Mismatched buckets detected"); 159 160 bt.pCurrent->elapsed += (tsc - bt.pCurrent->start); 161 bt.pCurrent->count++; 162 163 // pop to parent 164 bt.pCurrent = bt.pCurrent->pParent; 165 } 166 167 bt.level--; 168 } 169 170 INLINE void AddEvent(uint32_t id, uint32_t count) 171 { 172 if (!mCapturing) 173 return; 174 175 SWR_ASSERT(tlsThreadId < mThreads.size()); 176 177 BUCKET_THREAD& bt = mThreads[tlsThreadId]; 178 179 // don't record events for threadviz 180 { 181 if (bt.pCurrent->children.size() < mBuckets.size()) 182 { 183 bt.pCurrent->children.resize(mBuckets.size()); 184 } 185 BUCKET& child = bt.pCurrent->children[id]; 186 child.pParent = bt.pCurrent; 187 child.id = id; 188 child.count += count; 189 } 190 } 191 192private: 193 void PrintBucket( 194 FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket); 195 void PrintThread(FILE* f, const BUCKET_THREAD& thread); 196 197 // list of active threads that have registered with this manager 198 std::vector<BUCKET_THREAD> mThreads; 199 200 // list of buckets registered with this manager 201 std::vector<BUCKET_DESC> mBuckets; 202 203 // is capturing currently enabled 204 volatile bool mCapturing{false}; 205 206 // has capturing completed 207 volatile bool mDoneCapturing{false}; 208 209 std::mutex mThreadMutex; 210 211 std::string mThreadVizDir; 212 213}; 214 215// C helpers for jitter 216void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id); 217void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id); 218