xref: /freebsd-src/contrib/llvm-project/llvm/lib/Support/TimeProfiler.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- TimeProfiler.cpp - Hierarchical Time Profiler ---------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements hierarchical time profiler.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/Support/TimeProfiler.h"
14*0fca6ea1SDimitry Andric #include "llvm/ADT/STLExtras.h"
1504eeddc0SDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
170b57cec5SDimitry Andric #include "llvm/Support/JSON.h"
18480093f4SDimitry Andric #include "llvm/Support/Path.h"
195ffd83dbSDimitry Andric #include "llvm/Support/Process.h"
205ffd83dbSDimitry Andric #include "llvm/Support/Threading.h"
215ffd83dbSDimitry Andric #include <algorithm>
220b57cec5SDimitry Andric #include <cassert>
230b57cec5SDimitry Andric #include <chrono>
24*0fca6ea1SDimitry Andric #include <memory>
255ffd83dbSDimitry Andric #include <mutex>
260b57cec5SDimitry Andric #include <string>
270b57cec5SDimitry Andric #include <vector>
280b57cec5SDimitry Andric 
295ffd83dbSDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
31bdd1243dSDimitry Andric namespace {
32bdd1243dSDimitry Andric 
33bdd1243dSDimitry Andric using std::chrono::duration;
34bdd1243dSDimitry Andric using std::chrono::duration_cast;
35bdd1243dSDimitry Andric using std::chrono::microseconds;
36bdd1243dSDimitry Andric using std::chrono::steady_clock;
37bdd1243dSDimitry Andric using std::chrono::system_clock;
38bdd1243dSDimitry Andric using std::chrono::time_point;
39bdd1243dSDimitry Andric using std::chrono::time_point_cast;
40bdd1243dSDimitry Andric 
41bdd1243dSDimitry Andric struct TimeTraceProfilerInstances {
42bdd1243dSDimitry Andric   std::mutex Lock;
43bdd1243dSDimitry Andric   std::vector<TimeTraceProfiler *> List;
44bdd1243dSDimitry Andric };
45bdd1243dSDimitry Andric 
46bdd1243dSDimitry Andric TimeTraceProfilerInstances &getTimeTraceProfilerInstances() {
47bdd1243dSDimitry Andric   static TimeTraceProfilerInstances Instances;
48bdd1243dSDimitry Andric   return Instances;
49bdd1243dSDimitry Andric }
50bdd1243dSDimitry Andric 
51bdd1243dSDimitry Andric } // anonymous namespace
52bdd1243dSDimitry Andric 
535ffd83dbSDimitry Andric // Per Thread instance
545ffd83dbSDimitry Andric static LLVM_THREAD_LOCAL TimeTraceProfiler *TimeTraceProfilerInstance = nullptr;
550b57cec5SDimitry Andric 
565ffd83dbSDimitry Andric TimeTraceProfiler *llvm::getTimeTraceProfilerInstance() {
575ffd83dbSDimitry Andric   return TimeTraceProfilerInstance;
585ffd83dbSDimitry Andric }
590b57cec5SDimitry Andric 
605ffd83dbSDimitry Andric namespace {
61bdd1243dSDimitry Andric 
62bdd1243dSDimitry Andric using ClockType = steady_clock;
63bdd1243dSDimitry Andric using TimePointType = time_point<ClockType>;
64bdd1243dSDimitry Andric using DurationType = duration<ClockType::rep, ClockType::period>;
65bdd1243dSDimitry Andric using CountAndDurationType = std::pair<size_t, DurationType>;
66bdd1243dSDimitry Andric using NameAndCountAndDurationType =
67bdd1243dSDimitry Andric     std::pair<std::string, CountAndDurationType>;
68bdd1243dSDimitry Andric 
69*0fca6ea1SDimitry Andric } // anonymous namespace
70*0fca6ea1SDimitry Andric 
71bdd1243dSDimitry Andric /// Represents an open or completed time section entry to be captured.
72*0fca6ea1SDimitry Andric struct llvm::TimeTraceProfilerEntry {
73480093f4SDimitry Andric   const TimePointType Start;
748bcb0991SDimitry Andric   TimePointType End;
75480093f4SDimitry Andric   const std::string Name;
76*0fca6ea1SDimitry Andric   TimeTraceMetadata Metadata;
77*0fca6ea1SDimitry Andric 
78*0fca6ea1SDimitry Andric   const bool AsyncEvent = false;
79*0fca6ea1SDimitry Andric   TimeTraceProfilerEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
80*0fca6ea1SDimitry Andric                          std::string &&Dt, bool Ae)
81*0fca6ea1SDimitry Andric       : Start(std::move(S)), End(std::move(E)), Name(std::move(N)), Metadata(),
82*0fca6ea1SDimitry Andric         AsyncEvent(Ae) {
83*0fca6ea1SDimitry Andric     Metadata.Detail = std::move(Dt);
84*0fca6ea1SDimitry Andric   }
850b57cec5SDimitry Andric 
86bdd1243dSDimitry Andric   TimeTraceProfilerEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
87*0fca6ea1SDimitry Andric                          TimeTraceMetadata &&Mt, bool Ae)
888bcb0991SDimitry Andric       : Start(std::move(S)), End(std::move(E)), Name(std::move(N)),
89*0fca6ea1SDimitry Andric         Metadata(std::move(Mt)), AsyncEvent(Ae) {}
908bcb0991SDimitry Andric 
918bcb0991SDimitry Andric   // Calculate timings for FlameGraph. Cast time points to microsecond precision
92bdd1243dSDimitry Andric   // rather than casting duration. This avoids truncation issues causing inner
938bcb0991SDimitry Andric   // scopes overruning outer scopes.
94bdd1243dSDimitry Andric   ClockType::rep getFlameGraphStartUs(TimePointType StartTime) const {
958bcb0991SDimitry Andric     return (time_point_cast<microseconds>(Start) -
968bcb0991SDimitry Andric             time_point_cast<microseconds>(StartTime))
978bcb0991SDimitry Andric         .count();
988bcb0991SDimitry Andric   }
998bcb0991SDimitry Andric 
100bdd1243dSDimitry Andric   ClockType::rep getFlameGraphDurUs() const {
1018bcb0991SDimitry Andric     return (time_point_cast<microseconds>(End) -
1028bcb0991SDimitry Andric             time_point_cast<microseconds>(Start))
1038bcb0991SDimitry Andric         .count();
1048bcb0991SDimitry Andric   }
1050b57cec5SDimitry Andric };
106bdd1243dSDimitry Andric 
1075ffd83dbSDimitry Andric struct llvm::TimeTraceProfiler {
108*0fca6ea1SDimitry Andric   TimeTraceProfiler(unsigned TimeTraceGranularity = 0, StringRef ProcName = "",
109*0fca6ea1SDimitry Andric                     bool TimeTraceVerbose = false)
110bdd1243dSDimitry Andric       : BeginningOfTime(system_clock::now()), StartTime(ClockType::now()),
1115ffd83dbSDimitry Andric         ProcName(ProcName), Pid(sys::Process::getProcessId()),
112*0fca6ea1SDimitry Andric         Tid(llvm::get_threadid()), TimeTraceGranularity(TimeTraceGranularity),
113*0fca6ea1SDimitry Andric         TimeTraceVerbose(TimeTraceVerbose) {
1145ffd83dbSDimitry Andric     llvm::get_thread_name(ThreadName);
1155ffd83dbSDimitry Andric   }
1160b57cec5SDimitry Andric 
117*0fca6ea1SDimitry Andric   TimeTraceProfilerEntry *begin(std::string Name,
118*0fca6ea1SDimitry Andric                                 llvm::function_ref<std::string()> Detail,
119*0fca6ea1SDimitry Andric                                 bool AsyncEvent = false) {
120*0fca6ea1SDimitry Andric     Stack.emplace_back(std::make_unique<TimeTraceProfilerEntry>(
121*0fca6ea1SDimitry Andric         ClockType::now(), TimePointType(), std::move(Name), Detail(),
122*0fca6ea1SDimitry Andric         AsyncEvent));
123*0fca6ea1SDimitry Andric     return Stack.back().get();
124*0fca6ea1SDimitry Andric   }
125*0fca6ea1SDimitry Andric 
126*0fca6ea1SDimitry Andric   TimeTraceProfilerEntry *
127*0fca6ea1SDimitry Andric   begin(std::string Name, llvm::function_ref<TimeTraceMetadata()> Metadata,
128*0fca6ea1SDimitry Andric         bool AsyncEvent = false) {
129*0fca6ea1SDimitry Andric     Stack.emplace_back(std::make_unique<TimeTraceProfilerEntry>(
130*0fca6ea1SDimitry Andric         ClockType::now(), TimePointType(), std::move(Name), Metadata(),
131*0fca6ea1SDimitry Andric         AsyncEvent));
132*0fca6ea1SDimitry Andric     return Stack.back().get();
1330b57cec5SDimitry Andric   }
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   void end() {
1360b57cec5SDimitry Andric     assert(!Stack.empty() && "Must call begin() first");
137*0fca6ea1SDimitry Andric     end(*Stack.back());
138*0fca6ea1SDimitry Andric   }
1390b57cec5SDimitry Andric 
140*0fca6ea1SDimitry Andric   void end(TimeTraceProfilerEntry &E) {
141*0fca6ea1SDimitry Andric     assert(!Stack.empty() && "Must call begin() first");
142*0fca6ea1SDimitry Andric     E.End = ClockType::now();
1438bcb0991SDimitry Andric 
1448bcb0991SDimitry Andric     // Calculate duration at full precision for overall counts.
1458bcb0991SDimitry Andric     DurationType Duration = E.End - E.Start;
1468bcb0991SDimitry Andric 
1478bcb0991SDimitry Andric     // Only include sections longer or equal to TimeTraceGranularity msec.
1488bcb0991SDimitry Andric     if (duration_cast<microseconds>(Duration).count() >= TimeTraceGranularity)
1490b57cec5SDimitry Andric       Entries.emplace_back(E);
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric     // Track total time taken by each "name", but only the topmost levels of
1520b57cec5SDimitry Andric     // them; e.g. if there's a template instantiation that instantiates other
1530b57cec5SDimitry Andric     // templates from within, we only want to add the topmost one. "topmost"
1540b57cec5SDimitry Andric     // happens to be the ones that don't have any currently open entries above
1550b57cec5SDimitry Andric     // itself.
156349cc55cSDimitry Andric     if (llvm::none_of(llvm::drop_begin(llvm::reverse(Stack)),
157*0fca6ea1SDimitry Andric                       [&](const std::unique_ptr<TimeTraceProfilerEntry> &Val) {
158*0fca6ea1SDimitry Andric                         return Val->Name == E.Name;
159bdd1243dSDimitry Andric                       })) {
1600b57cec5SDimitry Andric       auto &CountAndTotal = CountAndTotalPerName[E.Name];
1610b57cec5SDimitry Andric       CountAndTotal.first++;
1628bcb0991SDimitry Andric       CountAndTotal.second += Duration;
163*0fca6ea1SDimitry Andric     };
1640b57cec5SDimitry Andric 
165*0fca6ea1SDimitry Andric     llvm::erase_if(Stack,
166*0fca6ea1SDimitry Andric                    [&](const std::unique_ptr<TimeTraceProfilerEntry> &Val) {
167*0fca6ea1SDimitry Andric                      return Val.get() == &E;
168*0fca6ea1SDimitry Andric                    });
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric 
1715ffd83dbSDimitry Andric   // Write events from this TimeTraceProfilerInstance and
1725ffd83dbSDimitry Andric   // ThreadTimeTraceProfilerInstances.
1735ffd83dbSDimitry Andric   void write(raw_pwrite_stream &OS) {
1745ffd83dbSDimitry Andric     // Acquire Mutex as reading ThreadTimeTraceProfilerInstances.
175bdd1243dSDimitry Andric     auto &Instances = getTimeTraceProfilerInstances();
176bdd1243dSDimitry Andric     std::lock_guard<std::mutex> Lock(Instances.Lock);
1770b57cec5SDimitry Andric     assert(Stack.empty() &&
1785ffd83dbSDimitry Andric            "All profiler sections should be ended when calling write");
179bdd1243dSDimitry Andric     assert(llvm::all_of(Instances.List,
1805ffd83dbSDimitry Andric                         [](const auto &TTP) { return TTP->Stack.empty(); }) &&
1815ffd83dbSDimitry Andric            "All profiler sections should be ended when calling write");
1825ffd83dbSDimitry Andric 
1830b57cec5SDimitry Andric     json::OStream J(OS);
1840b57cec5SDimitry Andric     J.objectBegin();
1850b57cec5SDimitry Andric     J.attributeBegin("traceEvents");
1860b57cec5SDimitry Andric     J.arrayBegin();
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric     // Emit all events for the main flame graph.
1895ffd83dbSDimitry Andric     auto writeEvent = [&](const auto &E, uint64_t Tid) {
1908bcb0991SDimitry Andric       auto StartUs = E.getFlameGraphStartUs(StartTime);
1918bcb0991SDimitry Andric       auto DurUs = E.getFlameGraphDurUs();
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric       J.object([&] {
1945ffd83dbSDimitry Andric         J.attribute("pid", Pid);
1955ffd83dbSDimitry Andric         J.attribute("tid", int64_t(Tid));
1960b57cec5SDimitry Andric         J.attribute("ts", StartUs);
197*0fca6ea1SDimitry Andric         if (E.AsyncEvent) {
198*0fca6ea1SDimitry Andric           J.attribute("cat", E.Name);
199*0fca6ea1SDimitry Andric           J.attribute("ph", "b");
200*0fca6ea1SDimitry Andric           J.attribute("id", 0);
201*0fca6ea1SDimitry Andric         } else {
202*0fca6ea1SDimitry Andric           J.attribute("ph", "X");
2030b57cec5SDimitry Andric           J.attribute("dur", DurUs);
204*0fca6ea1SDimitry Andric         }
2050b57cec5SDimitry Andric         J.attribute("name", E.Name);
206*0fca6ea1SDimitry Andric         if (!E.Metadata.isEmpty()) {
207*0fca6ea1SDimitry Andric           J.attributeObject("args", [&] {
208*0fca6ea1SDimitry Andric             if (!E.Metadata.Detail.empty())
209*0fca6ea1SDimitry Andric               J.attribute("detail", E.Metadata.Detail);
210*0fca6ea1SDimitry Andric             if (!E.Metadata.File.empty())
211*0fca6ea1SDimitry Andric               J.attribute("file", E.Metadata.File);
212*0fca6ea1SDimitry Andric             if (E.Metadata.Line > 0)
213*0fca6ea1SDimitry Andric               J.attribute("line", E.Metadata.Line);
214*0fca6ea1SDimitry Andric           });
215480093f4SDimitry Andric         }
2160b57cec5SDimitry Andric       });
217*0fca6ea1SDimitry Andric 
218*0fca6ea1SDimitry Andric       if (E.AsyncEvent) {
219*0fca6ea1SDimitry Andric         J.object([&] {
220*0fca6ea1SDimitry Andric           J.attribute("pid", Pid);
221*0fca6ea1SDimitry Andric           J.attribute("tid", int64_t(Tid));
222*0fca6ea1SDimitry Andric           J.attribute("ts", StartUs + DurUs);
223*0fca6ea1SDimitry Andric           J.attribute("cat", E.Name);
224*0fca6ea1SDimitry Andric           J.attribute("ph", "e");
225*0fca6ea1SDimitry Andric           J.attribute("id", 0);
226*0fca6ea1SDimitry Andric           J.attribute("name", E.Name);
227*0fca6ea1SDimitry Andric         });
228*0fca6ea1SDimitry Andric       }
2295ffd83dbSDimitry Andric     };
230bdd1243dSDimitry Andric     for (const TimeTraceProfilerEntry &E : Entries)
2315ffd83dbSDimitry Andric       writeEvent(E, this->Tid);
232bdd1243dSDimitry Andric     for (const TimeTraceProfiler *TTP : Instances.List)
233bdd1243dSDimitry Andric       for (const TimeTraceProfilerEntry &E : TTP->Entries)
2345ffd83dbSDimitry Andric         writeEvent(E, TTP->Tid);
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric     // Emit totals by section name as additional "thread" events, sorted from
2370b57cec5SDimitry Andric     // longest one.
2385ffd83dbSDimitry Andric     // Find highest used thread id.
2395ffd83dbSDimitry Andric     uint64_t MaxTid = this->Tid;
240bdd1243dSDimitry Andric     for (const TimeTraceProfiler *TTP : Instances.List)
2415ffd83dbSDimitry Andric       MaxTid = std::max(MaxTid, TTP->Tid);
2420b57cec5SDimitry Andric 
2435ffd83dbSDimitry Andric     // Combine all CountAndTotalPerName from threads into one.
2445ffd83dbSDimitry Andric     StringMap<CountAndDurationType> AllCountAndTotalPerName;
2455ffd83dbSDimitry Andric     auto combineStat = [&](const auto &Stat) {
2465ffd83dbSDimitry Andric       StringRef Key = Stat.getKey();
2475ffd83dbSDimitry Andric       auto Value = Stat.getValue();
2485ffd83dbSDimitry Andric       auto &CountAndTotal = AllCountAndTotalPerName[Key];
2495ffd83dbSDimitry Andric       CountAndTotal.first += Value.first;
2505ffd83dbSDimitry Andric       CountAndTotal.second += Value.second;
2515ffd83dbSDimitry Andric     };
2525ffd83dbSDimitry Andric     for (const auto &Stat : CountAndTotalPerName)
2535ffd83dbSDimitry Andric       combineStat(Stat);
254bdd1243dSDimitry Andric     for (const TimeTraceProfiler *TTP : Instances.List)
2555ffd83dbSDimitry Andric       for (const auto &Stat : TTP->CountAndTotalPerName)
2565ffd83dbSDimitry Andric         combineStat(Stat);
2575ffd83dbSDimitry Andric 
2585ffd83dbSDimitry Andric     std::vector<NameAndCountAndDurationType> SortedTotals;
2595ffd83dbSDimitry Andric     SortedTotals.reserve(AllCountAndTotalPerName.size());
2605ffd83dbSDimitry Andric     for (const auto &Total : AllCountAndTotalPerName)
2615ffd83dbSDimitry Andric       SortedTotals.emplace_back(std::string(Total.getKey()), Total.getValue());
2625ffd83dbSDimitry Andric 
2635ffd83dbSDimitry Andric     llvm::sort(SortedTotals, [](const NameAndCountAndDurationType &A,
2640b57cec5SDimitry Andric                                 const NameAndCountAndDurationType &B) {
2650b57cec5SDimitry Andric       return A.second.second > B.second.second;
2660b57cec5SDimitry Andric     });
2675ffd83dbSDimitry Andric 
2685ffd83dbSDimitry Andric     // Report totals on separate threads of tracing file.
2695ffd83dbSDimitry Andric     uint64_t TotalTid = MaxTid + 1;
2705ffd83dbSDimitry Andric     for (const NameAndCountAndDurationType &Total : SortedTotals) {
2715ffd83dbSDimitry Andric       auto DurUs = duration_cast<microseconds>(Total.second.second).count();
2725ffd83dbSDimitry Andric       auto Count = AllCountAndTotalPerName[Total.first].first;
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric       J.object([&] {
2755ffd83dbSDimitry Andric         J.attribute("pid", Pid);
2765ffd83dbSDimitry Andric         J.attribute("tid", int64_t(TotalTid));
2770b57cec5SDimitry Andric         J.attribute("ph", "X");
2780b57cec5SDimitry Andric         J.attribute("ts", 0);
2790b57cec5SDimitry Andric         J.attribute("dur", DurUs);
2805ffd83dbSDimitry Andric         J.attribute("name", "Total " + Total.first);
2810b57cec5SDimitry Andric         J.attributeObject("args", [&] {
2820b57cec5SDimitry Andric           J.attribute("count", int64_t(Count));
2830b57cec5SDimitry Andric           J.attribute("avg ms", int64_t(DurUs / Count / 1000));
2840b57cec5SDimitry Andric         });
2850b57cec5SDimitry Andric       });
2860b57cec5SDimitry Andric 
2875ffd83dbSDimitry Andric       ++TotalTid;
2880b57cec5SDimitry Andric     }
2890b57cec5SDimitry Andric 
2905ffd83dbSDimitry Andric     auto writeMetadataEvent = [&](const char *Name, uint64_t Tid,
2915ffd83dbSDimitry Andric                                   StringRef arg) {
2920b57cec5SDimitry Andric       J.object([&] {
2930b57cec5SDimitry Andric         J.attribute("cat", "");
2945ffd83dbSDimitry Andric         J.attribute("pid", Pid);
2955ffd83dbSDimitry Andric         J.attribute("tid", int64_t(Tid));
2960b57cec5SDimitry Andric         J.attribute("ts", 0);
2970b57cec5SDimitry Andric         J.attribute("ph", "M");
2985ffd83dbSDimitry Andric         J.attribute("name", Name);
2995ffd83dbSDimitry Andric         J.attributeObject("args", [&] { J.attribute("name", arg); });
3000b57cec5SDimitry Andric       });
3015ffd83dbSDimitry Andric     };
3025ffd83dbSDimitry Andric 
3035ffd83dbSDimitry Andric     writeMetadataEvent("process_name", Tid, ProcName);
3045ffd83dbSDimitry Andric     writeMetadataEvent("thread_name", Tid, ThreadName);
305bdd1243dSDimitry Andric     for (const TimeTraceProfiler *TTP : Instances.List)
3065ffd83dbSDimitry Andric       writeMetadataEvent("thread_name", TTP->Tid, TTP->ThreadName);
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric     J.arrayEnd();
3090b57cec5SDimitry Andric     J.attributeEnd();
3105ffd83dbSDimitry Andric 
3115ffd83dbSDimitry Andric     // Emit the absolute time when this TimeProfiler started.
3125ffd83dbSDimitry Andric     // This can be used to combine the profiling data from
3135ffd83dbSDimitry Andric     // multiple processes and preserve actual time intervals.
3145ffd83dbSDimitry Andric     J.attribute("beginningOfTime",
3155ffd83dbSDimitry Andric                 time_point_cast<microseconds>(BeginningOfTime)
3165ffd83dbSDimitry Andric                     .time_since_epoch()
3175ffd83dbSDimitry Andric                     .count());
3185ffd83dbSDimitry Andric 
3190b57cec5SDimitry Andric     J.objectEnd();
3200b57cec5SDimitry Andric   }
3210b57cec5SDimitry Andric 
322*0fca6ea1SDimitry Andric   SmallVector<std::unique_ptr<TimeTraceProfilerEntry>, 16> Stack;
323bdd1243dSDimitry Andric   SmallVector<TimeTraceProfilerEntry, 128> Entries;
3240b57cec5SDimitry Andric   StringMap<CountAndDurationType> CountAndTotalPerName;
325bdd1243dSDimitry Andric   // System clock time when the session was begun.
3265ffd83dbSDimitry Andric   const time_point<system_clock> BeginningOfTime;
327bdd1243dSDimitry Andric   // Profiling clock time when the session was begun.
328480093f4SDimitry Andric   const TimePointType StartTime;
329480093f4SDimitry Andric   const std::string ProcName;
3305ffd83dbSDimitry Andric   const sys::Process::Pid Pid;
3315ffd83dbSDimitry Andric   SmallString<0> ThreadName;
3325ffd83dbSDimitry Andric   const uint64_t Tid;
3338bcb0991SDimitry Andric 
3348bcb0991SDimitry Andric   // Minimum time granularity (in microseconds)
335480093f4SDimitry Andric   const unsigned TimeTraceGranularity;
336*0fca6ea1SDimitry Andric 
337*0fca6ea1SDimitry Andric   // Make time trace capture verbose event details (e.g. source filenames). This
338*0fca6ea1SDimitry Andric   // can increase the size of the output by 2-3 times.
339*0fca6ea1SDimitry Andric   const bool TimeTraceVerbose;
3400b57cec5SDimitry Andric };
3410b57cec5SDimitry Andric 
342*0fca6ea1SDimitry Andric bool llvm::isTimeTraceVerbose() {
343*0fca6ea1SDimitry Andric   return getTimeTraceProfilerInstance() &&
344*0fca6ea1SDimitry Andric          getTimeTraceProfilerInstance()->TimeTraceVerbose;
345*0fca6ea1SDimitry Andric }
346*0fca6ea1SDimitry Andric 
3475ffd83dbSDimitry Andric void llvm::timeTraceProfilerInitialize(unsigned TimeTraceGranularity,
348*0fca6ea1SDimitry Andric                                        StringRef ProcName,
349*0fca6ea1SDimitry Andric                                        bool TimeTraceVerbose) {
3500b57cec5SDimitry Andric   assert(TimeTraceProfilerInstance == nullptr &&
3510b57cec5SDimitry Andric          "Profiler should not be initialized");
352480093f4SDimitry Andric   TimeTraceProfilerInstance = new TimeTraceProfiler(
353*0fca6ea1SDimitry Andric       TimeTraceGranularity, llvm::sys::path::filename(ProcName),
354*0fca6ea1SDimitry Andric       TimeTraceVerbose);
3550b57cec5SDimitry Andric }
3560b57cec5SDimitry Andric 
3575ffd83dbSDimitry Andric // Removes all TimeTraceProfilerInstances.
3585ffd83dbSDimitry Andric // Called from main thread.
3595ffd83dbSDimitry Andric void llvm::timeTraceProfilerCleanup() {
3600b57cec5SDimitry Andric   delete TimeTraceProfilerInstance;
361349cc55cSDimitry Andric   TimeTraceProfilerInstance = nullptr;
362bdd1243dSDimitry Andric 
363bdd1243dSDimitry Andric   auto &Instances = getTimeTraceProfilerInstances();
364bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(Instances.Lock);
365bdd1243dSDimitry Andric   for (auto *TTP : Instances.List)
3665ffd83dbSDimitry Andric     delete TTP;
367bdd1243dSDimitry Andric   Instances.List.clear();
3685ffd83dbSDimitry Andric }
3695ffd83dbSDimitry Andric 
3705ffd83dbSDimitry Andric // Finish TimeTraceProfilerInstance on a worker thread.
3715ffd83dbSDimitry Andric // This doesn't remove the instance, just moves the pointer to global vector.
3725ffd83dbSDimitry Andric void llvm::timeTraceProfilerFinishThread() {
373bdd1243dSDimitry Andric   auto &Instances = getTimeTraceProfilerInstances();
374bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(Instances.Lock);
375bdd1243dSDimitry Andric   Instances.List.push_back(TimeTraceProfilerInstance);
3760b57cec5SDimitry Andric   TimeTraceProfilerInstance = nullptr;
3770b57cec5SDimitry Andric }
3780b57cec5SDimitry Andric 
3795ffd83dbSDimitry Andric void llvm::timeTraceProfilerWrite(raw_pwrite_stream &OS) {
3800b57cec5SDimitry Andric   assert(TimeTraceProfilerInstance != nullptr &&
3810b57cec5SDimitry Andric          "Profiler object can't be null");
3825ffd83dbSDimitry Andric   TimeTraceProfilerInstance->write(OS);
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric 
3855ffd83dbSDimitry Andric Error llvm::timeTraceProfilerWrite(StringRef PreferredFileName,
3865ffd83dbSDimitry Andric                                    StringRef FallbackFileName) {
3875ffd83dbSDimitry Andric   assert(TimeTraceProfilerInstance != nullptr &&
3885ffd83dbSDimitry Andric          "Profiler object can't be null");
3895ffd83dbSDimitry Andric 
3905ffd83dbSDimitry Andric   std::string Path = PreferredFileName.str();
3915ffd83dbSDimitry Andric   if (Path.empty()) {
3925ffd83dbSDimitry Andric     Path = FallbackFileName == "-" ? "out" : FallbackFileName.str();
3935ffd83dbSDimitry Andric     Path += ".time-trace";
3945ffd83dbSDimitry Andric   }
3955ffd83dbSDimitry Andric 
3965ffd83dbSDimitry Andric   std::error_code EC;
397fe6060f1SDimitry Andric   raw_fd_ostream OS(Path, EC, sys::fs::OF_TextWithCRLF);
3985ffd83dbSDimitry Andric   if (EC)
3995ffd83dbSDimitry Andric     return createStringError(EC, "Could not open " + Path);
4005ffd83dbSDimitry Andric 
4015ffd83dbSDimitry Andric   timeTraceProfilerWrite(OS);
4025ffd83dbSDimitry Andric   return Error::success();
4035ffd83dbSDimitry Andric }
4045ffd83dbSDimitry Andric 
405*0fca6ea1SDimitry Andric TimeTraceProfilerEntry *llvm::timeTraceProfilerBegin(StringRef Name,
406*0fca6ea1SDimitry Andric                                                      StringRef Detail) {
4070b57cec5SDimitry Andric   if (TimeTraceProfilerInstance != nullptr)
408*0fca6ea1SDimitry Andric     return TimeTraceProfilerInstance->begin(
409*0fca6ea1SDimitry Andric         std::string(Name), [&]() { return std::string(Detail); }, false);
410*0fca6ea1SDimitry Andric   return nullptr;
4110b57cec5SDimitry Andric }
4120b57cec5SDimitry Andric 
413*0fca6ea1SDimitry Andric TimeTraceProfilerEntry *
414*0fca6ea1SDimitry Andric llvm::timeTraceProfilerBegin(StringRef Name,
4150b57cec5SDimitry Andric                              llvm::function_ref<std::string()> Detail) {
4160b57cec5SDimitry Andric   if (TimeTraceProfilerInstance != nullptr)
417*0fca6ea1SDimitry Andric     return TimeTraceProfilerInstance->begin(std::string(Name), Detail, false);
418*0fca6ea1SDimitry Andric   return nullptr;
419*0fca6ea1SDimitry Andric }
420*0fca6ea1SDimitry Andric 
421*0fca6ea1SDimitry Andric TimeTraceProfilerEntry *
422*0fca6ea1SDimitry Andric llvm::timeTraceProfilerBegin(StringRef Name,
423*0fca6ea1SDimitry Andric                              llvm::function_ref<TimeTraceMetadata()> Metadata) {
424*0fca6ea1SDimitry Andric   if (TimeTraceProfilerInstance != nullptr)
425*0fca6ea1SDimitry Andric     return TimeTraceProfilerInstance->begin(std::string(Name), Metadata, false);
426*0fca6ea1SDimitry Andric   return nullptr;
427*0fca6ea1SDimitry Andric }
428*0fca6ea1SDimitry Andric 
429*0fca6ea1SDimitry Andric TimeTraceProfilerEntry *llvm::timeTraceAsyncProfilerBegin(StringRef Name,
430*0fca6ea1SDimitry Andric                                                           StringRef Detail) {
431*0fca6ea1SDimitry Andric   if (TimeTraceProfilerInstance != nullptr)
432*0fca6ea1SDimitry Andric     return TimeTraceProfilerInstance->begin(
433*0fca6ea1SDimitry Andric         std::string(Name), [&]() { return std::string(Detail); }, true);
434*0fca6ea1SDimitry Andric   return nullptr;
4350b57cec5SDimitry Andric }
4360b57cec5SDimitry Andric 
4375ffd83dbSDimitry Andric void llvm::timeTraceProfilerEnd() {
4380b57cec5SDimitry Andric   if (TimeTraceProfilerInstance != nullptr)
4390b57cec5SDimitry Andric     TimeTraceProfilerInstance->end();
4400b57cec5SDimitry Andric }
441*0fca6ea1SDimitry Andric 
442*0fca6ea1SDimitry Andric void llvm::timeTraceProfilerEnd(TimeTraceProfilerEntry *E) {
443*0fca6ea1SDimitry Andric   if (TimeTraceProfilerInstance != nullptr)
444*0fca6ea1SDimitry Andric     TimeTraceProfilerInstance->end(*E);
445*0fca6ea1SDimitry Andric }
446