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.cpp 24 * 25 * @brief implementation of rdtsc buckets. 26 * 27 * Notes: 28 * 29 ******************************************************************************/ 30#include "rdtsc_buckets.h" 31#include <inttypes.h> 32 33#if defined(_WIN32) 34#define PATH_SEPARATOR "\\" 35#elif defined(__unix__) || defined(__APPLE__) 36#define PATH_SEPARATOR "/" 37#else 38#error "Unsupported platform" 39#endif 40 41THREAD UINT tlsThreadId = 0; 42 43BucketManager::~BucketManager() 44{ 45} 46 47void BucketManager::RegisterThread(const std::string& name) 48{ 49 50 BUCKET_THREAD newThread; 51 newThread.name = name; 52 newThread.root.children.reserve(mBuckets.size()); 53 newThread.root.id = 0; 54 newThread.root.pParent = nullptr; 55 newThread.pCurrent = &newThread.root; 56 57 mThreadMutex.lock(); 58 59 // assign unique thread id for this thread 60 size_t id = mThreads.size(); 61 newThread.id = (UINT)id; 62 tlsThreadId = (UINT)id; 63 64 // store new thread 65 mThreads.push_back(newThread); 66 67 mThreadMutex.unlock(); 68} 69 70UINT BucketManager::RegisterBucket(const BUCKET_DESC& desc) 71{ 72 mThreadMutex.lock(); 73 size_t id = mBuckets.size(); 74 mBuckets.push_back(desc); 75 mThreadMutex.unlock(); 76 return (UINT)id; 77} 78 79void BucketManager::PrintBucket( 80 FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket) 81{ 82 const char* arrows[] = { 83 "", 84 "|-> ", 85 " |-> ", 86 " |-> ", 87 " |-> ", 88 " |-> ", 89 " |-> ", 90 " |-> ", 91 " |-> ", 92 }; 93 94 // compute percent of total cycles used by this bucket 95 float percentTotal = (float)((double)bucket.elapsed / (double)threadCycles * 100.0); 96 97 // compute percent of parent cycles used by this bucket 98 float percentParent = (float)((double)bucket.elapsed / (double)parentCycles * 100.0); 99 100 // compute average cycle count per invocation 101 uint64_t CPE = bucket.elapsed / bucket.count; 102 103 BUCKET_DESC& desc = mBuckets[bucket.id]; 104 105 // construct hierarchy visualization 106 std::string str = arrows[level]; 107 str += desc.name; 108 char hier[80]; 109 strcpy_s(hier, sizeof(hier)-1, str.c_str()); 110 111 // print out 112 fprintf(f, 113 "%6.2f %6.2f %-10" PRIu64 " %-10" PRIu64 " %-10u %-10lu %-10u %s\n", 114 percentTotal, 115 percentParent, 116 bucket.elapsed, 117 CPE, 118 bucket.count, 119 (unsigned long)0, 120 (uint32_t)0, 121 hier); 122 123 // dump all children of this bucket 124 for (const BUCKET& child : bucket.children) 125 { 126 if (child.count) 127 { 128 PrintBucket(f, level + 1, threadCycles, bucket.elapsed, child); 129 } 130 } 131} 132 133void BucketManager::PrintThread(FILE* f, const BUCKET_THREAD& thread) 134{ 135 // print header 136 fprintf(f, "\nThread %u (%s)\n", thread.id, thread.name.c_str()); 137 fprintf(f, " %%Tot %%Par Cycles CPE NumEvent CPE2 NumEvent2 Bucket\n"); 138 139 // compute thread level total cycle counts across all buckets from root 140 const BUCKET& root = thread.root; 141 uint64_t totalCycles = 0; 142 for (const BUCKET& child : root.children) 143 { 144 totalCycles += child.elapsed; 145 } 146 147 for (const BUCKET& child : root.children) 148 { 149 if (child.count) 150 { 151 PrintBucket(f, 0, totalCycles, totalCycles, child); 152 } 153 } 154} 155 156void BucketManager::PrintReport(const std::string& filename) 157{ 158 { 159 FILE* f = fopen(filename.c_str(), "w"); 160 assert(f); 161 162 mThreadMutex.lock(); 163 for (const BUCKET_THREAD& thread : mThreads) 164 { 165 PrintThread(f, thread); 166 fprintf(f, "\n"); 167 } 168 169 mThreadMutex.unlock(); 170 171 fclose(f); 172 } 173} 174 175 176void BucketManager::StartCapture() 177{ 178 179 printf("Capture Starting\n"); 180 181 mCapturing = true; 182} 183 184void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id) 185{ 186 pBucketMgr->StartBucket(id); 187} 188 189void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id) 190{ 191 pBucketMgr->StopBucket(id); 192} 193