NEURON
perf_visitor.hpp
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 #pragma once
9 
10 /**
11  * \file
12  * \brief \copybrief nmodl::visitor::PerfVisitor
13  */
14 
15 #include <map>
16 #include <set>
17 #include <stack>
18 
19 #include "printer/decl.hpp"
20 #include "symtab/decl.hpp"
21 #include "utils/perf_stat.hpp"
22 #include "visitors/ast_visitor.hpp"
23 
24 
25 namespace nmodl {
26 namespace visitor {
27 
28 /**
29  * \addtogroup visitor_classes
30  * \{
31  */
32 
33 /**
34  * \class PerfVisitor
35  * \brief %Visitor for measuring performance related information
36  *
37  * This visitor used to visit the ast and associated symbol tables
38  * to measure the performance of every block in nmodl file. For
39  * every symbol in associated symbol table, read/write count
40  * is updated which will be used during code generation (to select
41  * memory types). Certain statements like useion, valence etc.
42  * are not executed in the translated C code and hence need to
43  * be skipped (i.e. without visiting children). Note that this
44  * pass must be run after symbol table generation pass.
45  *
46  * \todo
47  * - To measure the performance of statements like if, elseif
48  * and else, we have to find maximum performance from if,elseif,else
49  * and then use it to calculate total performance. In the current
50  * implementation we are doing sum of all blocks. We need to override
51  * IfStatement (which has all sub-blocks) and get maximum performance
52  * of all statements recursively.
53  *
54  * - In order to avoid empty implementations and checking
55  * start_measurement, there should be "empty" ast visitor from
56  * which PerfVisitor should be inherited.
57  */
59  private:
60  /// symbol table of current block being visited
62 
63  /// performance stats of all blocks being visited
64  /// in recursive chain
65  std::stack<utils::PerfStat> blocks_perf;
66 
67  /// total performance of mod file
69 
70  /// performance of current block
72 
73  /// performance of current all childrens
74  std::stack<utils::PerfStat> children_blocks_perf;
75 
76  /// whether to measure performance for current block
77  bool start_measurement = false;
78 
79  /// true while visiting lhs of binary expression
80  /// (to count write operations)
82 
83  /// whether function call is being visited
84  bool under_function_call = false;
85 
86  /// whether solve block is being visited
87  bool under_solve_block = false;
88 
89  /// whether net receive block is being visited
91 
92  /// to print to json file
93  std::unique_ptr<printer::JSONPrinter> printer;
94 
95  /// if not json, all goes to string
96  std::stringstream stream;
97 
98  /// count of per channel instance variables
100 
101  /// subset of instance variables which are constant
103 
104  /// subset of instance variables which are localized
106 
107  /// count of global variables
109 
110  /// subset of global variables which are constant
112 
113  /// subset of global variables which are localized
115 
116  /// count of state variables
118 
119  /// count of pointer / bbcorepointer variables
121 
122  /// count of RANDOM variables
124 
125  /// keys used in map to track var usage
126  std::string const_memr_key = "cm_r_u";
127  std::string const_memw_key = "cm_w_u";
128  std::string global_memr_key = "gm_r_u";
129  std::string global_memw_key = "gm_w_u";
130 
131  /// map of variables to count unique read-writes
132  std::map<std::string, std::set<std::string>> var_usage = {{const_memr_key, {}},
133  {const_memw_key, {}},
134  {global_memr_key, {}},
135  {global_memw_key, {}}};
136 
137  void update_memory_ops(const std::string& name);
138 
139  bool symbol_to_skip(const std::shared_ptr<symtab::Symbol>& symbol) const;
140 
141  static bool is_local_variable(const std::shared_ptr<symtab::Symbol>& symbol);
142 
143  static bool is_constant_variable(const std::shared_ptr<symtab::Symbol>& symbol);
144 
145  void count_variables();
146 
147  void measure_performance(const ast::Ast& node);
148 
149  void print_memory_usage();
150 
151  void add_perf_to_printer(const utils::PerfStat& perf) const;
152 
153  public:
154  PerfVisitor() = default;
155 
156  explicit PerfVisitor(const std::string& filename);
157 
158  void compact_json(bool flag);
159 
160  const utils::PerfStat& get_total_perfstat() const noexcept {
161  return total_perf;
162  }
163 
164  int get_instance_variable_count() const noexcept {
165  return num_instance_variables;
166  }
167 
168  int get_const_instance_variable_count() const noexcept {
170  }
171 
172  int get_const_global_variable_count() const noexcept {
174  }
175 
176  int get_global_variable_count() const noexcept {
177  return num_global_variables;
178  }
179 
180  int get_state_variable_count() const noexcept {
181  return num_state_variables;
182  }
183 
184  void visit_binary_expression(const ast::BinaryExpression& node) override;
185 
186  void visit_function_call(const ast::FunctionCall& node) override;
187 
188  void visit_name(const ast::Name& node) override;
189 
190  void visit_prime_name(const ast::PrimeName& node) override;
191 
192  void visit_solve_block(const ast::SolveBlock& node) override;
193 
194  void visit_statement_block(const ast::StatementBlock& node) override;
195 
196  void visit_unary_expression(const ast::UnaryExpression& node) override;
197 
198  void visit_if_statement(const ast::IfStatement& node) override;
199 
200  void visit_else_if_statement(const ast::ElseIfStatement& node) override;
201 
202  void visit_program(const ast::Program& node) override;
203 
204  /// skip initial block under net_receive block
205  void visit_initial_block(const ast::InitialBlock& node) override;
206 
207  void visit_constructor_block(const ast::ConstructorBlock& node) override;
208 
209  void visit_destructor_block(const ast::DestructorBlock& node) override;
210 
211  void visit_derivative_block(const ast::DerivativeBlock& node) override;
212 
213  void visit_linear_block(const ast::LinearBlock& node) override;
214 
215  void visit_non_linear_block(const ast::NonLinearBlock& node) override;
216 
217  void visit_discrete_block(const ast::DiscreteBlock& node) override;
218 
220 
221  void visit_function_block(const ast::FunctionBlock& node) override;
222 
223  void visit_procedure_block(const ast::ProcedureBlock& node) override;
224 
225  void visit_net_receive_block(const ast::NetReceiveBlock& node) override;
226 
227  void visit_breakpoint_block(const ast::BreakpointBlock& node) override;
228 
229  void visit_before_block(const ast::BeforeBlock& node) override;
230 
231  void visit_after_block(const ast::AfterBlock& node) override;
232 
233  void visit_ba_block(const ast::BABlock& node) override;
234 
235  void visit_for_netcon(const ast::ForNetcon& node) override;
236 
237  void visit_kinetic_block(const ast::KineticBlock& node) override;
238 
239  /// certain constructs needs to be excluded from usage counting
240  /// and hence need to provide empty implementations
241 
242  void visit_conductance_hint(const ast::ConductanceHint& /*node*/) override {}
243 
244  void visit_local_list_statement(const ast::LocalListStatement& /*node*/) override {}
245 
246  void visit_suffix(const ast::Suffix& /*node*/) override {}
247 
248  void visit_useion(const ast::Useion& /*node*/) override {}
249 
250  void visit_valence(const ast::Valence& /*node*/) override {}
251 
252  void print(std::ostream& ss) const {
253  ss << stream.str();
254  }
255 };
256 
257 /** \} */ // end of visitor_classes
258 
259 } // namespace visitor
260 } // namespace nmodl
Concrete visitor for all AST classes.
Represents a AFTER block in NMODL.
Definition: after_block.hpp:51
Represents a block to be executed before or after another block.
Definition: ba_block.hpp:40
Represents a BEFORE block in NMODL.
Represents binary expression in the NMODL.
Represents a BREAKPOINT block in NMODL.
Represents CONDUCTANCE statement in NMODL.
Represents a CONSTRUCTOR block in the NMODL.
Represents DERIVATIVE block in the NMODL.
Represents a DESTRUCTOR block in the NMODL.
Represents a INITIAL block in the NMODL.
Represents LINEAR block in the NMODL.
Represents a name.
Definition: name.hpp:44
Represents NONLINEAR block in the NMODL.
Represents a prime variable (for ODE)
Definition: prime_name.hpp:48
Represents top level AST node for whole NMODL input.
Definition: program.hpp:39
Represents block encapsulating list of statements.
Represents SUFFIX statement in NMODL.
Definition: suffix.hpp:38
Represents USEION statement in NMODL.
Definition: useion.hpp:40
Represent symbol table for a NMODL block.
Concrete constant visitor for all AST classes.
Visitor for measuring performance related information
int get_const_global_variable_count() const noexcept
void visit_valence(const ast::Valence &) override
visit node of type ast::Valence
void visit_ba_block(const ast::BABlock &node) override
visit node of type ast::BABlock
void visit_program(const ast::Program &node) override
visit node of type ast::Program
static bool is_constant_variable(const std::shared_ptr< symtab::Symbol > &symbol)
void compact_json(bool flag)
void visit_local_list_statement(const ast::LocalListStatement &) override
visit node of type ast::LocalListStatement
void visit_initial_block(const ast::InitialBlock &node) override
skip initial block under net_receive block
int num_pointer_variables
count of pointer / bbcorepointer variables
void visit_useion(const ast::Useion &) override
visit node of type ast::Useion
int get_state_variable_count() const noexcept
void visit_constructor_block(const ast::ConstructorBlock &node) override
visit node of type ast::ConstructorBlock
int num_random_variables
count of RANDOM variables
int num_localized_global_variables
subset of global variables which are localized
const utils::PerfStat & get_total_perfstat() const noexcept
void print(std::ostream &ss) const
int get_instance_variable_count() const noexcept
symtab::SymbolTable * current_symtab
symbol table of current block being visited
void visit_breakpoint_block(const ast::BreakpointBlock &node) override
visit node of type ast::BreakpointBlock
void update_memory_ops(const std::string &name)
Find symbol in closest scope (up to parent) and update read/write count.
void visit_if_statement(const ast::IfStatement &node) override
visit node of type ast::IfStatement
int get_global_variable_count() const noexcept
void visit_name(const ast::Name &node) override
every variable used is of type name, update counters
bool visiting_lhs_expression
true while visiting lhs of binary expression (to count write operations)
utils::PerfStat total_perf
total performance of mod file
void measure_performance(const ast::Ast &node)
Helper function used by all ast nodes : visit all children recursively and performance stats get adde...
void visit_destructor_block(const ast::DestructorBlock &node) override
visit node of type ast::DestructorBlock
void visit_discrete_block(const ast::DiscreteBlock &node) override
visit node of type ast::DiscreteBlock
utils::PerfStat current_block_perf
performance of current block
int num_constant_instance_variables
subset of instance variables which are constant
void visit_derivative_block(const ast::DerivativeBlock &node) override
visit node of type ast::DerivativeBlock
int num_localized_instance_variables
subset of instance variables which are localized
std::string const_memr_key
keys used in map to track var usage
std::stack< utils::PerfStat > blocks_perf
performance stats of all blocks being visited in recursive chain
std::unique_ptr< printer::JSONPrinter > printer
to print to json file
void visit_unary_expression(const ast::UnaryExpression &node) override
visit node of type ast::UnaryExpression
void visit_prime_name(const ast::PrimeName &node) override
prime name derived from identifier and hence need to be handled here
void visit_function_table_block(const ast::FunctionTableBlock &node) override
visit node of type ast::FunctionTableBlock
std::map< std::string, std::set< std::string > > var_usage
map of variables to count unique read-writes
int get_const_instance_variable_count() const noexcept
void add_perf_to_printer(const utils::PerfStat &perf) const
add performance stats to json printer
void visit_statement_block(const ast::StatementBlock &node) override
Blocks like function can have multiple statement blocks and blocks like net receive has nested initia...
void visit_before_block(const ast::BeforeBlock &node) override
visit node of type ast::BeforeBlock
void visit_function_call(const ast::FunctionCall &node) override
count function calls and "most useful" or "commonly used" math functions
void visit_solve_block(const ast::SolveBlock &node) override
solve is not a statement but could have associated block and hence could/should not be skipped comple...
void visit_else_if_statement(const ast::ElseIfStatement &node) override
visit node of type ast::ElseIfStatement
void visit_for_netcon(const ast::ForNetcon &node) override
visit node of type ast::ForNetcon
std::stringstream stream
if not json, all goes to string
void visit_binary_expression(const ast::BinaryExpression &node) override
count math operations from all binary expressions
std::stack< utils::PerfStat > children_blocks_perf
performance of current all childrens
bool under_function_call
whether function call is being visited
void visit_after_block(const ast::AfterBlock &node) override
visit node of type ast::AfterBlock
void visit_net_receive_block(const ast::NetReceiveBlock &node) override
visit node of type ast::NetReceiveBlock
int num_global_variables
count of global variables
void visit_kinetic_block(const ast::KineticBlock &node) override
visit node of type ast::KineticBlock
void visit_suffix(const ast::Suffix &) override
visit node of type ast::Suffix
void visit_linear_block(const ast::LinearBlock &node) override
visit node of type ast::LinearBlock
int num_state_variables
count of state variables
void visit_non_linear_block(const ast::NonLinearBlock &node) override
visit node of type ast::NonLinearBlock
int num_instance_variables
count of per channel instance variables
void visit_procedure_block(const ast::ProcedureBlock &node) override
visit node of type ast::ProcedureBlock
bool under_solve_block
whether solve block is being visited
static bool is_local_variable(const std::shared_ptr< symtab::Symbol > &symbol)
bool under_net_receive_block
whether net receive block is being visited
bool start_measurement
whether to measure performance for current block
void visit_function_block(const ast::FunctionBlock &node) override
visit node of type ast::FunctionBlock
int num_constant_global_variables
subset of global variables which are constant
bool symbol_to_skip(const std::shared_ptr< symtab::Symbol > &symbol) const
Certain statements / symbols needs extra check while measuring read/write operations.
void visit_conductance_hint(const ast::ConductanceHint &) override
certain constructs needs to be excluded from usage counting and hence need to provide empty implement...
const char * name
Definition: init.cpp:16
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
static Node * node(Object *)
Definition: netcvode.cpp:291
Implement class for performance statistics.
Forward references of symbols defined in namespace nmodl::printer.
Base class for all Abstract Syntax Tree node types.
Definition: ast.hpp:52
Helper class to collect performance statistics.
Definition: perf_stat.hpp:36
Forward declarations of symbols in namespace nmodl::symtab.