diff --git a/ClavaLaraApi/src-lara/clava/lara/code/Timer.lara b/ClavaLaraApi/src-lara/clava/lara/code/Timer.lara index a7243edeb..e0e84e2d1 100644 --- a/ClavaLaraApi/src-lara/clava/lara/code/Timer.lara +++ b/ClavaLaraApi/src-lara/clava/lara/code/Timer.lara @@ -17,8 +17,9 @@ Timer.prototype.addedDefines = new StringSet(); * @param $start [Mandatory] Starting point of the time measure * @param prefix Message that will appear before the time measure. If undefined, empty string will be used. * @param $end Ending point of the time measure. If undefined, measure is done around starting point. + * @param {String|$expr} $condition - If defined, adds an if statement wrapping the time measuring code. If a string, it is converted to a literal expression. */ -Timer.prototype.time = function($start, prefix, $end) { +Timer.prototype.time = function ($start, prefix, $end, $condition) { if (!this._timeValidate($start, $end, 'function')) { return; @@ -26,22 +27,19 @@ Timer.prototype.time = function($start, prefix, $end) { var $file = $start.ancestor('file'); - if($file === undefined) { - println("Could not find the corresponding file of the given joinpoint: " + $jp); - return; - }else if ($file.isCxx) { - return this._time_cpp($start, prefix, $end); + if ($file === undefined) { + println("Could not find the corresponding file of the given joinpoint: " + $jp); + return; + } else if ($file.isCxx) { + return this._time_cpp($start, prefix, $end, $condition); } else { - return this._time_c($start, prefix, $end); + return this._time_c($start, prefix, $end, $condition); } - - //return this; - //PrintOnce.message("Timer.time: not implemented yet for C"); } -Timer.prototype._time_cpp = function($start, prefix, $end) { - if (this.timeUnits.unit == this.timeUnits._timerUnit.DAYS){ +Timer.prototype._time_cpp = function ($start, prefix, $end, $condition) { + if (this.timeUnits.unit == this.timeUnits._timerUnit.DAYS) { throw "Timer Exception: Timer metrics not implemented for DAYS in C++"; } var logger = new Logger(false, this.filename); @@ -65,83 +63,81 @@ Timer.prototype._time_cpp = function($start, prefix, $end) { var startVar = IdGenerator.next("clava_timing_start_"); var endVar = IdGenerator.next("clava_timing_end_"); - var codeTic = _timer_cpp_now(startVar); - var codeToc = _timer_cpp_now(endVar); + var $codeTic = ClavaJoinPoints.stmtLiteral(_timer_cpp_now(startVar)); + var $codeToc = ClavaJoinPoints.stmtLiteral(_timer_cpp_now(endVar)); + var $insertionTic = $codeTic; + var $insertionToc = $codeToc; - var cppUnit = this.timeUnits.getCppTimeUnit(); - // Create literal node with calculation of time interval - $timingResult = ClavaJoinPoints.exprLiteral(_timer_cpp_calc_interval(startVar, endVar, cppUnit)); + if ($condition !== undefined) { + $insertionTic = ClavaJoinPoints.ifStmt($condition, $codeTic); + $insertionToc = ClavaJoinPoints.ifStmt($condition, $codeToc); + } + + var cppUnit = this.timeUnits.getCppTimeUnit(); // Declare variable for time interval, which uses calculation as initialization var timeIntervalVar = IdGenerator.next("clava_timing_duration_"); - $timingResultDecl = ClavaJoinPoints.varDecl(timeIntervalVar, $timingResult); + // Create literal node with calculation of time interval + $timingResult = ClavaJoinPoints.exprLiteral(_timer_cpp_calc_interval(startVar, endVar, cppUnit, timeIntervalVar)); + // Build message - logger.append(prefix).appendDouble(timeIntervalVar); + logger.append(prefix).appendLong(_timer_cpp_print_interval(cppUnit, timeIntervalVar)); if (this.printUnit) { logger.append(this.timeUnits.getUnitsString()); } logger.ln(); - - // Check if $start is a scope - if($start.instanceOf("scope")) { - // Insert code - $start.insertBegin(codeTic); - } else { - // Insert code - $start.insertBefore(codeTic); - } - - var afterJp = undefined; - - // Check if $end is a scope - if($end.instanceOf("scope")) { - // 'insertEnd' insertions must be done in sequential order - $end.insertEnd(codeToc); - afterJp = $end.insertEnd($timingResultDecl); - } else { - // 'insertAfter' insertions must be done in reverse order - afterJp = $end.insertAfter($timingResultDecl); - $end.insertAfter(codeToc); - } - /* - // If $start/$end parent do not have a statement ancestor, use insertBegin/End instead - if($start.ancestor("statement") === undefined || $end.ancestor("statement") === undefined) { - - // Insert code - $start.insertBegin(codeTic); - - // 'end' insertions must be done in sequential order - $end.insertEnd(codeToc); - $end.insertEnd($timingResultDecl); - - - } else { - // Insert code - $start.insertBefore(codeTic); - - // 'after' insertions must be done in reverse order - $end.insertAfter($timingResultDecl); - $end.insertAfter(codeToc); - } - */ + // Check if $start is a scope + if ($start.instanceOf("scope")) { + $start.insertBegin($insertionTic); + } else { + $start.insertBefore($insertionTic); + } + $startVarDecl = ClavaJoinPoints.stmtLiteral(_timer_cpp_define_time_var(startVar)); + $endVarDecl = ClavaJoinPoints.stmtLiteral(_timer_cpp_define_time_var(endVar)); + $timingResultDecl = ClavaJoinPoints.varDeclNoInit( + timeIntervalVar, + ClavaJoinPoints.typeLiteral("std::chrono::high_resolution_clock::duration") + ); + $insertionTic.insertBefore($startVarDecl); + $insertionTic.insertBefore($endVarDecl); + $insertionTic.insertBefore($timingResultDecl); + + + var afterJp = undefined; + + // Check if $end is a scope + if ($end.instanceOf("scope")) { + $end.insertEnd($insertionToc); + } else { + $end.insertAfter($insertionToc); + } + $codeToc.insertAfter($timingResult); + + if ($condition !== undefined) { + afterJp = $insertionToc; + } else { + afterJp = $timingResult; + } // Log time information - if(this.print) { - logger.log($timingResultDecl); - afterJp = logger.getAfterJp(); - } - - this._setAfterJp(afterJp); - - return timeIntervalVar; + if (this.print) { + logger.log($timingResult); + if ($condition === undefined) { + afterJp = logger.getAfterJp(); + } + } + + this._setAfterJp(afterJp); + + return timeIntervalVar; } -Timer.prototype._time_c = function($start, prefix, $end) { +Timer.prototype._time_c = function ($start, prefix, $end, $condition) { var logger = new Logger(false, this.filename); @@ -149,19 +145,19 @@ Timer.prototype._time_c = function($start, prefix, $end) { if (prefix === undefined) { prefix = ""; } - + if ($end === undefined) { $end = $start; } - + $file = $start.ancestor("file"); - - var codeBefore, codeAfter, timeIntervalVar; - + + var $varDecl, $codeBefore, $codeAfter, $timingResult; + // Declare variable for time interval, which uses calculation as initialization var timeIntervalVar = IdGenerator.next("clava_timing_duration_"); - var $timingResultDecl; + var $timingResultDecl = ClavaJoinPoints.varDeclNoInit(timeIntervalVar, ClavaJoinPoints.builtinType("double")); if (Platforms.isWindows()) { //use QueryPerformanceCounter // Add includes @@ -173,140 +169,139 @@ Timer.prototype._time_c = function($start, prefix, $end) { var endVar = IdGenerator.next("clava_timing_end_"); var frequencyVar = IdGenerator.next("clava_timing_frequency_"); - codeBefore = _timer_c_windows_declare_vars_now(startVar, endVar, frequencyVar); - codeAfter = _timer_c_windows_get_final_time(endVar); + $varDecl = ClavaJoinPoints.stmtLiteral(_timer_c_windows_declare_vars(startVar, endVar, frequencyVar)); + $codeBefore = ClavaJoinPoints.stmtLiteral(_timer_c_windows_get_time(startVar)); + $codeAfter = ClavaJoinPoints.stmtLiteral(_timer_c_windows_get_time(endVar)); - // Create literal node with calculation of time interval - $timingResult = ClavaJoinPoints.exprLiteral(_timer_c_windows_calc_interval(startVar, endVar, frequencyVar, this.timeUnits.getMagnitudeFactorFromSeconds()), ClavaJoinPoints.builtinType("double")); - $timingResultDecl = ClavaJoinPoints.varDecl(timeIntervalVar, $timingResult); + // Create literal node with calculation of time interval + $timingResult = ClavaJoinPoints.exprLiteral(_timer_c_windows_calc_interval(startVar, endVar, timeIntervalVar, frequencyVar, this.timeUnits.getMagnitudeFactorFromSeconds()), $timingResultDecl.type); } else if (Platforms.isLinux()) { // Add includes $file.exec addInclude("time.h", true); - - // If C99 or C11 standard, needs define at the beginning of the file - // https://stackoverflow.com/questions/42597685/storage-size-of-timespec-isnt-known - var needsDefine = Clava.getStandard() === "c99" || Clava.getStandard() === "c11"; - if(needsDefine && !this.addedDefines.has($file.location)) { - $file.exec insertBegin("#define _POSIX_C_SOURCE 199309L"); - this.addedDefines.add($file.location); - } - + + // If C99 or C11 standard, needs define at the beginning of the file + // https://stackoverflow.com/questions/42597685/storage-size-of-timespec-isnt-known + var needsDefine = Clava.getStandard() === "c99" || Clava.getStandard() === "c11"; + if (needsDefine && !this.addedDefines.has($file.location)) { + $file.exec insertBegin("#define _POSIX_C_SOURCE 199309L"); + this.addedDefines.add($file.location); + } + // get variable names var startVar = IdGenerator.next("clava_timing_start_"); var endVar = IdGenerator.next("clava_timing_end_"); - codeBefore = _timer_c_linux_declare_vars_now(startVar, endVar); - codeAfter = _timer_c_linux_get_final_time(endVar); + $varDecl = ClavaJoinPoints.stmtLiteral(_timer_c_linux_declare_vars(startVar, endVar)); + $codeBefore = ClavaJoinPoints.stmtLiteral(_timer_c_linux_get_time(startVar)); + $codeAfter = ClavaJoinPoints.stmtLiteral(_timer_c_linux_get_time(endVar)); // Create literal node with calculation of time interval - $timingResult = ClavaJoinPoints.exprLiteral(_timer_c_linux_calc_interval(startVar, endVar, this.timeUnits.getMagnitudeFactorFromSeconds()), ClavaJoinPoints.builtinType("double")); + $timingResult = ClavaJoinPoints.exprLiteral(_timer_c_linux_calc_interval(startVar, endVar, timeIntervalVar, this.timeUnits.getMagnitudeFactorFromSeconds()), $timingResultDecl.type); - $timingResultDecl = ClavaJoinPoints.varDecl(timeIntervalVar, $timingResult); - }else{ + } else { throw "Timer Exception: Platform not supported (Windows and Linux only)"; } - + // Build message logger.append(prefix).appendDouble(timeIntervalVar); if (this.printUnit) { logger.append(this.timeUnits.getUnitsString()); } logger.ln(); + + var $insertionTic = $codeBefore; + var $insertionToc = $codeAfter; + + if ($condition !== undefined) { + $insertionTic = ClavaJoinPoints.ifStmt($condition, $codeBefore); + $insertionToc = ClavaJoinPoints.ifStmt($condition, $codeAfter); + } + + // Check if $start is a scope + if ($start.instanceOf("scope")) { + // Insert code + $start.insertBegin($insertionTic); + } else { + // Insert code + $start.insertBefore($insertionTic); + } + $insertionTic.insertBefore($varDecl); + $insertionTic.insertBefore($timingResultDecl); - // Check if $start is a scope - if($start.instanceOf("scope")) { - // Insert code - $start.insertBegin(codeBefore); - } else { - // Insert code - $start.insertBefore(codeBefore); - } - - - var afterJp = undefined; - - // Check if $end is a scope - if($end.instanceOf("scope")) { - // 'insertEnd' insertions must be done in sequential order - $end.insertEnd(codeAfter); - afterJp = $end.insertEnd($timingResultDecl); - } else { - // 'insertAfter' insertions must be done in reverse order - afterJp = $end.insertAfter($timingResultDecl); - $end.insertAfter(codeAfter); - } -/* - // If $start/$end parent do not have a statement ancestor, use insertBegin/End instead - if($start.ancestor("statement") === undefined || $end.ancestor("statement") === undefined) { - - // Insert code - $start.insertBegin(codeBefore); - - // 'end' insertions must be done in sequential order - $end.insertEnd(codeAfter); - $end.insertEnd($timingResultDecl); - - } else { - // Insert code - $start.insertBefore(codeBefore); - - // 'after' insertions must be done in reverse order - $end.insertAfter($timingResultDecl); - $end.insertAfter(codeAfter); - } -*/ + var afterJp = undefined; + + // Check if $end is a scope + if ($end.instanceOf("scope")) { + $end.insertEnd($insertionToc); + } else { + $end.insertAfter($insertionToc); + } + afterJp = $codeAfter.insertAfter($timingResult); + + if ($condition !== undefined) { + afterJp = $insertionToc; + } else { + afterJp = $timingResult; + } // Log time information - if(this.print) { - logger.log($timingResultDecl); - afterJp = logger.getAfterJp(); - } - - this._setAfterJp(afterJp); - - return timeIntervalVar; + if (this.print) { + logger.log(afterJp); + afterJp = logger.getAfterJp(); + } + + this._setAfterJp(afterJp); + + return timeIntervalVar; } //C codedefs // Windows -codedef _timer_c_windows_declare_vars_now(timeStartVar, timeEndVar, timeFrequencyVar)%{ +codedef _timer_c_windows_declare_vars(timeStartVar, timeEndVar, timeFrequencyVar)%{ LARGE_INTEGER [[timeStartVar]], [[timeEndVar]], [[timeFrequencyVar]]; QueryPerformanceFrequency(&[[timeFrequencyVar]]); -QueryPerformanceCounter(&[[timeStartVar]]); }%end -codedef _timer_c_windows_get_final_time(timeEndVar)%{ -QueryPerformanceCounter(&[[timeEndVar]]); +codedef _timer_c_windows_get_time(timeVar)%{ +QueryPerformanceCounter(&[[timeVar]]); }%end -codedef _timer_c_windows_calc_interval(timeStartVar, timeEndVar, timeFrequencyVar, factorConversion)%{ -(([[timeEndVar]].QuadPart-[[timeStartVar]].QuadPart) / (double)[[timeFrequencyVar]].QuadPart) * ([[factorConversion]]) +codedef _timer_c_windows_calc_interval(timeStartVar, timeEndVar, timeDiffenceVar, timeFrequencyVar, factorConversion)%{ +[[timeDiffenceVar]] = (([[timeEndVar]].QuadPart - [[timeStartVar]].QuadPart) / (double)[[timeFrequencyVar]].QuadPart) * ([[factorConversion]]) }%end //Linux -codedef _timer_c_linux_declare_vars_now(timeStartVar, timeEndVar)%{ +codedef _timer_c_linux_declare_vars(timeStartVar, timeEndVar)%{ struct timespec [[timeStartVar]], [[timeEndVar]]; -clock_gettime(CLOCK_MONOTONIC, &[[timeStartVar]]); }%end -codedef _timer_c_linux_get_final_time(timeEndVar)%{ -clock_gettime(CLOCK_MONOTONIC, &[[timeEndVar]]); +codedef _timer_c_linux_get_time(timeVar)%{ +clock_gettime(CLOCK_MONOTONIC, &[[timeVar]]); }%end -codedef _timer_c_linux_calc_interval(timeStartVar, timeEndVar, factorConversion)%{ -(([[timeEndVar]].tv_sec + ((double) [[timeEndVar]].tv_nsec / 1000000000)) - ([[timeStartVar]].tv_sec + ((double) [[timeStartVar]].tv_nsec / 1000000000))) * ([[factorConversion]]) + +codedef _timer_c_linux_calc_interval(timeStartVar, timeEndVar, timeDiffenceVar, factorConversion)%{ +[[timeDiffenceVar]] = (([[timeEndVar]].tv_sec + ((double)[[timeEndVar]].tv_nsec / 1000000000)) - ([[timeStartVar]].tv_sec + ((double)[[timeStartVar]].tv_nsec / 1000000000))) * ([[factorConversion]]) }%end //Cpp codedefs +codedef _timer_cpp_define_time_var(timeVar)%{ +std::chrono::high_resolution_clock::time_point [[timeVar]]; +}%end + codedef _timer_cpp_now(timeVar)%{ -std::chrono::high_resolution_clock::time_point [[timeVar]] = std::chrono::high_resolution_clock::now(); +[[timeVar]] = std::chrono::high_resolution_clock::now(); +}%end + +codedef _timer_cpp_calc_interval(startVar, endVar, unit, differentialVar)%{ +[[differentialVar]] = [[endVar]] - [[startVar]] }%end -codedef _timer_cpp_calc_interval(startVar, endVar, unit)%{ -std::chrono::duration_cast([[endVar]] - [[startVar]]).count() +codedef _timer_cpp_print_interval(unit, differentialVar)%{ +std::chrono::duration_cast ([[differentialVar]]).count() }%end \ No newline at end of file