/****************************************************************************
* 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 <inttypes.h>
#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);
}