• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket)
80 {
81     const char *arrows[] = {
82         "",
83         "|-> ",
84         "    |-> ",
85         "        |-> ",
86         "            |-> ",
87         "                |-> ",
88         "                    |-> ",
89         "                        |-> ",
90         "                            |-> ",
91     };
92 
93     // compute percent of total cycles used by this bucket
94     float percentTotal = (float)((double)bucket.elapsed / (double)threadCycles * 100.0);
95 
96     // compute percent of parent cycles used by this bucket
97     float percentParent = (float)((double)bucket.elapsed / (double)parentCycles * 100.0);
98 
99     // compute average cycle count per invocation
100     uint64_t CPE = bucket.elapsed / bucket.count;
101 
102     BUCKET_DESC &desc = mBuckets[bucket.id];
103 
104     // construct hierarchy visualization
105     char hier[80];
106     strcpy(hier, arrows[level]);
107     strcat(hier, desc.name.c_str());
108 
109     // print out
110     fprintf(f, "%6.2f %6.2f %-10" PRIu64 " %-10" PRIu64 " %-10u %-10lu %-10u %s\n",
111         percentTotal,
112         percentParent,
113         bucket.elapsed,
114         CPE,
115         bucket.count,
116         (unsigned long)0,
117         (uint32_t)0,
118         hier
119     );
120 
121     // dump all children of this bucket
122     for (const BUCKET& child : bucket.children)
123     {
124         if (child.count)
125         {
126             PrintBucket(f, level + 1, threadCycles, bucket.elapsed, child);
127         }
128     }
129 }
130 
PrintThread(FILE * f,const BUCKET_THREAD & thread)131 void BucketManager::PrintThread(FILE* f, const BUCKET_THREAD& thread)
132 {
133     // print header
134     fprintf(f, "\nThread %u (%s)\n", thread.id, thread.name.c_str());
135     fprintf(f, " %%Tot   %%Par  Cycles     CPE        NumEvent   CPE2       NumEvent2  Bucket\n");
136 
137     // compute thread level total cycle counts across all buckets from root
138     const BUCKET& root = thread.root;
139     uint64_t totalCycles = 0;
140     for (const BUCKET& child : root.children)
141     {
142         totalCycles += child.elapsed;
143     }
144 
145     for (const BUCKET& child : root.children)
146     {
147         if (child.count)
148         {
149             PrintBucket(f, 0, totalCycles, totalCycles, child);
150         }
151     }
152 }
153 
PrintReport(const std::string & filename)154 void BucketManager::PrintReport(const std::string& filename)
155 {
156     {
157         FILE* f = fopen(filename.c_str(), "w");
158 
159         mThreadMutex.lock();
160         for (const BUCKET_THREAD& thread : mThreads)
161         {
162             PrintThread(f, thread);
163             fprintf(f, "\n");
164         }
165 
166         mThreadMutex.unlock();
167 
168         fclose(f);
169     }
170 }
171 
172 
StartCapture()173 void BucketManager::StartCapture()
174 {
175 
176     printf("Capture Starting\n");
177 
178     mCapturing = true;
179 }
180 
BucketManager_StartBucket(BucketManager * pBucketMgr,uint32_t id)181 void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id)
182 {
183     pBucketMgr->StartBucket(id);
184 }
185 
BucketManager_StopBucket(BucketManager * pBucketMgr,uint32_t id)186 void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id)
187 {
188     pBucketMgr->StopBucket(id);
189 }
190