Skip to content

Commit

Permalink
Fortran: add capability to instrument pure procedures (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
zbeekman committed Feb 12, 2025
1 parent 24b53cc commit baac006
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 29 deletions.
58 changes: 58 additions & 0 deletions config_files/tau_pure_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Config variables:
# ${full_timer_name}: "function_name [file_path {start}-{end}]"

instrumentation: TAU
include:
- <Profile/Profiler.h>

main_insert:
- " TAU_PROFILE_TIMER(tautimer, \"${full_timer_name}\", \" \", TAU_DEFAULT);"
- " TAU_INIT(&argc, &argv);"
- "#ifndef TAU_MPI"
- "#ifndef TAU_SHMEM"
- " TAU_PROFILE_SET_NODE(0);"
- "#endif /* TAU_SHMEM */"
- "#endif /* TAU_MPI */"
- " TAU_PROFILE_START(tautimer);"

function_begin_insert:
- " TAU_PROFILE_TIMER(tautimer, \"${full_timer_name}\", \" \", TAU_USER);"
- " TAU_PROFILE_START(tautimer);"

function_end_insert:
- "TAU_PROFILE_STOP(tautimer);"

Fortran:
# Config variables:
# ${full_timer_name}: "procedure_name [file_path {start}-{end}]"
instrumentation: tauFortran
# use YAML block literal style with indentation indicators
# see https://stackoverflow.com/questions/3790454/how-do-i-break-a-string-in-yaml-over-multiple-lines
# Editors might complain about the indentation, but it is correct
program_insert:
- |-2
call TAU_START("${full_timer_name}&
&")
#ifndef TAU_MPI
call TAU_PROFILE_SET_NODE(0)
#endif
procedure_begin_insert:
- |-2
call TAU_START("${full_timer_name}&
&")
procedure_end_insert:
- |-2
call TAU_STOP("${full_timer_name}&
&")
pure_procedure_begin_insert:
- |-2
call TAU_START("&${full_timer_name}&
&")
pure_procedure_end_insert:
- |-2
call TAU_STOP("${full_timer_name}&
&")
23 changes: 17 additions & 6 deletions include/flang_instrumentation_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,25 @@ namespace salt::fortran {
private:
const std::string timerName_;
};
class ProcedureEndInstrumentationPoint final : public InstrumentationPoint {
public:
ProcedureEndInstrumentationPoint(const int line, std::string timerName) : InstrumentationPoint(
InstrumentationPointType::PROCEDURE_END, line, InstrumentationLocation::AFTER),
timerName_(std::move(timerName)) {
}

class ProcedureEndInstrumentationPoint final : public InstrumentationPoint {
public:
explicit ProcedureEndInstrumentationPoint(const int line) : InstrumentationPoint(
InstrumentationPointType::PROCEDURE_END, line, InstrumentationLocation::AFTER) {
}
};
[[nodiscard]] std::string timerName() const {
return timerName_;
}

[[nodiscard]] std::string toString() const override;

[[nodiscard]] std::string instrumentationString(const InstrumentationMap &instMap,
const std::string &lineText) const override;

private:
const std::string timerName_;
};
class ReturnStmtInstrumentationPoint final : public InstrumentationPoint {
public:
explicit ReturnStmtInstrumentationPoint(const int line) : InstrumentationPoint(
Expand Down
14 changes: 14 additions & 0 deletions src/flang_instrumentation_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ std::string salt::fortran::ProcedureBeginInstrumentationPoint::instrumentationSt
return std::regex_replace(instTemplate, timerNameRegex, timerName());
}

std::string salt::fortran::ProcedureEndInstrumentationPoint::toString() const {
std::stringstream ss;
ss << InstrumentationPoint::toString();
ss << "\"" << timerName() << "\"\t";
return ss.str();
}

std::string salt::fortran::ProcedureEndInstrumentationPoint::instrumentationString(
const InstrumentationMap &instMap, [[maybe_unused]] const std::string &lineText) const {
static std::regex timerNameRegex{SALT_FORTRAN_TIMER_NAME_TEMPLATE};
const std::string instTemplate{InstrumentationPoint::instrumentationString(instMap, lineText)};
return std::regex_replace(instTemplate, timerNameRegex, timerName());
}

std::string salt::fortran::IfReturnStmtInstrumentationPoint::toString() const {
std::stringstream ss;
ss << InstrumentationPoint::toString();
Expand Down
46 changes: 23 additions & 23 deletions src/flang_salt_instrument_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ namespace salt::fortran {
}
}

void addProcedureEndInstrumentation(const int end_line) {
void addProcedureEndInstrumentation(const int end_line, const std::string &timer_name) {
if (shouldInstrument()) {
instrumentationPoints_.emplace_back(std::make_unique<ProcedureEndInstrumentationPoint>(end_line));
instrumentationPoints_.emplace_back(
std::make_unique<ProcedureEndInstrumentationPoint>(end_line, timer_name));
}
}

Expand Down Expand Up @@ -280,34 +281,34 @@ namespace salt::fortran {

const auto &startLoc{startLocOpt.value()};
const auto &endLoc{endLocOpt.value()};
std::stringstream ss;
ss << (isInMainProgram_ ? mainProgramName_ : subprogramName_);
ss << " [{" << startLoc.sourceFile->path() << "} {";
ss << (isInMainProgram_ ? mainProgramLine_ : subProgramLine_);
ss << ",1}-{"; // TODO column number, first char of program/subroutine/function stmt
ss << endLoc.line + 1;
ss << ",1}]"; // TODO column number, last char of end stmt

const std::string timerName{ss.str()};

// Split the timerName string so that it will fit between Fortran 77's 72-character limit,
// and use character string line continuation syntax compatible with Fortran 77 and modern
// Fortran.
std::stringstream ss2;
for (size_t i = 0; i < timerName.size(); i += SALT_F77_LINE_LENGTH) {
ss2 << SALT_FORTRAN_STRING_SPLITTER;
ss2 << timerName.substr(i, SALT_F77_LINE_LENGTH);
}

const std::string splitTimerName{ss2.str()};
// Insert the timer start in the Pre phase (when we first visit the node)
// and the timer stop in the Post phase (when we return after visiting the node's children).
if (pre) {
// TODO this assumes that the program end statement ends the next line after
// the last statement, but there could be whitespace/comments. Need to actually
// find the end statement. End statement may not have source position if name
// not listed -- need to find workaround.
std::stringstream ss;
ss << (isInMainProgram_ ? mainProgramName_ : subprogramName_);
ss << " [{" << startLoc.sourceFile->path() << "} {";
ss << (isInMainProgram_ ? mainProgramLine_ : subProgramLine_);
ss << ",1}-{"; // TODO column number, first char of program/subroutine/function stmt
ss << endLoc.line + 1;
ss << ",1}]"; // TODO column number, last char of end stmt

const std::string timerName{ss.str()};

// Split the timerName string so that it will fit between Fortran 77's 72-character limit,
// and use character string line continuation syntax compatible with Fortran 77 and modern
// Fortran.
std::stringstream ss2;
for (size_t i = 0; i < timerName.size(); i += SALT_F77_LINE_LENGTH) {
ss2 << SALT_FORTRAN_STRING_SPLITTER;
ss2 << timerName.substr(i, SALT_F77_LINE_LENGTH);
}

const std::string splitTimerName{ss2.str()};

if (isInMainProgram_) {
verboseStream() << "Program begin \"" << mainProgramName_ << "\" at " << startLoc.line <<
Expand All @@ -323,7 +324,7 @@ namespace salt::fortran {
}
} else {
verboseStream() << "End at " << endLoc.line << ", " << endLoc.column << "\n";
addProcedureEndInstrumentation(endLoc.line);
addProcedureEndInstrumentation(endLoc.line, splitTimerName);
}
}
}
Expand Down Expand Up @@ -364,7 +365,6 @@ namespace salt::fortran {
};
verboseStream() << "If-return, conditional: (" << startPos.line << "," << startPos.column << ") - "
<< "(" << endPos.line << "," << endPos.column << ")\n";
// TODO handle return <value> case
// TODO handle multi-line
// TODO handle line continuation if too long
addIfReturnStmtInstrumentation(startPos.line, endPos.column);
Expand Down

0 comments on commit baac006

Please sign in to comment.