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