Skip to content

Commit fdd8254

Browse files
committed
add compilation times and execution-time
1 parent c5d0a76 commit fdd8254

File tree

6 files changed

+194
-15
lines changed

6 files changed

+194
-15
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ benchmarks/
3636
*.DS_Store
3737
external/*
3838
!external/custom-r
39-
.history
39+
.history
40+
profile

.vscode/settings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@
112112
"cfenv": "cpp",
113113
"csignal": "cpp",
114114
"__functional_base_03": "cpp",
115-
"__memory": "cpp"
115+
"__memory": "cpp",
116+
"typeindex": "cpp",
117+
"variant": "cpp"
116118
}
117119
}

rir/src/api.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include <memory>
2424
#include <string>
2525

26+
#include <chrono>
27+
#include <ctime>
28+
2629
using namespace rir;
2730

2831
extern "C" Rboolean R_Visible;
@@ -304,14 +307,22 @@ SEXP pirCompile(SEXP what, const Context& assumptions, const std::string& name,
304307
logger.title("Compiling " + name);
305308
pir::Compiler cmp(m, logger);
306309
pir::Backend backend(logger, name);
310+
auto start = std::chrono::system_clock::now();
311+
std::chrono::duration<double> duration;
312+
307313
cmp.compileClosure(what, name, assumptions, true,
308314
[&](pir::ClosureVersion* c) {
309315
logger.flush();
310316
cmp.optimizeModule();
311317

312318
auto fun = backend.getOrCompile(c);
319+
// Some computation here
320+
auto end = std::chrono::system_clock::now();
321+
322+
duration = end - start;
313323

314-
ContextualProfiling::countSuccessfulCompilation(what,assumptions);
324+
325+
ContextualProfiling::countSuccessfulCompilation(what,assumptions,duration);
315326

316327
// Install
317328
if (dryRun)
@@ -321,7 +332,10 @@ SEXP pirCompile(SEXP what, const Context& assumptions, const std::string& name,
321332
DispatchTable::unpack(BODY(what))->insert(fun);
322333
},
323334
[&]() {
324-
ContextualProfiling::countFailedCompilation(what,assumptions);
335+
auto end = std::chrono::system_clock::now();
336+
337+
duration = end - start;
338+
ContextualProfiling::countFailedCompilation(what,assumptions,duration);
325339
if (debug.includes(pir::DebugFlag::ShowWarnings))
326340
std::cerr << "Compilation failed\n";
327341
},

rir/src/interpreter/interp.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ RIR_INLINE SEXP rirCall(CallContext& call, InterpreterInstance* ctx) {
10711071
Context lContext = call.givenContext;
10721072
// For Logger -- END
10731073

1074-
if (!isDeoptimizing() && RecompileHeuristic(table, fun)) {
1074+
if (ContextualProfiling::compileFlag(lMethodId, lContext) && !isDeoptimizing() && RecompileHeuristic(table, fun)) {
10751075
Context given = call.givenContext;
10761076
// addDynamicAssumptionForOneTarget compares arguments with the
10771077
// signature of the current dispatch target. There the number of
@@ -1094,6 +1094,8 @@ RIR_INLINE SEXP rirCall(CallContext& call, InterpreterInstance* ctx) {
10941094
*fun
10951095
);
10961096

1097+
auto start = std::chrono::system_clock::now(); // runtime start
1098+
10971099
bool needsEnv = fun->signature().envCreation ==
10981100
FunctionSignature::Environment::CallerProvided;
10991101

@@ -1102,12 +1104,16 @@ RIR_INLINE SEXP rirCall(CallContext& call, InterpreterInstance* ctx) {
11021104
call.depromiseArgs();
11031105
}
11041106

1107+
11051108
LazyArglistOnStack lazyPromargs(
11061109
call.callId,
11071110
call.caller ? call.caller->arglistOrderContainer() : nullptr,
11081111
call.suppliedArgs, call.stackArgs, call.ast);
11091112

1113+
11101114
SEXP result;
1115+
1116+
std::chrono::duration<double> duration;
11111117
if (!needsEnv) {
11121118
// Default fast calling convention for pir, environment is created by
11131119
// the callee
@@ -1129,6 +1135,18 @@ RIR_INLINE SEXP rirCall(CallContext& call, InterpreterInstance* ctx) {
11291135
}
11301136
assert(result);
11311137
assert(!fun->flags.contains(Function::Deopt));
1138+
1139+
1140+
auto end = std::chrono::system_clock::now();
1141+
duration = end - start;
1142+
1143+
ContextualProfiling::addFunctionDispatchRuntime(
1144+
lMethodId,
1145+
lContext,
1146+
*fun,
1147+
duration
1148+
);
1149+
11321150
return result;
11331151
}
11341152

rir/src/utils/ContextualProfiling.cpp

Lines changed: 134 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,14 @@ namespace rir {
6060
int call_count_in_ctxt = 0;
6161
int successful_compilation_count = 0;
6262
int failed_compilation_count = 0;
63+
double time_spent_in_compilation = 0;
64+
double time_wasted_in_compilation = 0;
6365
// Count the number of time the version for the context C
6466
// has been called in this context in
6567
// version_called_count[C]
6668
unordered_map<Context, int> version_called_count;
69+
unordered_map<Context, int> version_success_run_count;
70+
unordered_map<Context, double> version_runtime;
6771
};
6872

6973
class Entry {
@@ -88,7 +92,7 @@ namespace rir {
8892
string runId = runId_ss.str();
8993

9094
myfile.open("profile/" + runId + ".csv");
91-
myfile << "ID,NAME,CONTEXT,N_CALL,CMP_SUCCESS,CMP_FAIL,DISPATCHED FUNCTIONS\n";
95+
myfile << "ID,NAME,CONTEXT,N_CALL,TOTAL_RUNTIME,CMP_SUCCESS,SUCCESS_TIME,CMP_FAIL,FAIL_TIME,GOODNESS,DISPATCHED FUNCTIONS\n";
9296
}
9397

9498
static size_t getEntryKey(SEXP callee) {
@@ -186,30 +190,71 @@ namespace rir {
186190
ctxt_data.version_called_count[version_context]++;
187191
}
188192

193+
void addFunctionDispatchRuntime(
194+
size_t id,
195+
Context call_context,
196+
Function const & f,
197+
std::chrono::duration<double> duration
198+
) {
199+
Context version_context = f.context();
200+
201+
// find entry for this function
202+
// entry must have been previously created by a call to createEntry
203+
auto & entry = entries.at(id);
204+
205+
// create or get call context data
206+
auto & ctxt_data = entry.dispatch_data[call_context];
207+
208+
// count one call in the context callContextId to version compiled for funContextId
209+
210+
ctxt_data.version_success_run_count[version_context]++;
211+
ctxt_data.version_runtime[version_context] += duration.count();
212+
}
213+
189214
// For the two functions below: function entry must have been previously
190215
// created by createEntry, context entry may not exist yet
191216
void countSuccessfulCompilation(
192217
SEXP callee,
193-
Context call_ctxt
218+
Context call_ctxt,
219+
std::chrono::duration<double> duration
194220
) {
195221
size_t entry_key = getEntryKey(callee);
196222

197223
auto & entry = entries.at(entry_key);
198224
auto & dispatch_data = entry.dispatch_data[call_ctxt];
199225

200226
dispatch_data.successful_compilation_count++;
227+
228+
dispatch_data.time_spent_in_compilation += duration.count();
229+
230+
}
231+
232+
bool compileOnlyOnce(
233+
size_t entry_key,
234+
Context call_context
235+
) {
236+
auto & entry = entries.at(entry_key);
237+
auto & dispatch_data = entry.dispatch_data[call_context];
238+
239+
if(dispatch_data.successful_compilation_count > 0 || dispatch_data.failed_compilation_count > 0) {
240+
return false;
241+
} else {
242+
return true;
243+
}
201244
}
202245

203246
void countFailedCompilation(
204247
SEXP callee,
205-
Context call_ctxt
248+
Context call_ctxt,
249+
std::chrono::duration<double> duration
206250
) {
207251
size_t entry_key = getEntryKey(callee);
208252

209253
auto & entry = entries.at(entry_key);
210254
auto & dispatch_data = entry.dispatch_data[call_ctxt];
211255

212256
dispatch_data.failed_compilation_count++;
257+
dispatch_data.time_wasted_in_compilation += duration.count();
213258
}
214259

215260

@@ -329,6 +374,7 @@ namespace rir {
329374
}
330375

331376
~FileLogger() {
377+
double total_time_in_compilation = 0;
332378
for (auto const & ir : entries) {
333379
auto fun_id = ir.first;
334380
auto & entry = ir.second;
@@ -344,6 +390,12 @@ namespace rir {
344390

345391
stringstream contextsDispatched;
346392

393+
double totalRuntimeUnderContext = 0;
394+
395+
double goodness = false;
396+
double baselineAvgRuntime = 0;
397+
int otherRuntimeCount = 0;
398+
double otherAvgRuntime = 0;
347399

348400
// iterate over dispatched functions under this context
349401
for (auto const & itr1 : dispatch_data.version_called_count) {
@@ -352,7 +404,32 @@ namespace rir {
352404
int functionContextCallCount = itr1.second; // current function context __call count
353405
string currContextString = getContextString(version_context); // current function context __string
354406

355-
contextsDispatched << "[" << functionContextCallCount << "]" << currContextString << " ";
407+
unordered_map<Context, int> version_success_run_count = dispatch_data.version_success_run_count;
408+
unordered_map<Context, double> version_runtime = dispatch_data.version_runtime;
409+
410+
double success_runs = version_success_run_count[version_context];
411+
double success_runtime = version_runtime[version_context];
412+
double avg_runtime = 0;
413+
totalRuntimeUnderContext += success_runtime;
414+
415+
if(success_runs > 0) {
416+
avg_runtime = success_runtime / success_runs;
417+
}
418+
bool baseline = version_context.toI() == 0 ? true : false;
419+
420+
if(baseline) {
421+
baselineAvgRuntime = avg_runtime;
422+
} else {
423+
otherRuntimeCount++;
424+
otherAvgRuntime += avg_runtime;
425+
}
426+
427+
contextsDispatched << "[" << functionContextCallCount << "]{" << avg_runtime << "}" << currContextString << " ";
428+
}
429+
otherAvgRuntime = otherAvgRuntime / otherRuntimeCount;
430+
total_time_in_compilation += dispatch_data.time_spent_in_compilation;
431+
if(otherAvgRuntime < baselineAvgRuntime) {
432+
goodness = true;
356433
}
357434
// print row
358435
myfile
@@ -364,14 +441,33 @@ namespace rir {
364441
<< del
365442
<< dispatch_data.call_count_in_ctxt // call context count
366443
<< del
444+
<< totalRuntimeUnderContext // total runtime under context
445+
<< del
367446
<< dispatch_data.successful_compilation_count // number of successful compilations in this context
368447
<< del
448+
<< dispatch_data.time_spent_in_compilation // time spent for successful compilation
449+
<< del
369450
<< dispatch_data.failed_compilation_count // number of failed compilations in this context
370451
<< del
452+
<< dispatch_data.time_wasted_in_compilation // time wasted trying to compile
453+
<< del
454+
<< goodness
455+
<< del
371456
<< contextsDispatched.str() // functions dispatched under this context
372457
<< "\n";
373458
}
374459
}
460+
myfile
461+
<< del
462+
<< del
463+
<< del
464+
<< del
465+
<< del
466+
<< total_time_in_compilation // Total time in compilation
467+
<< del
468+
<< del
469+
<< del
470+
<< "\n";
375471
myfile.close();
376472
}
377473

@@ -420,21 +516,51 @@ void ContextualProfiling::addFunctionDispatchInfo(
420516

421517
void ContextualProfiling::countSuccessfulCompilation(
422518
SEXP callee,
423-
Context assumptions
519+
Context assumptions,
520+
std::chrono::duration<double> duration
424521
) {
425522
if (fileLogger) {
426-
fileLogger->countSuccessfulCompilation(callee, assumptions);
523+
fileLogger->countSuccessfulCompilation(callee, assumptions, duration);
427524
}
428525
}
429526

430527
void ContextualProfiling::countFailedCompilation(
431528
SEXP callee,
432-
Context assumptions
529+
Context assumptions,
530+
std::chrono::duration<double> duration
433531
) {
434532
if (fileLogger) {
435-
fileLogger->countFailedCompilation(callee, assumptions);
533+
fileLogger->countFailedCompilation(callee, assumptions, duration);
436534
}
437535
}
438536

537+
bool ContextualProfiling::compileFlag(
538+
size_t id,
539+
Context contextCaller
540+
) {
541+
if (getenv("SKIP_ALL_COMPILATION")) {
542+
return false;
543+
}
544+
if (!getenv("COMPILE_ONLY_ONCE")) {
545+
return true;
546+
}
547+
if (fileLogger) {
548+
return fileLogger->compileOnlyOnce(id, contextCaller);
549+
} else {
550+
return true;
551+
}
552+
}
553+
554+
void ContextualProfiling::addFunctionDispatchRuntime(
555+
size_t id,
556+
Context contextCaller,
557+
Function const &f,
558+
std::chrono::duration<double> duration
559+
560+
) {
561+
if(fileLogger) {
562+
return fileLogger->addFunctionDispatchRuntime(id, contextCaller, f, duration);
563+
}
564+
}
439565

440566
} // namespace rir

0 commit comments

Comments
 (0)