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
~BucketManager()43 BucketManager::~BucketManager()
44 {
45 }
46
RegisterThread(const std::string & name)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
RegisterBucket(const BUCKET_DESC & desc)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
PrintBucket(FILE * f,UINT level,uint64_t threadCycles,uint64_t parentCycles,const BUCKET & bucket)79 void 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
PrintThread(FILE * f,const BUCKET_THREAD & thread)133 void 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
PrintReport(const std::string & filename)156 void 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
StartCapture()176 void BucketManager::StartCapture()
177 {
178
179 printf("Capture Starting\n");
180
181 mCapturing = true;
182 }
183
BucketManager_StartBucket(BucketManager * pBucketMgr,uint32_t id)184 void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id)
185 {
186 pBucketMgr->StartBucket(id);
187 }
188
BucketManager_StopBucket(BucketManager * pBucketMgr,uint32_t id)189 void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id)
190 {
191 pBucketMgr->StopBucket(id);
192 }
193