1 /****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved.
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:
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
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
23 * @file rdtsc_buckets.cpp
25 * @brief implementation of rdtsc buckets.
29 ******************************************************************************/
30 #include "rdtsc_buckets.h"
33 THREAD UINT tlsThreadId
= 0;
35 void BucketManager::RegisterThread(const std::string
& name
)
37 // lazy evaluate threadviz knob
38 if (!mThreadViz
&& KNOB_BUCKETS_ENABLE_THREADVIZ
)
40 uint32_t pid
= GetCurrentProcessId();
41 std::stringstream str
;
42 str
<< "threadviz." << pid
;
43 mThreadVizDir
= str
.str();
44 CreateDirectory(mThreadVizDir
.c_str(), NULL
);
49 BUCKET_THREAD newThread
;
50 newThread
.name
= name
;
51 newThread
.root
.children
.reserve(mBuckets
.size());
52 newThread
.root
.id
= 0;
53 newThread
.root
.pParent
= nullptr;
54 newThread
.pCurrent
= &newThread
.root
;
58 // assign unique thread id for this thread
59 size_t id
= mThreads
.size();
60 newThread
.id
= (UINT
)id
;
61 tlsThreadId
= (UINT
)id
;
63 // open threadviz file if enabled
67 ss
<< mThreadVizDir
<< "\\threadviz_thread." << newThread
.id
<< ".dat";
68 newThread
.vizFile
= fopen(ss
.str().c_str(), "wb");
72 mThreads
.push_back(newThread
);
74 mThreadMutex
.unlock();
77 UINT
BucketManager::RegisterBucket(const BUCKET_DESC
& desc
)
80 size_t id
= mBuckets
.size();
81 mBuckets
.push_back(desc
);
82 mThreadMutex
.unlock();
86 void BucketManager::PrintBucket(FILE* f
, UINT level
, uint64_t threadCycles
, uint64_t parentCycles
, const BUCKET
& bucket
)
88 const char *arrows
[] = {
100 // compute percent of total cycles used by this bucket
101 float percentTotal
= (float)((double)bucket
.elapsed
/ (double)threadCycles
* 100.0);
103 // compute percent of parent cycles used by this bucket
104 float percentParent
= (float)((double)bucket
.elapsed
/ (double)parentCycles
* 100.0);
106 // compute average cycle count per invocation
107 uint64_t CPE
= bucket
.elapsed
/ bucket
.count
;
109 BUCKET_DESC
&desc
= mBuckets
[bucket
.id
];
111 // construct hierarchy visualization
113 strcpy(hier
, arrows
[level
]);
114 strcat(hier
, desc
.name
.c_str());
117 fprintf(f
, "%6.2f %6.2f %-10" PRIu64
" %-10" PRIu64
" %-10u %-10lu %-10u %s\n",
128 // dump all children of this bucket
129 for (const BUCKET
& child
: bucket
.children
)
133 PrintBucket(f
, level
+ 1, threadCycles
, bucket
.elapsed
, child
);
138 void BucketManager::PrintThread(FILE* f
, const BUCKET_THREAD
& thread
)
141 fprintf(f
, "\nThread %u (%s)\n", thread
.id
, thread
.name
.c_str());
142 fprintf(f
, " %%Tot %%Par Cycles CPE NumEvent CPE2 NumEvent2 Bucket\n");
144 // compute thread level total cycle counts across all buckets from root
145 const BUCKET
& root
= thread
.root
;
146 uint64_t totalCycles
= 0;
147 for (const BUCKET
& child
: root
.children
)
149 totalCycles
+= child
.elapsed
;
152 for (const BUCKET
& child
: root
.children
)
156 PrintBucket(f
, 0, totalCycles
, totalCycles
, child
);
161 void BucketManager::DumpThreadViz()
163 // ensure all thread data is flushed
165 for (auto& thread
: mThreads
)
167 fflush(thread
.vizFile
);
168 fclose(thread
.vizFile
);
170 mThreadMutex
.unlock();
172 // dump bucket descriptions
173 std::stringstream ss
;
174 ss
<< mThreadVizDir
<< "\\threadviz_buckets.dat";
176 FILE* f
= fopen(ss
.str().c_str(), "wb");
177 for (auto& bucket
: mBuckets
)
179 Serialize(f
, bucket
);
184 void BucketManager::PrintReport(const std::string
& filename
)
192 FILE* f
= fopen(filename
.c_str(), "w");
195 for (const BUCKET_THREAD
& thread
: mThreads
)
197 PrintThread(f
, thread
);
200 mThreadMutex
.unlock();
206 void BucketManager_StartBucket(BucketManager
* pBucketMgr
, uint32_t id
)
208 pBucketMgr
->StartBucket(id
);
211 void BucketManager_StopBucket(BucketManager
* pBucketMgr
, uint32_t id
)
213 pBucketMgr
->StopBucket(id
);