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