Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1 | //===-- 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 Friedman | 8896697 | 2010-06-09 08:50:27 +0000 | [diff] [blame] | 13 | #include <algorithm> |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 14 | |
| 15 | #include "lldb/Core/Stream.h" |
| 16 | #include "lldb/Host/Mutex.h" |
Virgile Bello | b2f1fb2 | 2013-08-23 12:44:05 +0000 | [diff] [blame] | 17 | #include "lldb/Host/Host.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 18 | |
Eli Friedman | 8896697 | 2010-06-09 08:50:27 +0000 | [diff] [blame] | 19 | #include <stdio.h> |
| 20 | |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 21 | using namespace lldb_private; |
| 22 | |
| 23 | #define TIMER_INDENT_AMOUNT 2 |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 24 | |
| 25 | namespace |
| 26 | { |
| 27 | typedef std::map<const char*, uint64_t> TimerCategoryMap; |
| 28 | |
| 29 | struct TimerStack |
| 30 | { |
| 31 | TimerStack() : |
| 32 | m_depth(0) |
| 33 | {} |
| 34 | |
| 35 | uint32_t m_depth; |
| 36 | std::vector<Timer*> m_stack; |
| 37 | }; |
| 38 | } // end of anonymous namespace |
| 39 | |
Tamas Berghammer | 5ee6b7f | 2015-10-23 10:53:31 +0000 | [diff] [blame] | 40 | std::atomic<bool> Timer::g_quiet(true); |
| 41 | std::atomic<unsigned> Timer::g_display_depth(0); |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 42 | std::mutex Timer::g_file_mutex; |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 43 | |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 44 | |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 45 | static Mutex & |
| 46 | GetCategoryMutex() |
| 47 | { |
| 48 | static Mutex g_category_mutex(Mutex::eMutexTypeNormal); |
| 49 | return g_category_mutex; |
| 50 | } |
| 51 | |
Enrico Granata | 5548cb5 | 2013-01-28 23:47:25 +0000 | [diff] [blame] | 52 | static TimerCategoryMap & |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 53 | GetCategoryMap() |
| 54 | { |
Enrico Granata | 5548cb5 | 2013-01-28 23:47:25 +0000 | [diff] [blame] | 55 | static TimerCategoryMap g_category_map; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 56 | return g_category_map; |
| 57 | } |
| 58 | |
Pavel Labath | 061140c | 2016-02-01 13:29:41 +0000 | [diff] [blame^] | 59 | static void |
| 60 | ThreadSpecificCleanup(void *p) |
| 61 | { |
| 62 | delete static_cast<TimerStack *>(p); |
| 63 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 64 | |
| 65 | static TimerStack * |
| 66 | GetTimerStackForCurrentThread () |
| 67 | { |
Pavel Labath | 061140c | 2016-02-01 13:29:41 +0000 | [diff] [blame^] | 68 | static lldb::thread_key_t g_key = Host::ThreadLocalStorageCreate(ThreadSpecificCleanup); |
| 69 | |
Virgile Bello | b2f1fb2 | 2013-08-23 12:44:05 +0000 | [diff] [blame] | 70 | void *timer_stack = Host::ThreadLocalStorageGet(g_key); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 71 | if (timer_stack == NULL) |
| 72 | { |
Virgile Bello | b2f1fb2 | 2013-08-23 12:44:05 +0000 | [diff] [blame] | 73 | Host::ThreadLocalStorageSet(g_key, new TimerStack); |
| 74 | timer_stack = Host::ThreadLocalStorageGet(g_key); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 75 | } |
| 76 | return (TimerStack *)timer_stack; |
| 77 | } |
| 78 | |
| 79 | void |
Jim Ingham | f7f4f50 | 2010-11-04 23:19:21 +0000 | [diff] [blame] | 80 | Timer::SetQuiet (bool value) |
| 81 | { |
| 82 | g_quiet = value; |
| 83 | } |
| 84 | |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 85 | Timer::Timer (const char *category, const char *format, ...) : |
| 86 | m_category (category), |
| 87 | m_total_start (), |
| 88 | m_timer_start (), |
| 89 | m_total_ticks (0), |
| 90 | m_timer_ticks (0) |
| 91 | { |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 92 | TimerStack *stack = GetTimerStackForCurrentThread (); |
| 93 | if (!stack) |
| 94 | return; |
| 95 | |
| 96 | if (stack->m_depth++ < g_display_depth) |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 97 | { |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 98 | if (g_quiet == false) |
| 99 | { |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 100 | std::lock_guard<std::mutex> lock(g_file_mutex); |
| 101 | |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 102 | // Indent |
Pavel Labath | 061140c | 2016-02-01 13:29:41 +0000 | [diff] [blame^] | 103 | ::fprintf(stdout, "%*s", stack->m_depth * TIMER_INDENT_AMOUNT, ""); |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 104 | // Print formatted string |
| 105 | va_list args; |
| 106 | va_start (args, format); |
Pavel Labath | 061140c | 2016-02-01 13:29:41 +0000 | [diff] [blame^] | 107 | ::vfprintf(stdout, format, args); |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 108 | va_end (args); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 109 | |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 110 | // Newline |
Pavel Labath | 061140c | 2016-02-01 13:29:41 +0000 | [diff] [blame^] | 111 | ::fprintf(stdout, "\n"); |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 112 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 113 | TimeValue start_time(TimeValue::Now()); |
| 114 | m_total_start = start_time; |
| 115 | m_timer_start = start_time; |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 116 | |
| 117 | if (!stack->m_stack.empty()) |
| 118 | stack->m_stack.back()->ChildStarted (start_time); |
| 119 | stack->m_stack.push_back(this); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 120 | } |
| 121 | } |
| 122 | |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 123 | Timer::~Timer() |
| 124 | { |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 125 | TimerStack *stack = GetTimerStackForCurrentThread (); |
| 126 | if (!stack) |
| 127 | return; |
| 128 | |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 129 | if (m_total_start.IsValid()) |
| 130 | { |
| 131 | TimeValue stop_time = TimeValue::Now(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 132 | if (m_total_start.IsValid()) |
| 133 | { |
| 134 | m_total_ticks += (stop_time - m_total_start); |
| 135 | m_total_start.Clear(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 136 | } |
| 137 | if (m_timer_start.IsValid()) |
| 138 | { |
| 139 | m_timer_ticks += (stop_time - m_timer_start); |
| 140 | m_timer_start.Clear(); |
| 141 | } |
| 142 | |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 143 | assert (stack->m_stack.back() == this); |
| 144 | stack->m_stack.pop_back(); |
| 145 | if (stack->m_stack.empty() == false) |
| 146 | stack->m_stack.back()->ChildStopped(stop_time); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 147 | |
| 148 | const uint64_t total_nsec_uint = GetTotalElapsedNanoSeconds(); |
| 149 | const uint64_t timer_nsec_uint = GetTimerElapsedNanoSeconds(); |
| 150 | const double total_nsec = total_nsec_uint; |
| 151 | const double timer_nsec = timer_nsec_uint; |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 152 | |
| 153 | if (g_quiet == false) |
| 154 | { |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 155 | std::lock_guard<std::mutex> lock(g_file_mutex); |
Pavel Labath | 061140c | 2016-02-01 13:29:41 +0000 | [diff] [blame^] | 156 | ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n", (stack->m_depth - 1) * TIMER_INDENT_AMOUNT, "", |
| 157 | total_nsec / 1000000000.0, timer_nsec / 1000000000.0); |
Greg Clayton | 0996003 | 2010-09-10 18:31:35 +0000 | [diff] [blame] | 158 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 159 | |
| 160 | // Keep total results for each category so we can dump results. |
| 161 | Mutex::Locker locker (GetCategoryMutex()); |
Enrico Granata | 5548cb5 | 2013-01-28 23:47:25 +0000 | [diff] [blame] | 162 | TimerCategoryMap &category_map = GetCategoryMap(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 163 | category_map[m_category] += timer_nsec_uint; |
| 164 | } |
Tamas Berghammer | d779da9 | 2015-10-23 10:34:29 +0000 | [diff] [blame] | 165 | if (stack->m_depth > 0) |
| 166 | --stack->m_depth; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | uint64_t |
| 170 | Timer::GetTotalElapsedNanoSeconds() |
| 171 | { |
| 172 | uint64_t total_ticks = m_total_ticks; |
| 173 | |
| 174 | // If we are currently running, we need to add the current |
| 175 | // elapsed time of the running timer... |
| 176 | if (m_total_start.IsValid()) |
| 177 | total_ticks += (TimeValue::Now() - m_total_start); |
| 178 | |
| 179 | return total_ticks; |
| 180 | } |
| 181 | |
| 182 | uint64_t |
| 183 | Timer::GetTimerElapsedNanoSeconds() |
| 184 | { |
| 185 | uint64_t timer_ticks = m_timer_ticks; |
| 186 | |
| 187 | // If we are currently running, we need to add the current |
| 188 | // elapsed time of the running timer... |
| 189 | if (m_timer_start.IsValid()) |
| 190 | timer_ticks += (TimeValue::Now() - m_timer_start); |
| 191 | |
| 192 | return timer_ticks; |
| 193 | } |
| 194 | |
| 195 | void |
| 196 | Timer::ChildStarted (const TimeValue& start_time) |
| 197 | { |
| 198 | if (m_timer_start.IsValid()) |
| 199 | { |
| 200 | m_timer_ticks += (start_time - m_timer_start); |
| 201 | m_timer_start.Clear(); |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | void |
| 206 | Timer::ChildStopped (const TimeValue& stop_time) |
| 207 | { |
| 208 | if (!m_timer_start.IsValid()) |
| 209 | m_timer_start = stop_time; |
| 210 | } |
| 211 | |
| 212 | void |
| 213 | Timer::SetDisplayDepth (uint32_t depth) |
| 214 | { |
| 215 | g_display_depth = depth; |
| 216 | } |
| 217 | |
| 218 | |
| 219 | /* binary function predicate: |
| 220 | * - returns whether a person is less than another person |
| 221 | */ |
| 222 | static bool |
Enrico Granata | 5548cb5 | 2013-01-28 23:47:25 +0000 | [diff] [blame] | 223 | CategoryMapIteratorSortCriterion (const TimerCategoryMap::const_iterator& lhs, const TimerCategoryMap::const_iterator& rhs) |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 224 | { |
| 225 | return lhs->second > rhs->second; |
| 226 | } |
| 227 | |
| 228 | |
| 229 | void |
| 230 | Timer::ResetCategoryTimes () |
| 231 | { |
| 232 | Mutex::Locker locker (GetCategoryMutex()); |
Enrico Granata | 5548cb5 | 2013-01-28 23:47:25 +0000 | [diff] [blame] | 233 | TimerCategoryMap &category_map = GetCategoryMap(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 234 | category_map.clear(); |
| 235 | } |
| 236 | |
| 237 | void |
| 238 | Timer::DumpCategoryTimes (Stream *s) |
| 239 | { |
| 240 | Mutex::Locker locker (GetCategoryMutex()); |
Enrico Granata | 5548cb5 | 2013-01-28 23:47:25 +0000 | [diff] [blame] | 241 | TimerCategoryMap &category_map = GetCategoryMap(); |
| 242 | std::vector<TimerCategoryMap::const_iterator> sorted_iterators; |
| 243 | TimerCategoryMap::const_iterator pos, end = category_map.end(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 244 | for (pos = category_map.begin(); pos != end; ++pos) |
| 245 | { |
| 246 | sorted_iterators.push_back (pos); |
| 247 | } |
| 248 | std::sort (sorted_iterators.begin(), sorted_iterators.end(), CategoryMapIteratorSortCriterion); |
| 249 | |
| 250 | const size_t count = sorted_iterators.size(); |
| 251 | for (size_t i=0; i<count; ++i) |
| 252 | { |
| 253 | const double timer_nsec = sorted_iterators[i]->second; |
| 254 | s->Printf("%.9f sec for %s\n", timer_nsec / 1000000000.0, sorted_iterators[i]->first); |
| 255 | } |
Eli Friedman | 8896697 | 2010-06-09 08:50:27 +0000 | [diff] [blame] | 256 | } |