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 41 THREAD UINT tlsThreadId = 0; 42 43 BucketManager::~BucketManager() 44 { 45 } 46 47 void 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 70 UINT 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 79 void BucketManager::PrintBucket(FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket) 80 { 81 const char *arrows[] = { 82 "", 83 "|-> ", 84 " |-> ", 85 " |-> ", 86 " |-> ", 87 " |-> ", 88 " |-> ", 89 " |-> ", 90 " |-> ", 91 }; 92 93 // compute percent of total cycles used by this bucket 94 float percentTotal = (float)((double)bucket.elapsed / (double)threadCycles * 100.0); 95 96 // compute percent of parent cycles used by this bucket 97 float percentParent = (float)((double)bucket.elapsed / (double)parentCycles * 100.0); 98 99 // compute average cycle count per invocation 100 uint64_t CPE = bucket.elapsed / bucket.count; 101 102 BUCKET_DESC &desc = mBuckets[bucket.id]; 103 104 // construct hierarchy visualization 105 char hier[80]; 106 strcpy(hier, arrows[level]); 107 strcat(hier, desc.name.c_str()); 108 109 // print out 110 fprintf(f, "%6.2f %6.2f %-10" PRIu64 " %-10" PRIu64 " %-10u %-10lu %-10u %s\n", 111 percentTotal, 112 percentParent, 113 bucket.elapsed, 114 CPE, 115 bucket.count, 116 (unsigned long)0, 117 (uint32_t)0, 118 hier 119 ); 120 121 // dump all children of this bucket 122 for (const BUCKET& child : bucket.children) 123 { 124 if (child.count) 125 { 126 PrintBucket(f, level + 1, threadCycles, bucket.elapsed, child); 127 } 128 } 129 } 130 131 void BucketManager::PrintThread(FILE* f, const BUCKET_THREAD& thread) 132 { 133 // print header 134 fprintf(f, "\nThread %u (%s)\n", thread.id, thread.name.c_str()); 135 fprintf(f, " %%Tot %%Par Cycles CPE NumEvent CPE2 NumEvent2 Bucket\n"); 136 137 // compute thread level total cycle counts across all buckets from root 138 const BUCKET& root = thread.root; 139 uint64_t totalCycles = 0; 140 for (const BUCKET& child : root.children) 141 { 142 totalCycles += child.elapsed; 143 } 144 145 for (const BUCKET& child : root.children) 146 { 147 if (child.count) 148 { 149 PrintBucket(f, 0, totalCycles, totalCycles, child); 150 } 151 } 152 } 153 154 void BucketManager::PrintReport(const std::string& filename) 155 { 156 { 157 FILE* f = fopen(filename.c_str(), "w"); 158 159 mThreadMutex.lock(); 160 for (const BUCKET_THREAD& thread : mThreads) 161 { 162 PrintThread(f, thread); 163 fprintf(f, "\n"); 164 } 165 166 mThreadMutex.unlock(); 167 168 fclose(f); 169 } 170 } 171 172 173 void BucketManager::StartCapture() 174 { 175 176 printf("Capture Starting\n"); 177 178 mCapturing = true; 179 } 180 181 void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id) 182 { 183 pBucketMgr->StartBucket(id); 184 } 185 186 void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id) 187 { 188 pBucketMgr->StopBucket(id); 189 } 190