Skip to content

Commit

Permalink
Blame NMODL for lines it's generating.
Browse files Browse the repository at this point in the history
Adds

    nmodl MOD_FILE blame --line LINE

which will cause NMODL to print a backtrace every time it writes to line
`LINE`.

This is very helpful when trying to find the NMODL code responsible for
printing a (faulty) line of code.
  • Loading branch information
1uc committed Feb 26, 2024
1 parent b10adb6 commit cf89870
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 24 deletions.
1 change: 1 addition & 0 deletions .github/workflows/nmodl-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ jobs:
fi
cmake_args+=(-DCMAKE_CXX_COMPILER=${CXX} \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache)
cmake_args+=(-DNMODL_ENABLE_BACKWARD=On)
cmake .. "${cmake_args[@]}"
env:
INSTALL_DIR: ${{ runner.workspace }}/install
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@
[submodule "ext/catch2"]
path = ext/catch2
url = https://github.com/catchorg/Catch2.git
[submodule "ext/backward"]
path = ext/backward
url = https://github.com/bombela/backward-cpp.git
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ option(NMODL_ENABLE_PYTHON_BINDINGS "Enable pybind11 based python bindings" ON)
option(NMODL_ENABLE_TESTS "Enable build of tests" ON)
option(NMODL_ENABLE_USECASES
"If building tests, additionally enable build of usecase tests. Requires neuron." OFF)
option(NMODL_ENABLE_BACKWARD "Use backward, enables blame." OFF)
set(NMODL_EXTRA_CXX_FLAGS
""
CACHE STRING "Add extra compile flags for NMODL sources")
Expand Down Expand Up @@ -131,6 +132,10 @@ if(NMODL_3RDPARTY_USE_SPDLOG)
endif()
cpp_cc_git_submodule(spdlog BUILD PACKAGE spdlog REQUIRED)

if(NMODL_ENABLE_BACKWARD)
cpp_cc_git_submodule(backward BUILD PACKAGE backward REQUIRED)
endif()

# =============================================================================
# Format & execute ipynb notebooks in place (pip install nbconvert clean-ipynb)
# =============================================================================
Expand Down
1 change: 1 addition & 0 deletions ext/backward
Submodule backward added at 51f070
11 changes: 7 additions & 4 deletions src/codegen/codegen_cpp_visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,10 @@ class CodegenCppVisitor: public visitor::ConstAstVisitor {
CodegenCppVisitor(std::string mod_filename,
const std::string& output_dir,
std::string float_type,
const bool optimize_ionvar_copies)
: printer(std::make_unique<CodePrinter>(output_dir + "/" + mod_filename + ".cpp"))
const bool optimize_ionvar_copies,
size_t blame_line = 0)
: printer(
std::make_unique<CodePrinter>(output_dir + "/" + mod_filename + ".cpp", blame_line))
, mod_filename(std::move(mod_filename))
, float_type(std::move(float_type))
, optimize_ionvar_copies(optimize_ionvar_copies) {}
Expand All @@ -224,8 +226,9 @@ class CodegenCppVisitor: public visitor::ConstAstVisitor {
CodegenCppVisitor(std::string mod_filename,
std::ostream& stream,
std::string float_type,
const bool optimize_ionvar_copies)
: printer(std::make_unique<CodePrinter>(stream))
const bool optimize_ionvar_copies,
size_t blame_line = 0)
: printer(std::make_unique<CodePrinter>(stream, blame_line))
, mod_filename(std::move(mod_filename))
, float_type(std::move(float_type))
, optimize_ionvar_copies(optimize_ionvar_copies) {}
Expand Down
26 changes: 14 additions & 12 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ int main(int argc, const char* argv[]) {
/// floating point data type
std::string data_type("double");

/// which line to run blame for
size_t blame_line = 0;

// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
app.get_formatter()->column_width(40);
app.set_help_all_flag("-H,--help-all", "Print this help message including all sub-commands");
Expand Down Expand Up @@ -269,6 +272,11 @@ int main(int argc, const char* argv[]) {
optimize_ionvar_copies_codegen,
fmt::format("Optimize copies of ion variables ({})", optimize_ionvar_copies_codegen))->ignore_case();

#if NMODL_ENABLE_BACKWARD
auto blame_opt = app.add_subcommand("blame", "Blame NMODL code that generated some code.");
blame_opt->add_option("--line", blame_line, "Justify why this line was generated.");
#endif

// clang-format on

CLI11_PARSE(app, argc, argv);
Expand Down Expand Up @@ -538,28 +546,22 @@ int main(int argc, const char* argv[]) {
{
if (coreneuron_code && oacc_backend) {
logger->info("Running OpenACC backend code generator for CoreNEURON");
CodegenAccVisitor visitor(modfile,
output_dir,
data_type,
optimize_ionvar_copies_codegen);
CodegenAccVisitor visitor(
modfile, output_dir, data_type, optimize_ionvar_copies_codegen, blame_line);
visitor.visit_program(*ast);
}

else if (coreneuron_code && !neuron_code && cpp_backend) {
logger->info("Running C++ backend code generator for CoreNEURON");
CodegenCoreneuronCppVisitor visitor(modfile,
output_dir,
data_type,
optimize_ionvar_copies_codegen);
CodegenCoreneuronCppVisitor visitor(
modfile, output_dir, data_type, optimize_ionvar_copies_codegen, blame_line);
visitor.visit_program(*ast);
}

else if (neuron_code && cpp_backend) {
logger->info("Running C++ backend code generator for NEURON");
CodegenNeuronCppVisitor visitor(modfile,
output_dir,
data_type,
optimize_ionvar_copies_codegen);
CodegenNeuronCppVisitor visitor(
modfile, output_dir, data_type, optimize_ionvar_copies_codegen, blame_line);
visitor.visit_program(*ast);
}

Expand Down
6 changes: 5 additions & 1 deletion src/printer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
# =============================================================================
add_library(printer OBJECT code_printer.cpp json_printer.cpp nmodl_printer.cpp)
set_property(TARGET printer PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(printer PRIVATE util)

if(NMODL_ENABLE_BACKWARD)
target_link_libraries(printer PRIVATE util Backward::Interface)
target_compile_definitions(printer PUBLIC NMODL_ENABLE_BACKWARD=1)
endif()
26 changes: 24 additions & 2 deletions src/printer/code_printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
#include "printer/code_printer.hpp"
#include "utils/string_utils.hpp"

#if NMODL_ENABLE_BACKWARD
#include <backward.hpp>
#endif

namespace nmodl {
namespace printer {

CodePrinter::CodePrinter(const std::string& filename) {
CodePrinter::CodePrinter(const std::string& filename, size_t blame_line)
: blame_line(blame_line) {
if (filename.empty()) {
throw std::runtime_error("Empty filename for CodePrinter");
}
Expand Down Expand Up @@ -88,8 +93,9 @@ void CodePrinter::add_multi_line(const std::string& text) {
}

void CodePrinter::add_newline(std::size_t n) {
for (std::size_t i{}; i < n; ++i) {
for (std::size_t i = 0; i < n; ++i) {
*result << '\n';
++current_line;
}
}

Expand All @@ -110,5 +116,21 @@ void CodePrinter::pop_block(const std::string_view& suffix, std::size_t num_newl
add_newline(num_newlines);
}

void CodePrinter::blame() {
#if NMODL_ENABLE_BACKWARD
if (current_line == blame_line) {
*result << std::flush;

std::cout << "\n\n== Blame =======================================================\n";

backward::StackTrace st;
st.load_here(32);
backward::Printer p;
p.print(st, std::cout);
}
#endif
}


} // namespace printer
} // namespace nmodl
19 changes: 14 additions & 5 deletions src/printer/code_printer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,21 @@ class CodePrinter {
std::ofstream ofs;
std::streambuf* sbuf = nullptr;
std::unique_ptr<std::ostream> result;
size_t current_line = 1;
size_t blame_line = 0;
size_t indent_level = 0;
const size_t NUM_SPACES = 4;

public:
CodePrinter()
: result(std::make_unique<std::ostream>(std::cout.rdbuf())) {}
CodePrinter(size_t blame_line = 0)
: result(std::make_unique<std::ostream>(std::cout.rdbuf()))
, blame_line(blame_line) {}

CodePrinter(std::ostream& stream)
: result(std::make_unique<std::ostream>(stream.rdbuf())) {}
CodePrinter(std::ostream& stream, size_t blame_line = 0)
: result(std::make_unique<std::ostream>(stream.rdbuf()))
, blame_line(blame_line) {}

CodePrinter(const std::string& filename);
CodePrinter(const std::string& filename, size_t blame_line = 0);

~CodePrinter() {
ofs.close();
Expand All @@ -74,6 +78,7 @@ class CodePrinter {

template <typename... Args>
void add_text(Args&&... args) {
blame();
(operator<<(*result, args), ...);
}

Expand Down Expand Up @@ -127,6 +132,10 @@ class CodePrinter {
int indent_spaces() {
return NUM_SPACES * indent_level;
}

private:
/// Blame when on the requested line.
void blame();
};

/** @} */ // end of printer
Expand Down

0 comments on commit cf89870

Please sign in to comment.