1 //===-- Timer.cpp -----------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "lldb/Core/Timer.h"
15 #include "lldb/Core/Stream.h"
16 #include "lldb/Host/Mutex.h"
20 using namespace lldb_private;
22 #define TIMER_INDENT_AMOUNT 2
23 static bool g_quiet = true;
24 uint32_t Timer::g_depth = 0;
25 uint32_t Timer::g_display_depth = 0;
26 FILE * Timer::g_file = NULL;
27 typedef std::vector<Timer *> TimerStack;
28 typedef std::map<const char *, uint64_t> TimerCategoryMap;
29 static pthread_key_t g_key;
34 static Mutex g_category_mutex(Mutex::eMutexTypeNormal);
35 return g_category_mutex;
38 static TimerCategoryMap &
41 static TimerCategoryMap g_category_map;
42 return g_category_map;
47 GetTimerStackForCurrentThread ()
49 void *timer_stack = ::pthread_getspecific (g_key);
50 if (timer_stack == NULL)
52 ::pthread_setspecific (g_key, new TimerStack);
53 timer_stack = ::pthread_getspecific (g_key);
55 return (TimerStack *)timer_stack;
59 ThreadSpecificCleanup (void *p)
61 delete (TimerStack *)p;
65 Timer::SetQuiet (bool value)
73 Timer::g_file = stdout;
74 ::pthread_key_create (&g_key, ThreadSpecificCleanup);
78 Timer::Timer (const char *category, const char *format, ...) :
79 m_category (category),
85 if (g_depth++ < g_display_depth)
90 ::fprintf (g_file, "%*s", g_depth * TIMER_INDENT_AMOUNT, "");
91 // Print formatted string
93 va_start (args, format);
94 ::vfprintf (g_file, format, args);
98 ::fprintf (g_file, "\n");
100 TimeValue start_time(TimeValue::Now());
101 m_total_start = start_time;
102 m_timer_start = start_time;
103 TimerStack *stack = GetTimerStackForCurrentThread ();
106 if (stack->empty() == false)
107 stack->back()->ChildStarted (start_time);
108 stack->push_back(this);
116 if (m_total_start.IsValid())
118 TimeValue stop_time = TimeValue::Now();
119 if (m_total_start.IsValid())
121 m_total_ticks += (stop_time - m_total_start);
122 m_total_start.Clear();
124 if (m_timer_start.IsValid())
126 m_timer_ticks += (stop_time - m_timer_start);
127 m_timer_start.Clear();
130 TimerStack *stack = GetTimerStackForCurrentThread ();
133 assert (stack->back() == this);
135 if (stack->empty() == false)
136 stack->back()->ChildStopped(stop_time);
139 const uint64_t total_nsec_uint = GetTotalElapsedNanoSeconds();
140 const uint64_t timer_nsec_uint = GetTimerElapsedNanoSeconds();
141 const double total_nsec = total_nsec_uint;
142 const double timer_nsec = timer_nsec_uint;
144 if (g_quiet == false)
148 "%*s%.9f sec (%.9f sec)\n",
149 (g_depth - 1) *TIMER_INDENT_AMOUNT, "",
150 total_nsec / 1000000000.0,
151 timer_nsec / 1000000000.0);
154 // Keep total results for each category so we can dump results.
155 Mutex::Locker locker (GetCategoryMutex());
156 TimerCategoryMap &category_map = GetCategoryMap();
157 category_map[m_category] += timer_nsec_uint;
164 Timer::GetTotalElapsedNanoSeconds()
166 uint64_t total_ticks = m_total_ticks;
168 // If we are currently running, we need to add the current
169 // elapsed time of the running timer...
170 if (m_total_start.IsValid())
171 total_ticks += (TimeValue::Now() - m_total_start);
177 Timer::GetTimerElapsedNanoSeconds()
179 uint64_t timer_ticks = m_timer_ticks;
181 // If we are currently running, we need to add the current
182 // elapsed time of the running timer...
183 if (m_timer_start.IsValid())
184 timer_ticks += (TimeValue::Now() - m_timer_start);
190 Timer::ChildStarted (const TimeValue& start_time)
192 if (m_timer_start.IsValid())
194 m_timer_ticks += (start_time - m_timer_start);
195 m_timer_start.Clear();
200 Timer::ChildStopped (const TimeValue& stop_time)
202 if (!m_timer_start.IsValid())
203 m_timer_start = stop_time;
207 Timer::SetDisplayDepth (uint32_t depth)
209 g_display_depth = depth;
213 /* binary function predicate:
214 * - returns whether a person is less than another person
217 CategoryMapIteratorSortCriterion (const TimerCategoryMap::const_iterator& lhs, const TimerCategoryMap::const_iterator& rhs)
219 return lhs->second > rhs->second;
224 Timer::ResetCategoryTimes ()
226 Mutex::Locker locker (GetCategoryMutex());
227 TimerCategoryMap &category_map = GetCategoryMap();
228 category_map.clear();
232 Timer::DumpCategoryTimes (Stream *s)
234 Mutex::Locker locker (GetCategoryMutex());
235 TimerCategoryMap &category_map = GetCategoryMap();
236 std::vector<TimerCategoryMap::const_iterator> sorted_iterators;
237 TimerCategoryMap::const_iterator pos, end = category_map.end();
238 for (pos = category_map.begin(); pos != end; ++pos)
240 sorted_iterators.push_back (pos);
242 std::sort (sorted_iterators.begin(), sorted_iterators.end(), CategoryMapIteratorSortCriterion);
244 const size_t count = sorted_iterators.size();
245 for (size_t i=0; i<count; ++i)
247 const double timer_nsec = sorted_iterators[i]->second;
248 s->Printf("%.9f sec for %s\n", timer_nsec / 1000000000.0, sorted_iterators[i]->first);