13
13
#include " llvm/Support/TimeProfiler.h"
14
14
#include " llvm/ADT/STLExtras.h"
15
15
#include " llvm/ADT/STLFunctionalExtras.h"
16
+ #include " llvm/ADT/SmallVector.h"
16
17
#include " llvm/ADT/StringMap.h"
17
18
#include " llvm/Support/JSON.h"
18
19
#include " llvm/Support/Path.h"
@@ -75,18 +76,18 @@ struct llvm::TimeTraceProfilerEntry {
75
76
const std::string Name;
76
77
TimeTraceMetadata Metadata;
77
78
78
- const bool AsyncEvent = false ;
79
+ const TimeTraceEventType EventType = TimeTraceEventType::CompleteEvent ;
79
80
TimeTraceProfilerEntry (TimePointType &&S, TimePointType &&E, std::string &&N,
80
- std::string &&Dt, bool Ae )
81
+ std::string &&Dt, TimeTraceEventType Et )
81
82
: Start(std::move(S)), End(std::move(E)), Name(std::move(N)), Metadata(),
82
- AsyncEvent (Ae ) {
83
+ EventType (Et ) {
83
84
Metadata.Detail = std::move (Dt);
84
85
}
85
86
86
87
TimeTraceProfilerEntry (TimePointType &&S, TimePointType &&E, std::string &&N,
87
- TimeTraceMetadata &&Mt, bool Ae )
88
+ TimeTraceMetadata &&Mt, TimeTraceEventType Et )
88
89
: 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 ) {}
90
91
91
92
// Calculate timings for FlameGraph. Cast time points to microsecond precision
92
93
// rather than casting duration. This avoids truncation issues causing inner
@@ -104,6 +105,25 @@ struct llvm::TimeTraceProfilerEntry {
104
105
}
105
106
};
106
107
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
+
107
127
struct llvm ::TimeTraceProfiler {
108
128
TimeTraceProfiler (unsigned TimeTraceGranularity = 0 , StringRef ProcName = " " ,
109
129
bool TimeTraceVerbose = false )
@@ -114,27 +134,40 @@ struct llvm::TimeTraceProfiler {
114
134
llvm::get_thread_name (ThreadName);
115
135
}
116
136
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>(
121
143
ClockType::now (), TimePointType (), std::move (Name), Detail (),
122
- AsyncEvent ));
123
- return Stack.back (). get () ;
144
+ EventType ));
145
+ return & Stack.back ()-> Event ;
124
146
}
125
147
126
148
TimeTraceProfilerEntry *
127
149
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>(
130
154
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));
133
166
}
134
167
135
168
void end () {
136
169
assert (!Stack.empty () && " Must call begin() first" );
137
- end (* Stack.back ());
170
+ end (Stack.back ()-> Event );
138
171
}
139
172
140
173
void end (TimeTraceProfilerEntry &E) {
@@ -144,28 +177,35 @@ struct llvm::TimeTraceProfiler {
144
177
// Calculate duration at full precision for overall counts.
145
178
DurationType Duration = E.End - E.Start ;
146
179
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
+
147
186
// 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) {
149
188
Entries.emplace_back (E);
189
+ for (auto &IE : Iter->get ()->InstantEvents ) {
190
+ Entries.emplace_back (IE);
191
+ }
192
+ }
150
193
151
194
// Track total time taken by each "name", but only the topmost levels of
152
195
// them; e.g. if there's a template instantiation that instantiates other
153
196
// templates from within, we only want to add the topmost one. "topmost"
154
197
// happens to be the ones that don't have any currently open entries above
155
198
// itself.
156
199
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 ;
159
202
})) {
160
203
auto &CountAndTotal = CountAndTotalPerName[E.Name ];
161
204
CountAndTotal.first ++;
162
205
CountAndTotal.second += Duration;
163
206
};
164
207
165
- llvm::erase_if (Stack,
166
- [&](const std::unique_ptr<TimeTraceProfilerEntry> &Val) {
167
- return Val.get () == &E;
168
- });
208
+ Stack.erase (Iter);
169
209
}
170
210
171
211
// Write events from this TimeTraceProfilerInstance and
@@ -194,13 +234,17 @@ struct llvm::TimeTraceProfiler {
194
234
J.attribute (" pid" , Pid);
195
235
J.attribute (" tid" , int64_t (Tid));
196
236
J.attribute (" ts" , StartUs);
197
- if (E.AsyncEvent ) {
237
+ if (E.EventType == TimeTraceEventType:: AsyncEvent) {
198
238
J.attribute (" cat" , E.Name );
199
239
J.attribute (" ph" , " b" );
200
240
J.attribute (" id" , 0 );
201
- } else {
241
+ } else if (E. EventType == TimeTraceEventType::CompleteEvent) {
202
242
J.attribute (" ph" , " X" );
203
243
J.attribute (" dur" , DurUs);
244
+ } else { // instant event
245
+ assert (E.EventType == TimeTraceEventType::InstantEvent &&
246
+ " InstantEvent expected" );
247
+ J.attribute (" ph" , " i" );
204
248
}
205
249
J.attribute (" name" , E.Name );
206
250
if (!E.Metadata .isEmpty ()) {
@@ -215,7 +259,7 @@ struct llvm::TimeTraceProfiler {
215
259
}
216
260
});
217
261
218
- if (E.AsyncEvent ) {
262
+ if (E.EventType == TimeTraceEventType:: AsyncEvent) {
219
263
J.object ([&] {
220
264
J.attribute (" pid" , Pid);
221
265
J.attribute (" tid" , int64_t (Tid));
@@ -319,7 +363,7 @@ struct llvm::TimeTraceProfiler {
319
363
J.objectEnd ();
320
364
}
321
365
322
- SmallVector<std::unique_ptr<TimeTraceProfilerEntry >, 16 > Stack;
366
+ SmallVector<std::unique_ptr<InProgressEntry >, 16 > Stack;
323
367
SmallVector<TimeTraceProfilerEntry, 128 > Entries;
324
368
StringMap<CountAndDurationType> CountAndTotalPerName;
325
369
// System clock time when the session was begun.
@@ -406,34 +450,44 @@ TimeTraceProfilerEntry *llvm::timeTraceProfilerBegin(StringRef Name,
406
450
StringRef Detail) {
407
451
if (TimeTraceProfilerInstance != nullptr )
408
452
return TimeTraceProfilerInstance->begin (
409
- std::string (Name), [&]() { return std::string (Detail); }, false );
453
+ std::string (Name), [&]() { return std::string (Detail); },
454
+ TimeTraceEventType::CompleteEvent);
410
455
return nullptr ;
411
456
}
412
457
413
458
TimeTraceProfilerEntry *
414
459
llvm::timeTraceProfilerBegin (StringRef Name,
415
460
llvm::function_ref<std::string()> Detail) {
416
461
if (TimeTraceProfilerInstance != nullptr )
417
- return TimeTraceProfilerInstance->begin (std::string (Name), Detail, false );
462
+ return TimeTraceProfilerInstance->begin (std::string (Name), Detail,
463
+ TimeTraceEventType::CompleteEvent);
418
464
return nullptr ;
419
465
}
420
466
421
467
TimeTraceProfilerEntry *
422
468
llvm::timeTraceProfilerBegin (StringRef Name,
423
469
llvm::function_ref<TimeTraceMetadata()> Metadata) {
424
470
if (TimeTraceProfilerInstance != nullptr )
425
- return TimeTraceProfilerInstance->begin (std::string (Name), Metadata, false );
471
+ return TimeTraceProfilerInstance->begin (std::string (Name), Metadata,
472
+ TimeTraceEventType::CompleteEvent);
426
473
return nullptr ;
427
474
}
428
475
429
476
TimeTraceProfilerEntry *llvm::timeTraceAsyncProfilerBegin (StringRef Name,
430
477
StringRef Detail) {
431
478
if (TimeTraceProfilerInstance != nullptr )
432
479
return TimeTraceProfilerInstance->begin (
433
- std::string (Name), [&]() { return std::string (Detail); }, true );
480
+ std::string (Name), [&]() { return std::string (Detail); },
481
+ TimeTraceEventType::AsyncEvent);
434
482
return nullptr ;
435
483
}
436
484
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
+
437
491
void llvm::timeTraceProfilerEnd () {
438
492
if (TimeTraceProfilerInstance != nullptr )
439
493
TimeTraceProfilerInstance->end ();
0 commit comments