/**************************************************************************** * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * @file rdtsc_buckets.cpp * * @brief implementation of rdtsc buckets. * * Notes: * ******************************************************************************/ #include "rdtsc_buckets.h" #include #if defined(_WIN32) #define PATH_SEPARATOR "\\" #elif defined(__unix__) || defined(__APPLE__) #define PATH_SEPARATOR "/" #else #error "Unsupported platform" #endif THREAD UINT tlsThreadId = 0; BucketManager::~BucketManager() { } void BucketManager::RegisterThread(const std::string& name) { BUCKET_THREAD newThread; newThread.name = name; newThread.root.children.reserve(mBuckets.size()); newThread.root.id = 0; newThread.root.pParent = nullptr; newThread.pCurrent = &newThread.root; mThreadMutex.lock(); // assign unique thread id for this thread size_t id = mThreads.size(); newThread.id = (UINT)id; tlsThreadId = (UINT)id; // store new thread mThreads.push_back(newThread); mThreadMutex.unlock(); } UINT BucketManager::RegisterBucket(const BUCKET_DESC& desc) { mThreadMutex.lock(); size_t id = mBuckets.size(); mBuckets.push_back(desc); mThreadMutex.unlock(); return (UINT)id; } void BucketManager::PrintBucket( FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket) { const char* arrows[] = { "", "|-> ", " |-> ", " |-> ", " |-> ", " |-> ", " |-> ", " |-> ", " |-> ", }; // compute percent of total cycles used by this bucket float percentTotal = (float)((double)bucket.elapsed / (double)threadCycles * 100.0); // compute percent of parent cycles used by this bucket float percentParent = (float)((double)bucket.elapsed / (double)parentCycles * 100.0); // compute average cycle count per invocation uint64_t CPE = bucket.elapsed / bucket.count; BUCKET_DESC& desc = mBuckets[bucket.id]; // construct hierarchy visualization char hier[80]; strcpy(hier, arrows[level]); strcat(hier, desc.name.c_str()); // print out fprintf(f, "%6.2f %6.2f %-10" PRIu64 " %-10" PRIu64 " %-10u %-10lu %-10u %s\n", percentTotal, percentParent, bucket.elapsed, CPE, bucket.count, (unsigned long)0, (uint32_t)0, hier); // dump all children of this bucket for (const BUCKET& child : bucket.children) { if (child.count) { PrintBucket(f, level + 1, threadCycles, bucket.elapsed, child); } } } void BucketManager::PrintThread(FILE* f, const BUCKET_THREAD& thread) { // print header fprintf(f, "\nThread %u (%s)\n", thread.id, thread.name.c_str()); fprintf(f, " %%Tot %%Par Cycles CPE NumEvent CPE2 NumEvent2 Bucket\n"); // compute thread level total cycle counts across all buckets from root const BUCKET& root = thread.root; uint64_t totalCycles = 0; for (const BUCKET& child : root.children) { totalCycles += child.elapsed; } for (const BUCKET& child : root.children) { if (child.count) { PrintBucket(f, 0, totalCycles, totalCycles, child); } } } void BucketManager::PrintReport(const std::string& filename) { { FILE* f = fopen(filename.c_str(), "w"); mThreadMutex.lock(); for (const BUCKET_THREAD& thread : mThreads) { PrintThread(f, thread); fprintf(f, "\n"); } mThreadMutex.unlock(); fclose(f); } } void BucketManager::StartCapture() { printf("Capture Starting\n"); mCapturing = true; } void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id) { pBucketMgr->StartBucket(id); } void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id) { pBucketMgr->StopBucket(id); }