10
10
#include " clang/Frontend/FrontendActions.h"
11
11
#include " clang/Lex/PreprocessorOptions.h"
12
12
13
- #include " llvm/ADT/StringMap.h"
14
13
#include " llvm/Support/JSON.h"
15
14
#include " llvm/Support/TimeProfiler.h"
16
- #include " llvm/Support/VirtualFileSystem.h"
17
15
#include < stack>
18
16
19
17
#include " gtest/gtest.h"
20
- #include < tuple>
21
18
22
19
using namespace clang ;
23
20
using namespace llvm ;
@@ -26,8 +23,7 @@ namespace {
26
23
27
24
// Should be called before testing.
28
25
void setupProfiler () {
29
- timeTraceProfilerInitialize (/* TimeTraceGranularity=*/ 0 , " test" ,
30
- /* TimeTraceVerbose=*/ true );
26
+ timeTraceProfilerInitialize (/* TimeTraceGranularity=*/ 0 , " test" );
31
27
}
32
28
33
29
// Should be called after `compileFromString()`.
@@ -42,24 +38,14 @@ std::string teardownProfiler() {
42
38
43
39
// Returns true if code compiles successfully.
44
40
// We only parse AST here. This is enough for constexpr evaluation.
45
- bool compileFromString (StringRef Code, StringRef Standard, StringRef File,
46
- llvm::StringMap<std::string> Headers = {}) {
41
+ bool compileFromString (StringRef Code, StringRef Standard, StringRef FileName) {
47
42
CompilerInstance Compiler;
48
43
Compiler.createDiagnostics ();
49
44
50
- llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS (
51
- new llvm::vfs::InMemoryFileSystem ());
52
- FS->addFile (File, 0 , MemoryBuffer::getMemBuffer (Code));
53
- for (const auto &Header : Headers) {
54
- FS->addFile (Header.getKey (), 0 ,
55
- MemoryBuffer::getMemBuffer (Header.getValue ()));
56
- }
57
- llvm::IntrusiveRefCntPtr<FileManager> Files (
58
- new FileManager (FileSystemOptions (), FS));
59
- Compiler.setFileManager (Files.get ());
60
-
61
45
auto Invocation = std::make_shared<CompilerInvocation>();
62
- std::vector<const char *> Args = {Standard.data (), File.data ()};
46
+ Invocation->getPreprocessorOpts ().addRemappedFile (
47
+ FileName, MemoryBuffer::getMemBuffer (Code).release ());
48
+ const char *Args[] = {Standard.data (), FileName.data ()};
63
49
CompilerInvocation::CreateFromArgs (*Invocation, Args,
64
50
Compiler.getDiagnostics ());
65
51
Compiler.setInvocation (std::move (Invocation));
@@ -74,27 +60,13 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef File,
74
60
return Compiler.ExecuteAction (Action);
75
61
}
76
62
77
- std::string GetMetadata (json::Object *Event) {
78
- std::string Metadata;
79
- llvm::raw_string_ostream OS (Metadata);
80
- if (json::Object *Args = Event->getObject (" args" )) {
81
- if (auto Detail = Args->getString (" detail" ))
82
- OS << Detail->str ();
83
- if (auto File = Args->getString (" file" ))
84
- OS << " , " << File->str ();
85
- if (auto Line = Args->getInteger (" line" ))
86
- OS << " :" << *Line;
87
- }
88
- return Metadata;
89
- }
90
-
91
63
// Returns pretty-printed trace graph.
92
64
std::string buildTraceGraph (StringRef Json) {
93
65
struct EventRecord {
94
66
int64_t TimestampBegin;
95
67
int64_t TimestampEnd;
96
- std::string Name;
97
- std::string Metadata ;
68
+ StringRef Name;
69
+ StringRef Detail ;
98
70
};
99
71
std::vector<EventRecord> Events;
100
72
@@ -109,21 +81,18 @@ std::string buildTraceGraph(StringRef Json) {
109
81
int64_t TimestampBegin = TraceEventObj->getInteger (" ts" ).value_or (0 );
110
82
int64_t TimestampEnd =
111
83
TimestampBegin + TraceEventObj->getInteger (" dur" ).value_or (0 );
112
- std::string Name = TraceEventObj->getString (" name" ).value_or (" " ).str ();
113
- std::string Metadata = GetMetadata (TraceEventObj);
114
-
115
- // Source events are asynchronous events and may not perfectly nest the
116
- // synchronous events. Skip testing them.
117
- if (Name == " Source" )
118
- continue ;
84
+ StringRef Name = TraceEventObj->getString (" name" ).value_or (" " );
85
+ StringRef Detail = " " ;
86
+ if (json::Object *Args = TraceEventObj->getObject (" args" ))
87
+ Detail = Args->getString (" detail" ).value_or (" " );
119
88
120
89
// This is a "summary" event, like "Total PerformPendingInstantiations",
121
90
// skip it
122
91
if (TimestampBegin == 0 )
123
92
continue ;
124
93
125
94
Events.emplace_back (
126
- EventRecord{TimestampBegin, TimestampEnd, Name, Metadata });
95
+ EventRecord{TimestampBegin, TimestampEnd, Name, Detail });
127
96
}
128
97
129
98
// There can be nested events that are very fast, for example:
@@ -163,9 +132,9 @@ std::string buildTraceGraph(StringRef Json) {
163
132
Stream << " | " ;
164
133
}
165
134
Stream.write (Event.Name .data (), Event.Name .size ());
166
- if (!Event.Metadata .empty ()) {
135
+ if (!Event.Detail .empty ()) {
167
136
Stream << " (" ;
168
- Stream.write (Event.Metadata .data (), Event.Metadata .size ());
137
+ Stream.write (Event.Detail .data (), Event.Detail .size ());
169
138
Stream << " )" ;
170
139
}
171
140
Stream << " \n " ;
@@ -176,7 +145,7 @@ std::string buildTraceGraph(StringRef Json) {
176
145
} // namespace
177
146
178
147
TEST (TimeProfilerTest, ConstantEvaluationCxx20) {
179
- std::string Code = R"(
148
+ constexpr StringRef Code = R"(
180
149
void print(double value);
181
150
182
151
namespace slow_namespace {
@@ -206,7 +175,8 @@ constexpr int slow_init_list[] = {1, 1, 2, 3, 5, 8, 13, 21}; // 25th line
206
175
setupProfiler ();
207
176
ASSERT_TRUE (compileFromString (Code, " -std=c++20" , " test.cc" ));
208
177
std::string Json = teardownProfiler ();
209
- ASSERT_EQ (R"(
178
+ std::string TraceGraph = buildTraceGraph (Json);
179
+ ASSERT_TRUE (TraceGraph == R"(
210
180
Frontend
211
181
| ParseDeclarationOrFunctionDefinition (test.cc:2:1)
212
182
| ParseDeclarationOrFunctionDefinition (test.cc:6:1)
@@ -232,54 +202,14 @@ Frontend
232
202
| ParseDeclarationOrFunctionDefinition (test.cc:25:1)
233
203
| | EvaluateAsInitializer (slow_init_list)
234
204
| PerformPendingInstantiations
235
- )" ,
236
- buildTraceGraph (Json));
237
- }
238
-
239
- TEST (TimeProfilerTest, TemplateInstantiations) {
240
- std::string B_H = R"(
241
- template <typename T>
242
- T fooB(T t) {
243
- return T();
244
- }
205
+ )" );
245
206
246
- #define MacroTemp(x) template <typename T> void foo##x(T) { T(); }
247
- )" ;
248
-
249
- std::string A_H = R"(
250
- #include "b.h"
251
-
252
- MacroTemp(MTA)
253
-
254
- template <typename T>
255
- void fooA(T t) { fooB(t); fooMTA(t); }
256
- )" ;
257
- std::string Code = R"(
258
- #include "a.h"
259
- void user() { fooA(0); }
260
- )" ;
261
-
262
- setupProfiler ();
263
- ASSERT_TRUE (compileFromString (Code, " -std=c++20" , " test.cc" ,
264
- /* Headers=*/ {{" a.h" , A_H}, {" b.h" , B_H}}));
265
- std::string Json = teardownProfiler ();
266
- ASSERT_EQ (R"(
267
- Frontend
268
- | ParseFunctionDefinition (fooB)
269
- | ParseFunctionDefinition (fooMTA)
270
- | ParseFunctionDefinition (fooA)
271
- | ParseDeclarationOrFunctionDefinition (test.cc:3:5)
272
- | | ParseFunctionDefinition (user)
273
- | PerformPendingInstantiations
274
- | | InstantiateFunction (fooA<int>, ./a.h:7)
275
- | | | InstantiateFunction (fooB<int>, ./b.h:3)
276
- | | | InstantiateFunction (fooMTA<int>, ./a.h:4)
277
- )" ,
278
- buildTraceGraph (Json));
207
+ // NOTE: If this test is failing, run this test with
208
+ // `llvm::errs() << TraceGraph;` and change the assert above.
279
209
}
280
210
281
211
TEST (TimeProfilerTest, ConstantEvaluationC99) {
282
- std::string Code = R"(
212
+ constexpr StringRef Code = R"(
283
213
struct {
284
214
short quantval[4]; // 3rd line
285
215
} value;
@@ -288,12 +218,15 @@ struct {
288
218
setupProfiler ();
289
219
ASSERT_TRUE (compileFromString (Code, " -std=c99" , " test.c" ));
290
220
std::string Json = teardownProfiler ();
291
- ASSERT_EQ (R"(
221
+ std::string TraceGraph = buildTraceGraph (Json);
222
+ ASSERT_TRUE (TraceGraph == R"(
292
223
Frontend
293
224
| ParseDeclarationOrFunctionDefinition (test.c:2:1)
294
225
| | isIntegerConstantExpr (<test.c:3:18>)
295
226
| | EvaluateKnownConstIntCheckOverflow (<test.c:3:18>)
296
227
| PerformPendingInstantiations
297
- )" ,
298
- buildTraceGraph (Json));
228
+ )" );
229
+
230
+ // NOTE: If this test is failing, run this test with
231
+ // `llvm::errs() << TraceGraph;` and change the assert above.
299
232
}
0 commit comments