LIBINT  2.6.0
buildtest.h
1 /*
2  * Copyright (C) 2004-2019 Edward F. Valeev
3  *
4  * This file is part of Libint.
5  *
6  * Libint is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Libint is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #ifndef _libint2_src_bin_libint_buildtest_h_
22 #define _libint2_src_bin_libint_buildtest_h_
23 
24 #include <iostream>
25 #include <fstream>
26 #include <sstream>
27 #include <string>
28 #include <deque>
29 #include <iterator>
30 #include <dg.h>
31 #include <integral_11_11.h>
32 #include <strategy.h>
33 #include <iface.h>
34 #include <dims.h>
35 #include <graph_registry.h>
36 
37 namespace libint2 {
38 
39  // defined in buildtest.cc
40  void generate_rr_code(std::ostream& os, const SafePtr<CompilationParameters>& cparams,
41  std::deque<std::string>& decl_filenames,
42  std::deque<std::string>& def_filenames);
43 
45  void
46  GenerateCode(const SafePtr<DirectedGraph>& dg,
47  const SafePtr<CodeContext>& context,
48  const SafePtr<CompilationParameters>& cparams,
49  const SafePtr<Strategy>& strat,
50  const SafePtr<Tactic>& tactic,
51  const SafePtr<MemoryManager>& memman,
52  std::deque<std::string>& decl_filenames,
53  std::deque<std::string>& def_filenames,
54  const std::string& prefix,
55  const std::string& label,
56  bool have_parent);
57 
59  template <unsigned int N>
61  public:
62  TesterCmdLine(int argc, char* argv[]);
63  ~TesterCmdLine() {}
64 
65  const std::vector<unsigned int>& am() const { return am_; }
66  unsigned int size_to_unroll() const { return size_to_unroll_; }
67  unsigned int veclen() const { return veclen_; }
68  bool vectorize_by_line() const { return vectorize_by_line_; }
69  bool do_cse() const { return do_cse_; }
70 
71  private:
72  static const unsigned int max_am = 10;
73  std::vector<unsigned int> am_;
74  unsigned int size_to_unroll_;
75  unsigned int veclen_;
76  bool vectorize_by_line_;
77  bool do_cse_;
78  };
79 
84  template <class Integral, bool GenAllCode>
85  void BuildTest(const std::vector< SafePtr<Integral> >& targets, unsigned int size_to_unroll, unsigned int veclen,
86  bool vec_by_line, bool do_cse, const std::string& complabel = "buildtest",
87  std::ostream& os = std::cout);
88 
93  template <class Integral, bool GenAllCode>
94  void __BuildTest(const std::vector< SafePtr<Integral> >& targets, const SafePtr<CompilationParameters>& cparams,
95  unsigned int size_to_unroll, std::ostream& os = std::cout,
96  const SafePtr<Tactic>& tactic = SafePtr<Tactic>(new FirstChoiceTactic<DummyRandomizePolicy>),
97  const SafePtr<MemoryManager>& memman = SafePtr<MemoryManager>(new WorstFitMemoryManager),
98  const std::string& complabel = "general_integral");
99 
100  template <class Integral, bool GenAllCode>
101  void
102  __BuildTest(const std::vector< SafePtr<Integral> >& targets, const SafePtr<CompilationParameters>& cparams,
103  unsigned int size_to_unroll, std::ostream& os,
104  const SafePtr<Tactic>& tactic, const SafePtr<MemoryManager>& memman,
105  const std::string& complabel)
106  {
107  const std::string prefix("");
108  const std::string label = cparams->api_prefix() + complabel;
109  SafePtr<Strategy> strat(new Strategy);
110  SafePtr<CodeContext> context(new CppCodeContext(cparams));
111 
113  taskmgr.add(complabel);
114  taskmgr.current(complabel);
115 
116  //
117  // do CSE only if max_am <= cparams->max_am_opt()
118  //
119  unsigned int max_am = 0;
120  for(unsigned int t=0; t<targets.size(); ++t) {
121  const SafePtr<Integral>& target = targets[t];
122  const unsigned int np = target->bra().num_part();
123  // bra
124  for(unsigned int p=0; p<np; p++) {
125  const unsigned int nf = target->bra().num_members(p);
126  for(unsigned int f=0; f<nf; f++) {
127  // Assuming shells here
128  const unsigned int am = target->bra(p,f).qn();
129  using std::max;
130  max_am = max(max_am,am);
131  }
132  }
133  // ket
134  for(unsigned int p=0; p<np; p++) {
135  const unsigned int nf = target->ket().num_members(p);
136  for(unsigned int f=0; f<nf; f++) {
137  // Assuming shells here
138  const unsigned int am = target->ket(p,f).qn();
139  using std::max;
140  max_am = max(max_am,am);
141  }
142  }
143  }
144  const bool need_to_optimize = (max_am <= cparams->max_am_opt(complabel));
145 
146  std::deque<std::string> decl_filenames;
147  std::deque<std::string> def_filenames;
148 
149  os << "Building " << complabel << std::endl;
150 
151  SafePtr<DirectedGraph> dg_xxxx(new DirectedGraph);
152  dg_xxxx->set_label(complabel);
153 
154  // configure the graph
155  dg_xxxx->registry()->do_cse(need_to_optimize);
156  dg_xxxx->registry()->condense_expr(condense_expr(size_to_unroll,cparams->max_vector_length()>1));
157  // Need to accumulate integrals?
158  dg_xxxx->registry()->accumulate_targets(cparams->accumulate_targets());
159  dg_xxxx->registry()->unroll_threshold(size_to_unroll);
160 
161  for(unsigned int t=0; t<targets.size(); ++t) {
162  const SafePtr<Integral>& target = targets[t];
163  SafePtr<DGVertex> target_ptr = dynamic_pointer_cast<DGVertex,Integral>(target);
164  assert(target_ptr != 0);
165  dg_xxxx->append_target(target_ptr);
166  }
167 
168  // this will generate code for this targets, and potentially generate code for its prerequisites
169  GenerateCode(dg_xxxx, context, cparams, strat, tactic, memman,
170  decl_filenames, def_filenames,
171  prefix, label, false);
172 
173  // update max stack size
174  taskmgr.current().params()->max_stack_size(max_am, memman->max_memory_used());
175  taskmgr.current().params()->max_ntarget(targets.size());
176  os << "Max memory used = " << memman->max_memory_used() << std::endl;
177 
178  if (GenAllCode) {
179  // initialize code context to produce library API
180  SafePtr<CodeContext> icontext(new CppCodeContext(cparams));
181  // initialize object to generate interface
182  SafePtr<Libint2Iface> iface(new Libint2Iface(cparams,icontext));
183 
184  // generate interface
185  std::ostringstream oss;
186  for(std::deque<std::string>::const_iterator i = decl_filenames.begin(); i != decl_filenames.end(); ++i) {
187  oss << "#include <" << *i << ">" << std::endl;
188  }
189  iface->to_int_iface(oss.str());
190 
191  // transfer some configuration parameters to the generated library API
192  iface->to_params(iface->macro_define("CARTGAUSS_MAX_AM",LIBINT_CARTGAUSS_MAX_AM));
193  iface->to_params(iface->macro_define("CGSHELL_ORDERING",LIBINT_CGSHELL_ORDERING));
194  iface->to_params(iface->macro_define("CGSHELL_ORDERING_STANDARD",LIBINT_CGSHELL_ORDERING_STANDARD));
195  iface->to_params(iface->macro_define("CGSHELL_ORDERING_INTV3",LIBINT_CGSHELL_ORDERING_INTV3));
196  iface->to_params(iface->macro_define("CGSHELL_ORDERING_GAMESS",LIBINT_CGSHELL_ORDERING_GAMESS));
197  iface->to_params(iface->macro_define("CGSHELL_ORDERING_ORCA",LIBINT_CGSHELL_ORDERING_ORCA));
198  iface->to_params(iface->macro_define("CGSHELL_ORDERING_BAGEL",LIBINT_CGSHELL_ORDERING_BAGEL));
199  iface->to_params(iface->macro_define("SHELLQUARTET_SET",LIBINT_SHELL_SET));
200  iface->to_params(iface->macro_define("SHELLQUARTET_SET_STANDARD",LIBINT_SHELL_SET_STANDARD));
201  iface->to_params(iface->macro_define("SHELLQUARTET_SET_ORCA",LIBINT_SHELL_SET_ORCA));
202 
203  // Generate set-level RR code
204  generate_rr_code(os,cparams,
205  decl_filenames, def_filenames);
206 
207  // Print log
208  std::cout << "Generated headers: ";
209  std::copy(decl_filenames.begin(), decl_filenames.end(), std::ostream_iterator<std::string>(std::cout, " "));
210  std::cout << std::endl << "Generated sources: ";
211  std::copy(def_filenames.begin(), def_filenames.end(), std::ostream_iterator<std::string>(std::cout, " "));
212  std::cout << std::endl << "Top compute function: " << context->label_to_name(label_to_funcname(label)) << std::endl;
213 
214  }
215  }
216 
217  void
218  GenerateCode(const SafePtr<DirectedGraph>& dg,
219  const SafePtr<CodeContext>& context,
220  const SafePtr<CompilationParameters>& cparams,
221  const SafePtr<Strategy>& strat,
222  const SafePtr<Tactic>& tactic,
223  const SafePtr<MemoryManager>& memman,
224  std::deque<std::string>& decl_filenames,
225  std::deque<std::string>& def_filenames,
226  const std::string& prefix,
227  const std::string& label,
228  bool have_parent) {
229 
230  dg->apply(strat,tactic);
231 #if PRINT_DAG_GRAPHVIZ
232  {
233  std::basic_ofstream<char> dotfile(dg->label() + ".strat.dot");
234  dg->print_to_dot(false,dotfile);
235  }
236 #endif
237  dg->optimize_rr_out(context);
238 #if DEBUG
239  std::cout << "The number of vertices = " << dg->num_vertices() << std::endl;
240 #endif
241 
242  // if there are missing prerequisites -- make a list of them
244  if (dg->missing_prerequisites()) {
245  //std::cout << "missing some prerequisites!" << std::endl;
246  dg->foreach(pe);
247  }
248  std::deque< SafePtr<DGVertex> > prereq_list = pe.vertices;
249 
250  dg->traverse();
251  //dg->debug_print_traversal(cout);
252 
253 #if PRINT_DAG_GRAPHVIZ
254  {
255  std::basic_ofstream<char> dotfile(dg->label() + ".expr.dot");
256  dg->print_to_dot(false,dotfile);
257  }
258 #endif
259 
260  std::string decl_filename(prefix + context->label_to_name(label)); decl_filename += ".h";
261  std::string def_filename(prefix + context->label_to_name(label)); def_filename += ".cc";
262  std::basic_ofstream<char> declfile(decl_filename.c_str());
263  std::basic_ofstream<char> deffile(def_filename.c_str());
264  // if have parent graph, it will pass its stack where this graph will put its results
265  SafePtr<CodeSymbols> args(new CodeSymbols);
266  if (have_parent)
267  args->append_symbol("parent_stack");
268  dg->generate_code(context,memman,ImplicitDimensions::default_dims(),args,
269  label,declfile,deffile);
270  declfile.close();
271  deffile.close();
272 
273  // extract all external symbols
274  extract_symbols(dg);
275 
276 #if PRINT_DAG_GRAPHVIZ
277  {
278  std::basic_ofstream<char> dotfile(dg->label() + ".symb.dot");
279  dg->print_to_dot(true,dotfile);
280  }
281 #endif
282 
283  decl_filenames.push_back(decl_filename);
284  def_filenames.push_back(def_filename);
285 
286  // last: missing prerequisites? create new graph computing prereqs and move them onto it
287  if (dg->missing_prerequisites()) {
288 
289  SafePtr<DirectedGraph> dg_prereq(new DirectedGraph);
290  // configure identically
291  dg_prereq->registry() = SafePtr<GraphRegistry>(dg->registry()->clone());
292  // except:
293  // - allow uncontraction
294  // - no need to return targets via inteval->targets_ -- their locations are known by the parent graph (see allocate_mem)
295  dg_prereq->registry()->uncontract(true);
296  assert(cparams->contracted_targets() == true);
297  dg_prereq->registry()->return_targets(false);
298  dg_prereq->registry()->accumulate_targets(true);
299  dg_prereq->registry()->stack_name("stack");
300  if (dg->registry()->current_timer() >= 0) {
301  dg_prereq->registry()->current_timer( dg->registry()->current_timer() + 1 );
302  }
303 
304  // now is the "right" time to reset dg
305  // reset graph of the previous computation so that the vertices that will be targets on the new graph
306  // are not attached still to the vertices from the old graph
307  dg->reset();
308  memman->reset();
309 
310  while (!prereq_list.empty()) {
311  dg_prereq->append_target(prereq_list.front());
312  prereq_list.pop_front();
313  }
314 
315  const std::string label_prereq = label + "_prereq";
316  GenerateCode(dg_prereq, context, cparams, strat, tactic, memman,
317  decl_filenames, def_filenames,
318  prefix, label_prereq, true);
319 
320  }
321  dg->reset();
322  memman->reset();
323 
324  }
325 
326  template <class Integral, bool GenAllCode>
327  void BuildTest(const std::vector< SafePtr<Integral> >& targets, unsigned int size_to_unroll, unsigned int veclen,
328  bool vec_by_line, bool do_cse, const std::string& complabel,
329  std::ostream& os)
330  {
331  const unsigned int max_am = 10;
332  os << "generating code to compute " << complabel << std::endl;
333 
335  taskmgr.add(complabel);
336  taskmgr.current(complabel);
337 
338  // initialize cparams
339  SafePtr<CompilationParameters> cparams(new CompilationParameters);
340  cparams->max_am(complabel,max_am);
341  cparams->num_bf(complabel,4u);
342  cparams->max_vector_length(veclen);
343  cparams->vectorize_by_line(vec_by_line);
344 #if LIBINT_ALIGN_SIZE
345  cparams->align_size(LIBINT_ALIGN_SIZE);
346 #endif
347  cparams->count_flops(true);
348 #if LIBINT_ACCUM_INTS
349  cparams->accumulate_targets(true);
350 #else
351  cparams->accumulate_targets(false);
352 #endif
353 #ifdef LIBINT_API_PREFIX
354  {
355  const std::string api_prefix(LIBINT_API_PREFIX);
356  cparams->api_prefix(api_prefix);
357  }
358 #endif
359 #if LIBINT_CONTRACTED_INTS
360  cparams->contracted_targets(true);
361 #else
362  cparams->contracted_targets(false);
363 #endif
364 #ifdef LIBINT_USER_DEFINED_REAL
365  {
366  const std::string realtype(LIBINT_USER_DEFINED_REAL);
367  cparams->realtype(realtype);
368  }
369 #endif
370 
371  if (do_cse) {
372  cparams->max_am_opt(complabel,max_am);
373  }
374  else {
375  cparams->max_am_opt(complabel,0);
376  }
377  cparams->default_task_name(complabel);
378 
379  // set default dims
381 
382  SafePtr<StdRandomizePolicy> rpolicy(new StdRandomizePolicy(0.00));
383  // use 4-center OS if the target is a 4-center integral
384  SafePtr<Tactic> tactic;
385  {
386  typedef GenIntegralSet_11_11<typename Integral::BasisFunctionType,
387  typename Integral::OperatorType,
388  typename Integral::AuxIndexType> genint_11_11_t;
389  SafePtr< genint_11_11_t > cast_ptr = dynamic_pointer_cast<genint_11_11_t>(targets.front());
390  if (cast_ptr) {
391  const unsigned int la = cast_ptr->bra(0, 0).norm();
392  const unsigned int lb = cast_ptr->ket(0, 0).norm();
393  const unsigned int lc = cast_ptr->bra(1, 0).norm();
394  const unsigned int ld = cast_ptr->ket(1, 0).norm();
395  tactic = SafePtr<Tactic>(new FourCenter_OS_Tactic(la, lb, lc, ld));
396  }
397  else {
398  tactic = SafePtr<Tactic>(new FirstChoiceTactic<StdRandomizePolicy>(rpolicy));
399  }
400  }
401  const SafePtr<MemoryManager> memman(new WorstFitMemoryManager);
402  __BuildTest<Integral,true>(targets,cparams,size_to_unroll,os,tactic,memman,complabel);
403  }
404 
405  template <unsigned int N>
406  TesterCmdLine<N>::TesterCmdLine(int argc, char* argv[])
407  {
408  if (N == 0)
409  throw ProgrammingError("TesterCmdLine<N>::TesterCmdLine but N is 0");
410  const int argc_min = N + 2;
411  const int argc_max = N + 5;
412  if (argc < argc_min || argc > argc_max) {
413  std::cerr << "Usage: " << argv[0] << " <am> size_to_unroll [vector_length] [vector_method] [do_cse]" << std::endl
414  << " <am> -- angular momenta on each center, e.g. 4 nonnegative integers for a 4-center ERI" << std::endl
415  << " size_to_unroll -- size of the largest integral set to be unrolled" << std::endl
416  << " vector_length -- (optional) max vector length. Defaults to 1." << std::endl
417  << " vector_method -- (optional) vectorization method. Valid choices are 0 (by-block) and 1 (by-line). Defaults to 0." << std::endl
418  << " do_cse -- (optional) do Common Subexpression Elimination? Valid choices are 0 (no) and 1 (yes). Defaults to 0." << std::endl << std::endl;
419  throw InputError("TesterCmdLine<N>::TesterCmdLine -- incorrect number of command-line arguments");
420  }
421  for(unsigned int i=1; i<N+1; ++i) {
422  const unsigned int am = atoi(argv[i]);
423  if (am > max_am)
424  throw InputError("TesterCmdLine<N>::TesterCmdLine -- angular momentum limit exceeded");
425  am_.push_back(am);
426  }
427  size_to_unroll_ = atoi(argv[N+1]);
428 
429  veclen_ = 1;
430  if (argc >= N+3) {
431  veclen_ = atoi(argv[N+2]);
432  }
433  vectorize_by_line_ = false;
434  if (argc >= N+4) {
435  vectorize_by_line_ = (1 == atoi(argv[N+3]));
436  }
437  do_cse_ = false;
438  if (argc >= N+5) {
439  do_cse_ = (1 == atoi(argv[N+4]));
440  }
441  }
442 
443 };
444 
445 #endif
FirstChoiceTactic simply chooses the first RR.
Definition: tactic.h:61
std::string label_to_funcname(const std::string &label)
Converts a label, e.g. name of the target node, to the name of the function to compute it.
Definition: default_params.cc:216
Manages tasks. This is a Singleton.
Definition: task.h:63
Libint2Iface is used to generate Libint2 interfaces.
Definition: iface.h:43
bool condense_expr(unsigned int unroll_threshold, bool vectorize)
need to condense expressions? Makes sense if vectorizing the code or the compiler somehow prefers lon...
Definition: default_params.cc:229
static SafePtr< ImplicitDimensions > default_dims()
Default ImplicitDimension object.
Definition: dims.cc:38
void __BuildTest(const std::vector< SafePtr< Integral > > &targets, const SafePtr< CompilationParameters > &cparams, unsigned int size_to_unroll, std::ostream &os=std::cout, const SafePtr< Tactic > &tactic=SafePtr< Tactic >(new FirstChoiceTactic< DummyRandomizePolicy >), const SafePtr< MemoryManager > &memman=SafePtr< MemoryManager >(new WorstFitMemoryManager), const std::string &complabel="general_integral")
This is a generic test of building an Integral using specified cparams, memman, size_to_unroll,...
Definition: buildtest.h:102
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24
void extract_symbols(const SafePtr< DirectedGraph > &dg)
extracts external symbols and RRs from the graph
Definition: dg.cc:2357
Generic integral over a two-body operator with one bfs for each particle in bra and ket.
Definition: integral_11_11.h:33
void current(const std::string &task_label)
Makes this task current (must have been added already)
Definition: task.cc:76
Strategy specifies how to apply recurrence relations.
Definition: strategy.h:42
Command-line parser for the standard build tester – N is the number of centers, i....
Definition: buildtest.h:60
void BuildTest(const std::vector< SafePtr< Integral > > &targets, unsigned int size_to_unroll, unsigned int veclen, bool vec_by_line, bool do_cse, const std::string &complabel="buildtest", std::ostream &os=std::cout)
This is a user-friendly generic test of building an Integral using specified size_to_unroll,...
Definition: buildtest.h:327
CppCodeContext is an implementation of CodeContext for C++.
Definition: context.h:207
void add(const std::string &task_label)
Adds a new task. Do nothing if the task exists already.
Definition: task.cc:40
WorstFitMemoryManager allocates memory by trying to find the largest-possible free block.
Definition: src/bin/libint/memory.h:208
BraSetType::bfs_cref bra(unsigned int p, unsigned int i) const
Implementation of IntegralSet::bra() const.
Definition: integral.h:316
Class CodeSymbols specifies a set of symbols used in a code.
Definition: code.h:34
void GenerateCode(const SafePtr< DirectedGraph > &dg, const SafePtr< CodeContext > &context, const SafePtr< CompilationParameters > &cparams, const SafePtr< Strategy > &strat, const SafePtr< Tactic > &tactic, const SafePtr< MemoryManager > &memman, std::deque< std::string > &decl_filenames, std::deque< std::string > &def_filenames, const std::string &prefix, const std::string &label, bool have_parent)
defined below generates code for dg; dg and memman are reset at the end
Definition: buildtest.h:218
FourCenter_OS_Tactic decides graph build for (bra0 ket0| bra1 ket1) = <bra0 bra1|ket0 ket1>
Definition: tactic.h:164
static LibraryTaskManager & Instance()
LibraryTaskManager is a Singleton.
Definition: task.cc:34
static void set_default_dims(const SafePtr< CompilationParameters > &cparams)
Sets default ImplicitDimension object.
Definition: dims.cc:31
The shift parameter is computed as follows: delta = floor(nrrs*scale*random()/RAND_MAX) where nrrs is...
Definition: tactic.h:198
These are the parameters received by the compiler.
Definition: default_params.h:38
DirectedGraph is an implementation of a directed graph composed of vertices represented by DGVertex o...
Definition: dg.h:63