138d0632eSPavel Labath //===-- Timer.cpp -----------------------------------------------*- C++ -*-===// 238d0632eSPavel Labath // 338d0632eSPavel Labath // The LLVM Compiler Infrastructure 438d0632eSPavel Labath // 538d0632eSPavel Labath // This file is distributed under the University of Illinois Open Source 638d0632eSPavel Labath // License. See LICENSE.TXT for details. 738d0632eSPavel Labath // 838d0632eSPavel Labath //===----------------------------------------------------------------------===// 938d0632eSPavel Labath #include "lldb/Utility/Timer.h" 1038d0632eSPavel Labath #include "lldb/Utility/Stream.h" 1138d0632eSPavel Labath 1238d0632eSPavel Labath #include <algorithm> 1338d0632eSPavel Labath #include <map> 1438d0632eSPavel Labath #include <mutex> 15672d2c12SJonas Devlieghere #include <utility> 1638d0632eSPavel Labath #include <vector> 1738d0632eSPavel Labath 18672d2c12SJonas Devlieghere #include <assert.h> 19672d2c12SJonas Devlieghere #include <stdarg.h> 2038d0632eSPavel Labath #include <stdio.h> 2138d0632eSPavel Labath 2238d0632eSPavel Labath using namespace lldb_private; 2338d0632eSPavel Labath 2438d0632eSPavel Labath #define TIMER_INDENT_AMOUNT 2 2538d0632eSPavel Labath 2638d0632eSPavel Labath namespace { 2738d0632eSPavel Labath typedef std::vector<Timer *> TimerStack; 2838d0632eSPavel Labath static std::atomic<Timer::Category *> g_categories; 2938d0632eSPavel Labath } // end of anonymous namespace 3038d0632eSPavel Labath 3138d0632eSPavel Labath std::atomic<bool> Timer::g_quiet(true); 3238d0632eSPavel Labath std::atomic<unsigned> Timer::g_display_depth(0); 3338d0632eSPavel Labath static std::mutex &GetFileMutex() { 3438d0632eSPavel Labath static std::mutex *g_file_mutex_ptr = new std::mutex(); 3538d0632eSPavel Labath return *g_file_mutex_ptr; 3638d0632eSPavel Labath } 3738d0632eSPavel Labath 3838d0632eSPavel Labath static TimerStack &GetTimerStackForCurrentThread() { 3938d0632eSPavel Labath static thread_local TimerStack g_stack; 4038d0632eSPavel Labath return g_stack; 4138d0632eSPavel Labath } 4238d0632eSPavel Labath 4338d0632eSPavel Labath Timer::Category::Category(const char *cat) : m_name(cat) { 4438d0632eSPavel Labath m_nanos.store(0, std::memory_order_release); 4538d0632eSPavel Labath Category *expected = g_categories; 4638d0632eSPavel Labath do { 4738d0632eSPavel Labath m_next = expected; 4838d0632eSPavel Labath } while (!g_categories.compare_exchange_weak(expected, this)); 4938d0632eSPavel Labath } 5038d0632eSPavel Labath 5138d0632eSPavel Labath void Timer::SetQuiet(bool value) { g_quiet = value; } 5238d0632eSPavel Labath 5338d0632eSPavel Labath Timer::Timer(Timer::Category &category, const char *format, ...) 5438d0632eSPavel Labath : m_category(category), m_total_start(std::chrono::steady_clock::now()) { 5538d0632eSPavel Labath TimerStack &stack = GetTimerStackForCurrentThread(); 5638d0632eSPavel Labath 5738d0632eSPavel Labath stack.push_back(this); 5838d0632eSPavel Labath if (g_quiet && stack.size() <= g_display_depth) { 5938d0632eSPavel Labath std::lock_guard<std::mutex> lock(GetFileMutex()); 6038d0632eSPavel Labath 6138d0632eSPavel Labath // Indent 6238d0632eSPavel Labath ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, ""); 6338d0632eSPavel Labath // Print formatted string 6438d0632eSPavel Labath va_list args; 6538d0632eSPavel Labath va_start(args, format); 6638d0632eSPavel Labath ::vfprintf(stdout, format, args); 6738d0632eSPavel Labath va_end(args); 6838d0632eSPavel Labath 6938d0632eSPavel Labath // Newline 7038d0632eSPavel Labath ::fprintf(stdout, "\n"); 7138d0632eSPavel Labath } 7238d0632eSPavel Labath } 7338d0632eSPavel Labath 7438d0632eSPavel Labath Timer::~Timer() { 7538d0632eSPavel Labath using namespace std::chrono; 7638d0632eSPavel Labath 7738d0632eSPavel Labath auto stop_time = steady_clock::now(); 7838d0632eSPavel Labath auto total_dur = stop_time - m_total_start; 7938d0632eSPavel Labath auto timer_dur = total_dur - m_child_duration; 8038d0632eSPavel Labath 8138d0632eSPavel Labath TimerStack &stack = GetTimerStackForCurrentThread(); 8238d0632eSPavel Labath if (g_quiet && stack.size() <= g_display_depth) { 8338d0632eSPavel Labath std::lock_guard<std::mutex> lock(GetFileMutex()); 8438d0632eSPavel Labath ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n", 8538d0632eSPavel Labath int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "", 8638d0632eSPavel Labath duration<double>(total_dur).count(), 8738d0632eSPavel Labath duration<double>(timer_dur).count()); 8838d0632eSPavel Labath } 8938d0632eSPavel Labath 9038d0632eSPavel Labath assert(stack.back() == this); 9138d0632eSPavel Labath stack.pop_back(); 9238d0632eSPavel Labath if (!stack.empty()) 9338d0632eSPavel Labath stack.back()->ChildDuration(total_dur); 9438d0632eSPavel Labath 9538d0632eSPavel Labath // Keep total results for each category so we can dump results. 9638d0632eSPavel Labath m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count(); 9738d0632eSPavel Labath } 9838d0632eSPavel Labath 9938d0632eSPavel Labath void Timer::SetDisplayDepth(uint32_t depth) { g_display_depth = depth; } 10038d0632eSPavel Labath 10138d0632eSPavel Labath /* binary function predicate: 10238d0632eSPavel Labath * - returns whether a person is less than another person 10338d0632eSPavel Labath */ 10438d0632eSPavel Labath 10538d0632eSPavel Labath typedef std::pair<const char *, uint64_t> TimerEntry; 10638d0632eSPavel Labath 10738d0632eSPavel Labath static bool CategoryMapIteratorSortCriterion(const TimerEntry &lhs, 10838d0632eSPavel Labath const TimerEntry &rhs) { 10938d0632eSPavel Labath return lhs.second > rhs.second; 11038d0632eSPavel Labath } 11138d0632eSPavel Labath 11238d0632eSPavel Labath void Timer::ResetCategoryTimes() { 11338d0632eSPavel Labath for (Category *i = g_categories; i; i = i->m_next) 11438d0632eSPavel Labath i->m_nanos.store(0, std::memory_order_release); 11538d0632eSPavel Labath } 11638d0632eSPavel Labath 11738d0632eSPavel Labath void Timer::DumpCategoryTimes(Stream *s) { 11838d0632eSPavel Labath std::vector<TimerEntry> sorted; 11938d0632eSPavel Labath for (Category *i = g_categories; i; i = i->m_next) { 12038d0632eSPavel Labath uint64_t nanos = i->m_nanos.load(std::memory_order_acquire); 12138d0632eSPavel Labath if (nanos) 12238d0632eSPavel Labath sorted.push_back(std::make_pair(i->m_name, nanos)); 12338d0632eSPavel Labath } 12438d0632eSPavel Labath if (sorted.empty()) 12538d0632eSPavel Labath return; // Later code will break without any elements. 12638d0632eSPavel Labath 12738d0632eSPavel Labath // Sort by time 128*9bbba276SJonas Devlieghere llvm::sort(sorted.begin(), sorted.end(), CategoryMapIteratorSortCriterion); 12938d0632eSPavel Labath 13038d0632eSPavel Labath for (const auto &timer : sorted) 13138d0632eSPavel Labath s->Printf("%.9f sec for %s\n", timer.second / 1000000000., timer.first); 13238d0632eSPavel Labath } 133