1313#include " llvm/Support/TimeProfiler.h"
1414#include " llvm/ADT/STLExtras.h"
1515#include " llvm/ADT/STLFunctionalExtras.h"
16+ #include " llvm/ADT/SmallVector.h"
1617#include " llvm/ADT/StringMap.h"
1718#include " llvm/Support/JSON.h"
1819#include " llvm/Support/Path.h"
@@ -75,18 +76,18 @@ struct llvm::TimeTraceProfilerEntry {
7576 const std::string Name;
7677 TimeTraceMetadata Metadata;
7778
78- const bool AsyncEvent = false ;
79+ const TimeTraceEventType EventType = TimeTraceEventType::CompleteEvent ;
7980 TimeTraceProfilerEntry (TimePointType &&S, TimePointType &&E, std::string &&N,
80- std::string &&Dt, bool Ae )
81+ std::string &&Dt, TimeTraceEventType Et )
8182 : Start(std::move(S)), End(std::move(E)), Name(std::move(N)), Metadata(),
82- AsyncEvent (Ae ) {
83+ EventType (Et ) {
8384 Metadata.Detail = std::move (Dt);
8485 }
8586
8687 TimeTraceProfilerEntry (TimePointType &&S, TimePointType &&E, std::string &&N,
87- TimeTraceMetadata &&Mt, bool Ae )
88+ TimeTraceMetadata &&Mt, TimeTraceEventType Et )
8889 : Start(std::move(S)), End(std::move(E)), Name(std::move(N)),
89- Metadata(std::move(Mt)), AsyncEvent(Ae ) {}
90+ Metadata(std::move(Mt)), EventType(Et ) {}
9091
9192 // Calculate timings for FlameGraph. Cast time points to microsecond precision
9293 // rather than casting duration. This avoids truncation issues causing inner
@@ -104,6 +105,25 @@ struct llvm::TimeTraceProfilerEntry {
104105 }
105106};
106107
108+ // Represents a currently open (in-progress) time trace entry. InstantEvents
109+ // that happen during an open event are associated with the duration of this
110+ // parent event and they are dropped if parent duration is shorter than
111+ // the granularity.
112+ struct InProgressEntry {
113+ TimeTraceProfilerEntry Event;
114+ std::vector<TimeTraceProfilerEntry> InstantEvents;
115+
116+ InProgressEntry (TimePointType S, TimePointType E, std::string N,
117+ std::string Dt, TimeTraceEventType Et)
118+ : Event(std::move(S), std::move(E), std::move(N), std::move(Dt), Et),
119+ InstantEvents () {}
120+
121+ InProgressEntry (TimePointType S, TimePointType E, std::string N,
122+ TimeTraceMetadata Mt, TimeTraceEventType Et)
123+ : Event(std::move(S), std::move(E), std::move(N), std::move(Mt), Et),
124+ InstantEvents() {}
125+ };
126+
107127struct llvm ::TimeTraceProfiler {
108128 TimeTraceProfiler (unsigned TimeTraceGranularity = 0 , StringRef ProcName = " " ,
109129 bool TimeTraceVerbose = false )
@@ -114,27 +134,40 @@ struct llvm::TimeTraceProfiler {
114134 llvm::get_thread_name (ThreadName);
115135 }
116136
117- TimeTraceProfilerEntry *begin (std::string Name,
118- llvm::function_ref<std::string()> Detail,
119- bool AsyncEvent = false) {
120- Stack.emplace_back (std::make_unique<TimeTraceProfilerEntry>(
137+ TimeTraceProfilerEntry *
138+ begin (std::string Name, llvm::function_ref<std::string()> Detail,
139+ TimeTraceEventType EventType = TimeTraceEventType::CompleteEvent) {
140+ assert (EventType != TimeTraceEventType::InstantEvent &&
141+ " Instant Events don't have begin and end." );
142+ Stack.emplace_back (std::make_unique<InProgressEntry>(
121143 ClockType::now (), TimePointType (), std::move (Name), Detail (),
122- AsyncEvent ));
123- return Stack.back (). get () ;
144+ EventType ));
145+ return & Stack.back ()-> Event ;
124146 }
125147
126148 TimeTraceProfilerEntry *
127149 begin (std::string Name, llvm::function_ref<TimeTraceMetadata()> Metadata,
128- bool AsyncEvent = false) {
129- Stack.emplace_back (std::make_unique<TimeTraceProfilerEntry>(
150+ TimeTraceEventType EventType = TimeTraceEventType::CompleteEvent) {
151+ assert (EventType != TimeTraceEventType::InstantEvent &&
152+ " Instant Events don't have begin and end." );
153+ Stack.emplace_back (std::make_unique<InProgressEntry>(
130154 ClockType::now (), TimePointType (), std::move (Name), Metadata (),
131- AsyncEvent));
132- return Stack.back ().get ();
155+ EventType));
156+ return &Stack.back ()->Event ;
157+ }
158+
159+ void insert (std::string Name, llvm::function_ref<std::string()> Detail) {
160+ if (Stack.empty ())
161+ return ;
162+
163+ Stack.back ().get ()->InstantEvents .emplace_back (TimeTraceProfilerEntry (
164+ ClockType::now (), TimePointType (), std::move (Name), Detail (),
165+ TimeTraceEventType::InstantEvent));
133166 }
134167
135168 void end () {
136169 assert (!Stack.empty () && " Must call begin() first" );
137- end (* Stack.back ());
170+ end (Stack.back ()-> Event );
138171 }
139172
140173 void end (TimeTraceProfilerEntry &E) {
@@ -144,28 +177,35 @@ struct llvm::TimeTraceProfiler {
144177 // Calculate duration at full precision for overall counts.
145178 DurationType Duration = E.End - E.Start ;
146179
180+ const auto *Iter =
181+ llvm::find_if (Stack, [&](const std::unique_ptr<InProgressEntry> &Val) {
182+ return &Val->Event == &E;
183+ });
184+ assert (Iter != Stack.end () && " Event not in the Stack" );
185+
147186 // Only include sections longer or equal to TimeTraceGranularity msec.
148- if (duration_cast<microseconds>(Duration).count () >= TimeTraceGranularity)
187+ if (duration_cast<microseconds>(Duration).count () >= TimeTraceGranularity) {
149188 Entries.emplace_back (E);
189+ for (auto &IE : Iter->get ()->InstantEvents ) {
190+ Entries.emplace_back (IE);
191+ }
192+ }
150193
151194 // Track total time taken by each "name", but only the topmost levels of
152195 // them; e.g. if there's a template instantiation that instantiates other
153196 // templates from within, we only want to add the topmost one. "topmost"
154197 // happens to be the ones that don't have any currently open entries above
155198 // itself.
156199 if (llvm::none_of (llvm::drop_begin (llvm::reverse (Stack)),
157- [&](const std::unique_ptr<TimeTraceProfilerEntry > &Val) {
158- return Val->Name == E.Name ;
200+ [&](const std::unique_ptr<InProgressEntry > &Val) {
201+ return Val->Event . Name == E.Name ;
159202 })) {
160203 auto &CountAndTotal = CountAndTotalPerName[E.Name ];
161204 CountAndTotal.first ++;
162205 CountAndTotal.second += Duration;
163206 };
164207
165- llvm::erase_if (Stack,
166- [&](const std::unique_ptr<TimeTraceProfilerEntry> &Val) {
167- return Val.get () == &E;
168- });
208+ Stack.erase (Iter);
169209 }
170210
171211 // Write events from this TimeTraceProfilerInstance and
@@ -194,13 +234,17 @@ struct llvm::TimeTraceProfiler {
194234 J.attribute (" pid" , Pid);
195235 J.attribute (" tid" , int64_t (Tid));
196236 J.attribute (" ts" , StartUs);
197- if (E.AsyncEvent ) {
237+ if (E.EventType == TimeTraceEventType:: AsyncEvent) {
198238 J.attribute (" cat" , E.Name );
199239 J.attribute (" ph" , " b" );
200240 J.attribute (" id" , 0 );
201- } else {
241+ } else if (E. EventType == TimeTraceEventType::CompleteEvent) {
202242 J.attribute (" ph" , " X" );
203243 J.attribute (" dur" , DurUs);
244+ } else { // instant event
245+ assert (E.EventType == TimeTraceEventType::InstantEvent &&
246+ " InstantEvent expected" );
247+ J.attribute (" ph" , " i" );
204248 }
205249 J.attribute (" name" , E.Name );
206250 if (!E.Metadata .isEmpty ()) {
@@ -215,7 +259,7 @@ struct llvm::TimeTraceProfiler {
215259 }
216260 });
217261
218- if (E.AsyncEvent ) {
262+ if (E.EventType == TimeTraceEventType:: AsyncEvent) {
219263 J.object ([&] {
220264 J.attribute (" pid" , Pid);
221265 J.attribute (" tid" , int64_t (Tid));
@@ -319,7 +363,7 @@ struct llvm::TimeTraceProfiler {
319363 J.objectEnd ();
320364 }
321365
322- SmallVector<std::unique_ptr<TimeTraceProfilerEntry >, 16 > Stack;
366+ SmallVector<std::unique_ptr<InProgressEntry >, 16 > Stack;
323367 SmallVector<TimeTraceProfilerEntry, 128 > Entries;
324368 StringMap<CountAndDurationType> CountAndTotalPerName;
325369 // System clock time when the session was begun.
@@ -406,34 +450,44 @@ TimeTraceProfilerEntry *llvm::timeTraceProfilerBegin(StringRef Name,
406450 StringRef Detail) {
407451 if (TimeTraceProfilerInstance != nullptr )
408452 return TimeTraceProfilerInstance->begin (
409- std::string (Name), [&]() { return std::string (Detail); }, false );
453+ std::string (Name), [&]() { return std::string (Detail); },
454+ TimeTraceEventType::CompleteEvent);
410455 return nullptr ;
411456}
412457
413458TimeTraceProfilerEntry *
414459llvm::timeTraceProfilerBegin (StringRef Name,
415460 llvm::function_ref<std::string()> Detail) {
416461 if (TimeTraceProfilerInstance != nullptr )
417- return TimeTraceProfilerInstance->begin (std::string (Name), Detail, false );
462+ return TimeTraceProfilerInstance->begin (std::string (Name), Detail,
463+ TimeTraceEventType::CompleteEvent);
418464 return nullptr ;
419465}
420466
421467TimeTraceProfilerEntry *
422468llvm::timeTraceProfilerBegin (StringRef Name,
423469 llvm::function_ref<TimeTraceMetadata()> Metadata) {
424470 if (TimeTraceProfilerInstance != nullptr )
425- return TimeTraceProfilerInstance->begin (std::string (Name), Metadata, false );
471+ return TimeTraceProfilerInstance->begin (std::string (Name), Metadata,
472+ TimeTraceEventType::CompleteEvent);
426473 return nullptr ;
427474}
428475
429476TimeTraceProfilerEntry *llvm::timeTraceAsyncProfilerBegin (StringRef Name,
430477 StringRef Detail) {
431478 if (TimeTraceProfilerInstance != nullptr )
432479 return TimeTraceProfilerInstance->begin (
433- std::string (Name), [&]() { return std::string (Detail); }, true );
480+ std::string (Name), [&]() { return std::string (Detail); },
481+ TimeTraceEventType::AsyncEvent);
434482 return nullptr ;
435483}
436484
485+ void llvm::timeTraceAddInstantEvent (StringRef Name,
486+ llvm::function_ref<std::string()> Detail) {
487+ if (TimeTraceProfilerInstance != nullptr )
488+ TimeTraceProfilerInstance->insert (std::string (Name), Detail);
489+ }
490+
437491void llvm::timeTraceProfilerEnd () {
438492 if (TimeTraceProfilerInstance != nullptr )
439493 TimeTraceProfilerInstance->end ();
0 commit comments