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