User Guide
perf.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <catch2/catch_test_macros.hpp>
9 #include <catch2/matchers/catch_matchers_string.hpp>
10 
11 #include "ast/program.hpp"
12 #include "parser/nmodl_driver.hpp"
15 
16 using namespace nmodl;
17 using namespace visitor;
18 
21 
22 
23 //=============================================================================
24 // Symtab and Perf visitor tests
25 //=============================================================================
26 
27 SCENARIO("Symbol table generation with Perf stat visitor", "[visitor][performance]") {
28  GIVEN("A mod file and associated ast") {
29  std::string nmodl_text = R"(
30  NEURON {
31  SUFFIX NaTs2_t
32  USEION na READ ena WRITE ina
33  RANGE gNaTs2_tbar, A_AMPA_step : range + anything = range (2)
34  GLOBAL Rstate : global + anything = global
35  POINTER rng : pointer = global
36  BBCOREPOINTER coreRng : pointer + assigned = range
37  }
38 
39  PARAMETER {
40  gNaTs2_tbar = 0.00001 (S/cm2) : range + parameter = range already
41  tau_r = 0.2 (ms) : parameter = global
42  tau_d_AMPA = 1.0 : parameter = global
43  tsyn_fac = 11.1 : parameter + assigned = range
44  }
45 
46  ASSIGNED {
47  v (mV) : only assigned = range
48  ena (mV) : only assigned = range
49  tsyn_fac : parameter + assigned = range already
50  A_AMPA_step : range + assigned = range already
51  AmState : only assigned = range
52  Rstate : global + assigned == global already
53  coreRng : pointer + assigned = range already
54  }
55 
56  STATE {
57  m : state = range
58  h : state = range
59  }
60 
61  BREAKPOINT {
62  CONDUCTANCE gNaTs2_t USEION na
63  SOLVE states METHOD cnexp
64  {
65  LOCAL gNaTs2_t
66  {
67  gNaTs2_t = gNaTs2_tbar*m*m*m*h
68  }
69  ina = gNaTs2_t*(v-ena)
70  }
71  {
72  m = hBetaf(11+v)
73  m = 12/gNaTs2_tbar
74  }
75  {
76  gNaTs2_tbar = gNaTs2_tbar*gNaTs2_tbar + 11.0
77  gNaTs2_tbar = 12.0
78  }
79  }
80 
81  FUNCTION hBetaf(v) {
82  hBetaf = (-0.015 * (-v -60))/(1-(exp((-v -60)/6)))
83  }
84  )";
85 
87  const auto& ast = driver.parse_string(nmodl_text);
88 
89  WHEN("Symbol table generator pass runs") {
90  SymtabVisitor v;
91  v.visit_program(*ast);
92  auto symtab = ast->get_model_symbol_table();
93 
94  THEN("Can lookup for defined variables") {
95  auto symbol = symtab->lookup("m");
96  REQUIRE(symbol->has_any_property(NmodlType::assigned_definition));
97  REQUIRE_FALSE(symbol->has_any_property(NmodlType::local_var));
98 
99  symbol = symtab->lookup("gNaTs2_tbar");
100  REQUIRE(symbol->has_any_property(NmodlType::param_assign));
101  REQUIRE(symbol->has_any_property(NmodlType::range_var));
102 
103  symbol = symtab->lookup("ena");
104  REQUIRE(symbol->has_any_property(NmodlType::read_ion_var));
105  }
106  THEN("Can lookup for defined functions") {
107  auto symbol = symtab->lookup("hBetaf");
108  REQUIRE(symbol->has_any_property(NmodlType::function_block));
109  }
110  THEN("Non existent variable lookup returns nullptr") {
111  REQUIRE(symtab->lookup("xyz") == nullptr);
112  }
113 
114  WHEN("Perf visitor pass runs after symtab visitor") {
115  PerfVisitor v;
116  v.visit_program(*ast);
117 
118  auto result = v.get_total_perfstat();
119  auto num_instance_var = v.get_instance_variable_count();
120  auto num_global_var = v.get_global_variable_count();
121  auto num_state_var = v.get_state_variable_count();
122  auto num_const_instance_var = v.get_const_instance_variable_count();
123  auto num_const_global_var = v.get_const_global_variable_count();
124 
125  THEN("Performance counters are updated") {
126  REQUIRE(result.n_add == 2);
127  REQUIRE(result.n_sub == 4);
128  REQUIRE(result.n_mul == 7);
129  REQUIRE(result.n_div == 3);
130  REQUIRE(result.n_exp == 1);
131  REQUIRE(result.n_global_read == 7);
132  REQUIRE(result.n_unique_global_read == 4);
133  REQUIRE(result.n_global_write == 3);
134  REQUIRE(result.n_unique_global_write == 2);
135  REQUIRE(result.n_constant_read == 4);
136  REQUIRE(result.n_unique_constant_read == 1);
137  REQUIRE(result.n_constant_write == 2);
138  REQUIRE(result.n_unique_constant_write == 1);
139  REQUIRE(result.n_local_read == 3);
140  REQUIRE(result.n_local_write == 2);
141  REQUIRE(result.n_ext_func_call == 1);
142  REQUIRE(result.n_int_func_call == 1);
143  REQUIRE(result.n_neg == 3);
144  REQUIRE(num_instance_var == 9);
145  REQUIRE(num_global_var == 4);
146  REQUIRE(num_state_var == 2);
147  REQUIRE(num_const_instance_var == 2);
148  REQUIRE(num_const_global_var == 2);
149  }
150  }
151  }
152 
153  WHEN("Perf visitor pass runs before symtab visitor") {
154  PerfVisitor v;
155  THEN("exception is thrown") {
156  REQUIRE_THROWS_WITH(v.visit_program(*ast),
157  Catch::Matchers::ContainsSubstring("table not setup"));
158  }
159  }
160  }
161 }
nmodl::parser::NmodlDriver
Class that binds all pieces together for parsing nmodl file.
Definition: nmodl_driver.hpp:67
perf_visitor.hpp
Visitor for measuring performance related information
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
SCENARIO
SCENARIO("Symbol table generation with Perf stat visitor", "[visitor][performance]")
Definition: perf.cpp:27
program.hpp
Auto generated AST classes declaration.
driver
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28
nmodl::parser::UnitDriver::parse_string
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
Definition: unit_driver.cpp:40
nmodl::symtab::syminfo::NmodlType
NmodlType
NMODL variable properties.
Definition: symbol_properties.hpp:116
nmodl_driver.hpp
symtab_visitor.hpp
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.