1 //===-- Timer.cpp -----------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #include "lldb/Utility/Timer.h" 9 #include "lldb/Utility/Stream.h" 10 11 #include <algorithm> 12 #include <map> 13 #include <mutex> 14 #include <utility> 15 #include <vector> 16 17 #include <assert.h> 18 #include <stdarg.h> 19 #include <stdio.h> 20 21 using namespace lldb_private; 22 23 #define TIMER_INDENT_AMOUNT 2 24 25 namespace { 26 typedef std::vector<Timer *> TimerStack; 27 static std::atomic<Timer::Category *> g_categories; 28 } // end of anonymous namespace 29 30 std::atomic<bool> Timer::g_quiet(true); 31 std::atomic<unsigned> Timer::g_display_depth(0); 32 static std::mutex &GetFileMutex() { 33 static std::mutex *g_file_mutex_ptr = new std::mutex(); 34 return *g_file_mutex_ptr; 35 } 36 37 static TimerStack &GetTimerStackForCurrentThread() { 38 static thread_local TimerStack g_stack; 39 return g_stack; 40 } 41 42 Timer::Category::Category(const char *cat) : m_name(cat) { 43 m_nanos.store(0, std::memory_order_release); 44 Category *expected = g_categories; 45 do { 46 m_next = expected; 47 } while (!g_categories.compare_exchange_weak(expected, this)); 48 } 49 50 void Timer::SetQuiet(bool value) { g_quiet = value; } 51 52 Timer::Timer(Timer::Category &category, const char *format, ...) 53 : m_category(category), m_total_start(std::chrono::steady_clock::now()) { 54 TimerStack &stack = GetTimerStackForCurrentThread(); 55 56 stack.push_back(this); 57 if (g_quiet && stack.size() <= g_display_depth) { 58 std::lock_guard<std::mutex> lock(GetFileMutex()); 59 60 // Indent 61 ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, ""); 62 // Print formatted string 63 va_list args; 64 va_start(args, format); 65 ::vfprintf(stdout, format, args); 66 va_end(args); 67 68 // Newline 69 ::fprintf(stdout, "\n"); 70 } 71 } 72 73 Timer::~Timer() { 74 using namespace std::chrono; 75 76 auto stop_time = steady_clock::now(); 77 auto total_dur = stop_time - m_total_start; 78 auto timer_dur = total_dur - m_child_duration; 79 80 TimerStack &stack = GetTimerStackForCurrentThread(); 81 if (g_quiet && stack.size() <= g_display_depth) { 82 std::lock_guard<std::mutex> lock(GetFileMutex()); 83 ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n", 84 int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "", 85 duration<double>(total_dur).count(), 86 duration<double>(timer_dur).count()); 87 } 88 89 assert(stack.back() == this); 90 stack.pop_back(); 91 if (!stack.empty()) 92 stack.back()->ChildDuration(total_dur); 93 94 // Keep total results for each category so we can dump results. 95 m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count(); 96 } 97 98 void Timer::SetDisplayDepth(uint32_t depth) { g_display_depth = depth; } 99 100 /* binary function predicate: 101 * - returns whether a person is less than another person 102 */ 103 104 typedef std::pair<const char *, uint64_t> TimerEntry; 105 106 static bool CategoryMapIteratorSortCriterion(const TimerEntry &lhs, 107 const TimerEntry &rhs) { 108 return lhs.second > rhs.second; 109 } 110 111 void Timer::ResetCategoryTimes() { 112 for (Category *i = g_categories; i; i = i->m_next) 113 i->m_nanos.store(0, std::memory_order_release); 114 } 115 116 void Timer::DumpCategoryTimes(Stream *s) { 117 std::vector<TimerEntry> sorted; 118 for (Category *i = g_categories; i; i = i->m_next) { 119 uint64_t nanos = i->m_nanos.load(std::memory_order_acquire); 120 if (nanos) 121 sorted.push_back(std::make_pair(i->m_name, nanos)); 122 } 123 if (sorted.empty()) 124 return; // Later code will break without any elements. 125 126 // Sort by time 127 llvm::sort(sorted.begin(), sorted.end(), CategoryMapIteratorSortCriterion); 128 129 for (const auto &timer : sorted) 130 s->Printf("%.9f sec for %s\n", timer.second / 1000000000., timer.first); 131 } 132