blob: a5420c160455555940ddaa6fd2b7ae612bebab5e [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Timer.cpp -----------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "lldb/Core/Timer.h"
10
11#include <map>
12#include <vector>
Eli Friedman88966972010-06-09 08:50:27 +000013#include <algorithm>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014
15#include "lldb/Core/Stream.h"
16#include "lldb/Host/Mutex.h"
17
Eli Friedman88966972010-06-09 08:50:27 +000018#include <stdio.h>
19
Chris Lattner30fdc8d2010-06-08 16:52:24 +000020using namespace lldb_private;
21
22#define TIMER_INDENT_AMOUNT 2
Greg Clayton09960032010-09-10 18:31:35 +000023static bool g_quiet = true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000024uint32_t Timer::g_depth = 0;
25uint32_t Timer::g_display_depth = 0;
26FILE * Timer::g_file = NULL;
27typedef std::vector<Timer *> TimerStack;
28typedef std::map<const char *, uint64_t> CategoryMap;
29static pthread_key_t g_key;
30
31
32static Mutex &
33GetCategoryMutex()
34{
35 static Mutex g_category_mutex(Mutex::eMutexTypeNormal);
36 return g_category_mutex;
37}
38
39static CategoryMap &
40GetCategoryMap()
41{
42 static CategoryMap g_category_map;
43 return g_category_map;
44}
45
46
47static TimerStack *
48GetTimerStackForCurrentThread ()
49{
50 void *timer_stack = ::pthread_getspecific (g_key);
51 if (timer_stack == NULL)
52 {
53 ::pthread_setspecific (g_key, new TimerStack);
54 timer_stack = ::pthread_getspecific (g_key);
55 }
56 return (TimerStack *)timer_stack;
57}
58
59void
60ThreadSpecificCleanup (void *p)
61{
62 delete (TimerStack *)p;
63}
64
65void
66Timer::Initialize ()
67{
68 Timer::g_file = stdout;
69 ::pthread_key_create (&g_key, ThreadSpecificCleanup);
70
71}
72
73Timer::Timer (const char *category, const char *format, ...) :
74 m_category (category),
75 m_total_start (),
76 m_timer_start (),
77 m_total_ticks (0),
78 m_timer_ticks (0)
79{
80 if (g_depth++ < g_display_depth)
81 {
Greg Clayton09960032010-09-10 18:31:35 +000082 if (g_quiet == false)
83 {
84 // Indent
85 ::fprintf (g_file, "%*s", g_depth * TIMER_INDENT_AMOUNT, "");
86 // Print formatted string
87 va_list args;
88 va_start (args, format);
89 ::vfprintf (g_file, format, args);
90 va_end (args);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000091
Greg Clayton09960032010-09-10 18:31:35 +000092 // Newline
93 ::fprintf (g_file, "\n");
94 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000095 TimeValue start_time(TimeValue::Now());
96 m_total_start = start_time;
97 m_timer_start = start_time;
98 TimerStack *stack = GetTimerStackForCurrentThread ();
99 if (stack)
100 {
101 if (stack->empty() == false)
102 stack->back()->ChildStarted (start_time);
103 stack->push_back(this);
104 }
105 }
106}
107
108
109Timer::~Timer()
110{
111 if (m_total_start.IsValid())
112 {
113 TimeValue stop_time = TimeValue::Now();
114 bool notify = false;
115 if (m_total_start.IsValid())
116 {
117 m_total_ticks += (stop_time - m_total_start);
118 m_total_start.Clear();
119 notify = true;
120 }
121 if (m_timer_start.IsValid())
122 {
123 m_timer_ticks += (stop_time - m_timer_start);
124 m_timer_start.Clear();
125 }
126
127 TimerStack *stack = GetTimerStackForCurrentThread ();
128 if (stack)
129 {
130 assert (stack->back() == this);
131 stack->pop_back();
132 if (stack->empty() == false)
133 stack->back()->ChildStopped(stop_time);
134 }
135
136 const uint64_t total_nsec_uint = GetTotalElapsedNanoSeconds();
137 const uint64_t timer_nsec_uint = GetTimerElapsedNanoSeconds();
138 const double total_nsec = total_nsec_uint;
139 const double timer_nsec = timer_nsec_uint;
Greg Clayton09960032010-09-10 18:31:35 +0000140
141 if (g_quiet == false)
142 {
143
144 ::fprintf (g_file,
145 "%*s%.9f sec (%.9f sec)\n",
146 (g_depth - 1) *TIMER_INDENT_AMOUNT, "",
147 total_nsec / 1000000000.0,
148 timer_nsec / 1000000000.0);
149 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000150
151 // Keep total results for each category so we can dump results.
152 Mutex::Locker locker (GetCategoryMutex());
153 CategoryMap &category_map = GetCategoryMap();
154 category_map[m_category] += timer_nsec_uint;
155 }
156 if (g_depth > 0)
157 --g_depth;
158}
159
160uint64_t
161Timer::GetTotalElapsedNanoSeconds()
162{
163 uint64_t total_ticks = m_total_ticks;
164
165 // If we are currently running, we need to add the current
166 // elapsed time of the running timer...
167 if (m_total_start.IsValid())
168 total_ticks += (TimeValue::Now() - m_total_start);
169
170 return total_ticks;
171}
172
173uint64_t
174Timer::GetTimerElapsedNanoSeconds()
175{
176 uint64_t timer_ticks = m_timer_ticks;
177
178 // If we are currently running, we need to add the current
179 // elapsed time of the running timer...
180 if (m_timer_start.IsValid())
181 timer_ticks += (TimeValue::Now() - m_timer_start);
182
183 return timer_ticks;
184}
185
186void
187Timer::ChildStarted (const TimeValue& start_time)
188{
189 if (m_timer_start.IsValid())
190 {
191 m_timer_ticks += (start_time - m_timer_start);
192 m_timer_start.Clear();
193 }
194}
195
196void
197Timer::ChildStopped (const TimeValue& stop_time)
198{
199 if (!m_timer_start.IsValid())
200 m_timer_start = stop_time;
201}
202
203void
204Timer::SetDisplayDepth (uint32_t depth)
205{
206 g_display_depth = depth;
207}
208
209
210/* binary function predicate:
211 * - returns whether a person is less than another person
212 */
213static bool
214CategoryMapIteratorSortCriterion (const CategoryMap::const_iterator& lhs, const CategoryMap::const_iterator& rhs)
215{
216 return lhs->second > rhs->second;
217}
218
219
220void
221Timer::ResetCategoryTimes ()
222{
223 Mutex::Locker locker (GetCategoryMutex());
224 CategoryMap &category_map = GetCategoryMap();
225 category_map.clear();
226}
227
228void
229Timer::DumpCategoryTimes (Stream *s)
230{
231 Mutex::Locker locker (GetCategoryMutex());
232 CategoryMap &category_map = GetCategoryMap();
233 std::vector<CategoryMap::const_iterator> sorted_iterators;
234 CategoryMap::const_iterator pos, end = category_map.end();
235 for (pos = category_map.begin(); pos != end; ++pos)
236 {
237 sorted_iterators.push_back (pos);
238 }
239 std::sort (sorted_iterators.begin(), sorted_iterators.end(), CategoryMapIteratorSortCriterion);
240
241 const size_t count = sorted_iterators.size();
242 for (size_t i=0; i<count; ++i)
243 {
244 const double timer_nsec = sorted_iterators[i]->second;
245 s->Printf("%.9f sec for %s\n", timer_nsec / 1000000000.0, sorted_iterators[i]->first);
246 }
Eli Friedman88966972010-06-09 08:50:27 +0000247}