CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
model_c_source_gen_impl.hpp
1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_IMPL_INCLUDED
2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_IMPL_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 Ciengis
6  *
7  * CppADCodeGen is distributed under multiple licenses:
8  *
9  * - Eclipse Public License Version 1.0 (EPL1), and
10  * - GNU General Public License Version 3 (GPL3).
11  *
12  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14  * ----------------------------------------------------------------------------
15  * Author: Joao Leal
16  */
17 
18 #include <typeinfo>
19 
20 namespace CppAD {
21 namespace cg {
22 
23 template<class Base>
24 const std::string ModelCSourceGen<Base>::FUNCTION_FORWAD_ZERO = "forward_zero";
25 
26 template<class Base>
27 const std::string ModelCSourceGen<Base>::FUNCTION_JACOBIAN = "jacobian";
28 
29 template<class Base>
30 const std::string ModelCSourceGen<Base>::FUNCTION_HESSIAN = "hessian";
31 
32 template<class Base>
33 const std::string ModelCSourceGen<Base>::FUNCTION_FORWARD_ONE = "forward_one";
34 
35 template<class Base>
36 const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_ONE = "reverse_one";
37 
38 template<class Base>
39 const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_TWO = "reverse_two";
40 
41 template<class Base>
42 const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_JACOBIAN = "sparse_jacobian";
43 
44 template<class Base>
45 const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_HESSIAN = "sparse_hessian";
46 
47 template<class Base>
48 const std::string ModelCSourceGen<Base>::FUNCTION_JACOBIAN_SPARSITY = "jacobian_sparsity";
49 
50 template<class Base>
51 const std::string ModelCSourceGen<Base>::FUNCTION_HESSIAN_SPARSITY = "hessian_sparsity";
52 
53 template<class Base>
54 const std::string ModelCSourceGen<Base>::FUNCTION_HESSIAN_SPARSITY2 = "hessian_sparsity2";
55 
56 template<class Base>
57 const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_FORWARD_ONE = "sparse_forward_one";
58 
59 template<class Base>
60 const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_REVERSE_ONE = "sparse_reverse_one";
61 
62 template<class Base>
63 const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_REVERSE_TWO = "sparse_reverse_two";
64 
65 template<class Base>
66 const std::string ModelCSourceGen<Base>::FUNCTION_FORWARD_ONE_SPARSITY = "forward_one_sparsity";
67 
68 template<class Base>
69 const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_ONE_SPARSITY = "reverse_one_sparsity";
70 
71 template<class Base>
72 const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_TWO_SPARSITY = "sparse_reverse_two_sparsity";
73 
74 template<class Base>
75 const std::string ModelCSourceGen<Base>::FUNCTION_INFO = "info";
76 
77 template<class Base>
78 const std::string ModelCSourceGen<Base>::FUNCTION_ATOMIC_FUNC_NAMES = "atomic_functions";
79 
80 template<class Base>
81 const std::string ModelCSourceGen<Base>::CONST = "const";
82 
83 template<class Base>
84 VariableNameGenerator<Base>* ModelCSourceGen<Base>::createVariableNameGenerator(const std::string& depName,
85  const std::string& indepName,
86  const std::string& tmpName,
87  const std::string& tmpArrayName) {
88  return new LangCDefaultVariableNameGenerator<Base> (depName, indepName, tmpName, tmpArrayName);
89 }
90 
91 template<class Base>
92 const std::map<std::string, std::string>& ModelCSourceGen<Base>::getSources(MultiThreadingType multiThreadingType,
93  JobTimer* timer) {
94  if (_sources.empty()) {
95  generateSources(multiThreadingType, timer);
96  }
97  return _sources;
98 }
99 
100 template<class Base>
101 void ModelCSourceGen<Base>::generateSources(MultiThreadingType multiThreadingType,
102  JobTimer* timer) {
103  _jobTimer = timer;
104 
105  generateLoops();
106 
107  startingJob("'" + _name + "'", JobTimer::SOURCE_FOR_MODEL);
108 
109  if (_zero) {
110  generateZeroSource();
111  _zeroEvaluated = true;
112  }
113 
114  if (_jacobian) {
115  generateJacobianSource();
116  }
117 
118  if (_hessian) {
119  generateHessianSource();
120  }
121 
122  if (_forwardOne) {
123  generateSparseForwardOneSources();
124  generateForwardOneSources();
125  }
126 
127  if (_reverseOne) {
128  generateSparseReverseOneSources();
129  generateReverseOneSources();
130  }
131 
132  if (_reverseTwo) {
133  generateSparseReverseTwoSources();
134  generateReverseTwoSources();
135  }
136 
137  if (_sparseJacobian) {
138  generateSparseJacobianSource(multiThreadingType);
139  }
140 
141  if (_sparseHessian) {
142  generateSparseHessianSource(multiThreadingType);
143  }
144 
145  if (_sparseJacobian || _forwardOne || _reverseOne) {
146  generateJacobianSparsitySource();
147  }
148 
149  if (_sparseHessian || _reverseTwo) {
150  generateHessianSparsitySource();
151  }
152 
153  generateInfoSource();
154 
155  generateAtomicFuncNames();
156 
157  finishedJob();
158 }
159 
160 template<class Base>
161 void ModelCSourceGen<Base>::generateLoops() {
162  if (_relatedDepCandidates.empty()) {
163  return; //nothing to do
164  }
165 
166  startingJob("", JobTimer::LOOP_DETECTION);
167 
168  CodeHandler<Base> handler;
169  handler.setJobTimer(_jobTimer);
170 
171  std::vector<CGBase> xx(_fun.Domain());
172  handler.makeVariables(xx);
173  if (_x.size() > 0) {
174  for (size_t i = 0; i < xx.size(); i++) {
175  xx[i].setValue(_x[i]);
176  }
177  }
178 
179  std::vector<CGBase> yy = _fun.Forward(0, xx);
180 
181  DependentPatternMatcher<Base> matcher(_relatedDepCandidates, yy, xx);
182  matcher.generateTapes(_funNoLoops, _loopTapes);
183 
184  finishedJob();
185  if (_jobTimer != nullptr && _jobTimer->isVerbose()) {
186  std::cout << " equation patterns: " << matcher.getEquationPatterns().size() <<
187  " loops: " << matcher.getLoops().size() << std::endl;
188  }
189 }
190 
191 template<class Base>
192 void ModelCSourceGen<Base>::generateInfoSource() {
193  const char* localBaseName = typeid (Base).name();
194 
195  std::string funcName = _name + "_" + FUNCTION_INFO;
196 
197  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator());
198 
199  _cache.str("");
200  LanguageC<Base>::printFunctionDeclaration(_cache, "void", funcName, {"const char** baseName",
201  "unsigned long* m",
202  "unsigned long* n",
203  "unsigned int* indCount",
204  "unsigned int* depCount"});
205  _cache << " {\n"
206  " *baseName = \"" << _baseTypeName << " " << localBaseName << "\";\n"
207  " *m = " << _fun.Range() << ";\n"
208  " *n = " << _fun.Domain() << ";\n"
209  " *depCount = " << nameGen->getDependent().size() << "; // number of dependent array variables\n"
210  " *indCount = " << nameGen->getIndependent().size() << "; // number of independent array variables\n"
211  "}\n\n";
212 
213  _sources[funcName + ".c"] = _cache.str();
214 }
215 
216 template<class Base>
217 void ModelCSourceGen<Base>::generateAtomicFuncNames() {
218  std::string funcName = _name + "_" + FUNCTION_ATOMIC_FUNC_NAMES;
219  size_t n = _atomicFunctions.size();
220  _cache.str("");
221  LanguageC<Base>::printFunctionDeclaration(_cache, "void", funcName, {"const char*** names",
222  "unsigned long* n"});
223  _cache << " {\n"
224  " static const char* atomic[" << n << "] = {";
225  for (size_t i = 0; i < n; i++) {
226  if (i > 0) _cache << ", ";
227  _cache << "\"" << _atomicFunctions[i] << "\"";
228  }
229  _cache << "};\n"
230  " *names = atomic;\n"
231  " *n = " << n << ";\n"
232  "}\n\n";
233 
234  _sources[funcName + ".c"] = _cache.str();
235 }
236 
237 template<class Base>
238 bool ModelCSourceGen<Base>::isAtomicsUsed() {
239  if (_zeroEvaluated) {
240  return _atomicFunctions.size() > 0;
241  } else {
242  return !getAtomicsInfo().empty();
243  }
244 }
245 
246 template<class Base>
247 const std::map<size_t, AtomicUseInfo<Base> >& ModelCSourceGen<Base>::getAtomicsInfo() {
248  if (_atomicsInfo == nullptr) {
249  AtomicDependencyLocator<Base> adl(_fun);
250  _atomicsInfo = new std::map<size_t, AtomicUseInfo<Base> >(adl.findAtomicsUsage());
251  }
252  return *_atomicsInfo;
253 }
254 
255 template<class Base>
256 std::vector<typename ModelCSourceGen<Base>::Color> ModelCSourceGen<Base>::colorByRow(const std::set<size_t>& columns,
257  const SparsitySetType& sparsity) {
258  std::vector<Color> colors(sparsity.size()); // reserve the maximum size to avoid reallocating more space later
259 
264  size_t c_used = 0;
265  for (size_t i = 0; i < sparsity.size(); i++) {
266  const std::set<size_t>& row = sparsity[i];
267  if (row.size() == 0) {
268  continue; //nothing to do
269  }
270 
271  // consider only the columns present in the sparsity pattern
272  std::set<size_t> rowReduced;
273  if (_custom_hess.defined) {
274  for (size_t j : row) {
275  if (columns.find(j) != columns.end())
276  rowReduced.insert(j);
277  }
278  } else {
279  rowReduced = row;
280  }
281 
282  bool newColor = true;
283  size_t colori;
284  for (size_t c = 0; c < c_used; c++) {
285  std::set<size_t>& forbidden_c = colors[c].forbiddenRows;
286  if (!intersects(forbidden_c, rowReduced)) {
287  // no intersection
288  colori = c;
289  newColor = false;
290  forbidden_c.insert(rowReduced.begin(), rowReduced.end());
291  break;
292  }
293  }
294 
295  if (newColor) {
296  colori = c_used;
297  colors[c_used].forbiddenRows = rowReduced;
298  c_used++;
299  }
300 
301  colors[colori].rows.insert(i);
302 
303  for (size_t j : rowReduced) {
304  colors[colori].column2Row[j] = i;
305  colors[colori].row2Columns[i].insert(j);
306  }
307  }
308 
309  colors.resize(c_used); //reduce size
310  return colors;
311 }
312 
313 template<class Base>
315  const std::string& suffix,
316  const std::string& function_sparsity,
317  const std::map<size_t, std::vector<size_t> >& elements) {
321  LanguageC<Base> langC(_baseTypeName);
322  std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
323  std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
324  std::string args = langC.generateDefaultFunctionArguments();
325 
326  _cache.str("");
327  _cache << _name << "_" << function;
328  std::string model_function = _cache.str();
329  _cache.str("");
330 
331  _cache << LanguageC<Base>::ATOMICFUN_STRUCT_DEFINITION << "\n\n";
332  generateFunctionDeclarationSource(_cache, model_function, suffix, elements, argsDcl);
333  _cache << "\n";
334  LanguageC<Base>::printFunctionDeclaration(_cache, "int", model_function, {"unsigned long pos"}, argsDcl2);
335  _cache << " {\n"
336  " switch(pos) {\n";
337  for (const auto& it : elements) {
338  // the size of each sparsity row
339  _cache << " case " << it.first << ":\n"
340  " " << model_function << "_" << suffix << it.first << "(" << args << ");\n"
341  " return 0; // done\n";
342  }
343  _cache << " default:\n"
344  " return 1; // error\n"
345  " };\n";
346 
347  _cache << "}\n";
348  _sources[model_function + ".c"] = _cache.str();
349  _cache.str("");
350 
354  generateSparsity1DSource2(_name + "_" + function_sparsity, elements);
355  _sources[_name + "_" + function_sparsity + ".c"] = _cache.str();
356  _cache.str("");
357 }
358 
359 template<class Base>
360 template<class T>
361 void ModelCSourceGen<Base>::generateFunctionDeclarationSource(std::ostringstream& cache,
362  const std::string& model_function,
363  const std::string& suffix,
364  const std::map<size_t, T>& elements,
365  const std::string& argsDcl) {
366  for (const auto& it : elements) {
367  size_t pos = it.first;
368  cache << "void " << model_function << "_" << suffix << pos << "(" << argsDcl << ");\n";
369  }
370 }
371 
372 template<class Base>
373 void ModelCSourceGen<Base>::generateSparsity1DSource(const std::string& function,
374  const std::vector<size_t>& sparsity) {
375  LanguageC<Base>::printFunctionDeclaration(_cache, "void", function, {"unsigned long const** sparsity",
376  "unsigned long* nnz"});
377  _cache << " {\n";
378 
379  // the size of each sparsity row
380  _cache << " ";
381  LanguageC<Base>::printStaticIndexArray(_cache, "nonzeros", sparsity);
382 
383  _cache << " *sparsity = nonzeros;\n"
384  " *nnz = " << sparsity.size() << ";\n"
385  "}\n";
386 }
387 
388 template<class Base>
389 void ModelCSourceGen<Base>::generateSparsity2DSource(const std::string& function,
390  const LocalSparsityInfo& sparsity) {
391  const std::vector<size_t>& rows = sparsity.rows;
392  const std::vector<size_t>& cols = sparsity.cols;
393 
394  CPPADCG_ASSERT_UNKNOWN(rows.size() == cols.size());
395 
396  LanguageC<Base>::printFunctionDeclaration(_cache, "void", function, {"unsigned long const** row",
397  "unsigned long const** col",
398  "unsigned long* nnz"});
399  _cache << " {\n";
400 
401  // the size of each sparsity row
402  _cache << " ";
403  LanguageC<Base>::printStaticIndexArray(_cache, "rows", rows);
404 
405  _cache << " ";
406  LanguageC<Base>::printStaticIndexArray(_cache, "cols", cols);
407 
408  _cache << " *row = rows;\n"
409  " *col = cols;\n"
410  " *nnz = " << rows.size() << ";\n"
411  "}\n";
412 }
413 
414 template<class Base>
415 void ModelCSourceGen<Base>::generateSparsity2DSource2(const std::string& function,
416  const std::vector<LocalSparsityInfo>& sparsities) {
417  LanguageC<Base>::printFunctionDeclaration(_cache, "void", function, {"unsigned long i",
418  "unsigned long const** row",
419  "unsigned long const** col",
420  "unsigned long* nnz"});
421  _cache << " {\n";
422 
423  std::ostringstream os;
424 
425  std::vector<size_t> nnzs(sparsities.size());
426 
427  long long int maxNnzIndex = -1;
428 
429  for (size_t i = 0; i < sparsities.size(); i++) {
430  const std::vector<size_t>& rows = sparsities[i].rows;
431  const std::vector<size_t>& cols = sparsities[i].cols;
432  CPPADCG_ASSERT_UNKNOWN(rows.size() == cols.size());
433 
434  nnzs[i] = rows.size();
435 
436  if (!rows.empty()) {
437  os.str("");
438  os << "rows" << i;
439  _cache << " ";
440  LanguageC<Base>::printStaticIndexArray(_cache, os.str(), rows);
441 
442  os.str("");
443  os << "cols" << i;
444  _cache << " ";
445  LanguageC<Base>::printStaticIndexArray(_cache, os.str(), cols);
446 
447  maxNnzIndex = i;
448  }
449  }
450 
451  maxNnzIndex++;
452  nnzs.resize(maxNnzIndex);
453 
454  auto makeArrayOfArrays = [&, this](const std::string& name) {
455  _cache << " static " << LanguageC<Base>::U_INDEX_TYPE << " const * const " << name << "[" << maxNnzIndex
456  << "] = {";
457  for (size_t i = 0; i < size_t(maxNnzIndex); i++) {
458  if (i > 0) {
459  _cache << ", ";
460  }
461  if (sparsities[i].rows.empty()) {
462  _cache << "0";
463  } else {
464  _cache << name << i;
465  }
466  }
467  _cache << "};\n";
468  };
469 
470  if (maxNnzIndex > 0) {
471  makeArrayOfArrays("rows");
472  makeArrayOfArrays("cols");
473 
474  _cache << " ";
475  LanguageC<Base>::printStaticIndexArray(_cache, "nnzs", nnzs);
476 
477  _cache << "\n";
478 
479  _cache << " if(i < " << maxNnzIndex << ") {\n"
480  " *row = rows[i];\n"
481  " *col = cols[i];\n"
482  " *nnz = nnzs[i];\n"
483  " } else {\n"
484  " *row = 0;\n"
485  " *col = 0;\n"
486  " *nnz = 0;\n"
487  " }\n";
488  } else {
489  _cache << " *row = 0;\n"
490  " *col = 0;\n"
491  " *nnz = 0;\n";
492  }
493 
494  _cache << "}\n";
495 }
496 
497 template<class Base>
498 void ModelCSourceGen<Base>::generateSparsity1DSource2(const std::string& function,
499  const std::map<size_t, std::vector<size_t> >& elements) {
500  LanguageC<Base>::printFunctionDeclaration(_cache, "void", function, {"unsigned long pos",
501  "unsigned long const** elements",
502  "unsigned long* nnz"});
503  _cache << " {\n";
504 
505  std::vector<size_t> nnzs(elements.empty()? 0: elements.rbegin()->first + 1);
506 
507  long long int maxNnzIndex = -1;
508 
509  for (const auto& it : elements) {
510  // the size of each sparsity row
511  const std::vector<size_t>& els = it.second;
512  if (!els.empty()) {
513  _cache << " ";
514  std::ostringstream os;
515  os << "els" << it.first;
516  LanguageC<Base>::printStaticIndexArray(_cache, os.str(), els);
517 
518  maxNnzIndex = it.first;
519  nnzs[it.first] = els.size();
520  }
521  }
522 
523  maxNnzIndex++;
524  nnzs.resize(maxNnzIndex);
525 
526  if (maxNnzIndex > 0) {
527  _cache << " static " << LanguageC<Base>::U_INDEX_TYPE << " const * const els[" << maxNnzIndex << "] = {";
528  auto it = elements.begin();
529  for (size_t i = 0; i < size_t(maxNnzIndex); i++) {
530  if (i > 0) {
531  _cache << ", ";
532  }
533  if (it == elements.end() || i != it->first) {
534  _cache << "0";
535  } else {
536  _cache << "els" << i;
537  ++it;
538  }
539  }
540  _cache << "};\n";
541 
542  _cache << " ";
543  LanguageC<Base>::printStaticIndexArray(_cache, "nnzs", nnzs);
544 
545  _cache << "\n";
546 
547  _cache << " if(pos < " << maxNnzIndex << ") {\n"
548  " *elements = els[pos];\n"
549  " *nnz = nnzs[pos];\n"
550  " } else {\n"
551  " *elements = 0;\n"
552  " *nnz = 0;\n"
553  " }\n";
554  } else {
555  _cache << " *elements = 0;\n"
556  " *nnz = 0;\n";
557  }
558 
559  _cache << "}\n";
560 }
561 
562 template<class Base>
563 inline std::map<size_t, std::vector<std::set<size_t> > > ModelCSourceGen<Base>::determineOrderByCol(const std::map<size_t, std::vector<size_t> >& elements,
564  const LocalSparsityInfo& sparsity) {
565  return determineOrderByCol(elements, sparsity.rows, sparsity.cols);
566 }
567 
568 template<class Base>
569 inline std::map<size_t, std::vector<std::set<size_t> > > ModelCSourceGen<Base>::determineOrderByCol(const std::map<size_t, std::vector<size_t> >& elements,
570  const std::vector<size_t>& userRows,
571  const std::vector<size_t>& userCols) {
572  std::map<size_t, std::vector<std::set<size_t> > > userLocation;
573 
574  for (const auto& it : elements) {
575  size_t col = it.first;
576  const std::vector<size_t>& colElements = it.second;
577 
578  userLocation[col] = determineOrderByCol(col, colElements, userRows, userCols);
579  }
580 
581  return userLocation;
582 }
583 
584 template<class Base>
585 inline std::vector<std::set<size_t> > ModelCSourceGen<Base>::determineOrderByCol(size_t col,
586  const std::vector<size_t>& colElements,
587  const std::vector<size_t>& userRows,
588  const std::vector<size_t>& userCols) {
589  std::vector<std::set<size_t> > userLocationCol(colElements.size());
590 
591  for (size_t er = 0; er < colElements.size(); er++) {
592  size_t row = colElements[er];
593  for (size_t e = 0; e < userRows.size(); e++) {
594  if (userRows[e] == row && userCols[e] == col) {
595  userLocationCol[er].insert(e);
596  break;
597  }
598  }
599  }
600 
601  return userLocationCol;
602 }
603 
604 template<class Base>
605 inline std::map<size_t, std::vector<std::set<size_t> > > ModelCSourceGen<Base>::determineOrderByRow(const std::map<size_t, std::vector<size_t> >& elements,
606  const LocalSparsityInfo& sparsity) {
607  return determineOrderByRow(elements, sparsity.rows, sparsity.cols);
608 }
609 
610 template<class Base>
611 inline std::map<size_t, std::vector<std::set<size_t> > > ModelCSourceGen<Base>::determineOrderByRow(const std::map<size_t, std::vector<size_t> >& elements,
612  const std::vector<size_t>& userRows,
613  const std::vector<size_t>& userCols) {
614  std::map<size_t, std::vector<std::set<size_t> > > userLocation;
615 
616  for (const auto& it : elements) {
617  size_t row = it.first;
618  const std::vector<size_t>& rowsElements = it.second;
619  userLocation[row] = determineOrderByRow(row, rowsElements, userRows, userCols);
620  }
621 
622  return userLocation;
623 }
624 
625 template<class Base>
626 inline std::vector<std::set<size_t> > ModelCSourceGen<Base>::determineOrderByRow(size_t row,
627  const std::vector<size_t>& rowElements,
628  const std::vector<size_t>& userRows,
629  const std::vector<size_t>& userCols) {
630  std::vector<std::set<size_t> > userLocationRow(rowElements.size());
631 
632  for (size_t ec = 0; ec < rowElements.size(); ec++) {
633  size_t col = rowElements[ec];
634  for (size_t e = 0; e < userRows.size(); e++) {
635  if (userCols[e] == col && userRows[e] == row) {
636  userLocationRow[ec].insert(e);
637  break;
638  }
639  }
640  }
641 
642  return userLocationRow;
643 }
644 
645 template<class Base>
646 void ModelCSourceGen<Base>::printFileStartPThreads(std::ostringstream& cache,
647  const std::string& baseTypeName) {
648  cache << "\n";
649  cache << CPPADCG_PTHREAD_POOL_H_FILE << "\n";
650  cache << "\n";
651  cache << "typedef struct ExecArgStruct {\n"
652  " cppadcg_function_type func;\n"
653  " " << baseTypeName + " const *const * in;\n"
654  " " << baseTypeName + "* out[1];\n"
655  " struct LangCAtomicFun atomicFun;\n"
656  "} ExecArgStruct;\n"
657  "\n"
658  "static void exec_func(void* arg) {\n"
659  " ExecArgStruct* eArg = (ExecArgStruct*) arg;\n"
660  " (*eArg->func)(eArg->in, eArg->out, eArg->atomicFun);\n"
661  "}\n";
662 }
663 
664 template<class Base>
665 void ModelCSourceGen<Base>::printFunctionStartPThreads(std::ostringstream& cache,
666  size_t size) {
667  auto repeatFill = [&](const std::string& txt){
668  cache << "{";
669  for (size_t i = 0; i < size; ++i) {
670  if (i != 0) cache << ", ";
671  cache << txt;
672  }
673  cache << "};";
674  };
675 
676  cache << " ExecArgStruct* args[" << size << "];\n";
677  cache << " static cppadcg_thpool_function_type execute_functions[" << size << "] = ";
678  repeatFill("exec_func");
679  cache << "\n";
680  cache << " static float ref_elapsed[" << size << "] = ";
681  repeatFill("0");
682  cache << "\n";
683  cache << " static float elapsed[" << size << "] = ";
684  repeatFill("0");
685  cache << "\n"
686  " static int order[" << size << "] = {";
687  for (size_t i = 0; i < size; ++i) {
688  if (i != 0) cache << ", ";
689  cache << i;
690  }
691  cache << "};\n"
692  " static int job2Thread[" << size << "] = ";
693  repeatFill("-1");
694  cache << "\n"
695  " static int last_elapsed_changed = 1;\n"
696  " unsigned int nBench = cppadcg_thpool_get_n_time_meas();\n"
697  " static unsigned int n_meas = 0;\n"
698  " int do_benchmark = " << (size > 0 ? "(n_meas < nBench && !cppadcg_thpool_is_disabled())" : "0") << ";\n"
699  " float* elapsed_p = do_benchmark ? elapsed : NULL;\n";
700 }
701 
702 template<class Base>
703 void ModelCSourceGen<Base>::printFunctionEndPThreads(std::ostringstream& cache,
704  size_t size) {
705  cache << " cppadcg_thpool_add_jobs(execute_functions, (void**) args, ref_elapsed, elapsed_p, order, job2Thread, " << size << ", last_elapsed_changed" << ");\n"
706  "\n"
707  " cppadcg_thpool_wait();\n"
708  "\n"
709  " for(i = 0; i < " << size << "; ++i) {\n"
710  " free(args[i]);\n"
711  " }\n"
712  "\n"
713  " if(do_benchmark) {\n"
714  " cppadcg_thpool_update_order(ref_elapsed, n_meas, elapsed, order, " << size << ");\n"
715  " n_meas++;\n"
716  " } else {\n"
717  " last_elapsed_changed = 0;\n"
718  " }\n";
719 }
720 
721 template<class Base>
722 void ModelCSourceGen<Base>::printFileStartOpenMP(std::ostringstream& cache) {
723  cache << CPPADCG_OPENMP_H_FILE << "\n"
724  "#include <omp.h>\n"
725  "#include <stdio.h>\n"
726  "#include <time.h>\n";
727 }
728 
729 template<class Base>
730 void ModelCSourceGen<Base>::printFunctionStartOpenMP(std::ostringstream& cache,
731  size_t size) {
732  cache << "\n"
733  " enum omp_sched_t old_kind;\n"
734  " int old_modifier;\n"
735  " int enabled = !cppadcg_openmp_is_disabled();\n"
736  " int verbose = cppadcg_openmp_is_verbose();\n"
737  " struct timespec start[" << size << "];\n"
738  " struct timespec end[" << size << "];\n"
739  " int thread_id[" << size << "];\n"
740  " unsigned int n_threads = cppadcg_openmp_get_threads();\n"
741  " if(n_threads > " << size << ")\n"
742  " n_threads = " << size << ";\n"
743  "\n"
744  " if(enabled) {\n"
745  " omp_get_schedule(&old_kind, &old_modifier);\n"
746  " cppadcg_openmp_apply_scheduler_strategy();\n"
747  " }\n";
748 }
749 
750 template<class Base>
751 void ModelCSourceGen<Base>::printLoopStartOpenMP(std::ostringstream& cache,
752  size_t size) {
753  cache <<"#pragma omp parallel for private(outLocal) schedule(runtime) if(enabled) num_threads(n_threads)\n"
754  " for(i = 0; i < " << size << "; ++i) {\n"
755  " int info;\n"
756  " if(verbose) {\n"
757  " thread_id[i] = omp_get_thread_num();\n"
758  " info = clock_gettime(CLOCK_MONOTONIC, &start[i]);\n"
759  " if(info != 0) {\n"
760  " start[i].tv_sec = 0;\n"
761  " start[i].tv_nsec = 0;\n"
762  " end[i].tv_sec = 0;\n"
763  " end[i].tv_nsec = 0;\n"
764  " }\n"
765  " }\n"
766  "\n";
767 }
768 
769 template<class Base>
770 void ModelCSourceGen<Base>::printLoopEndOpenMP(std::ostringstream& cache,
771  size_t size) {
772  cache <<"\n"
773  " if(verbose) {\n"
774  " if(info == 0) {\n"
775  " info = clock_gettime(CLOCK_MONOTONIC, &end[i]);\n"
776  " if(info != 0) {\n"
777  " end[i].tv_sec = 0;\n"
778  " end[i].tv_nsec = 0;\n"
779  " }\n"
780  " }\n"
781  " }\n"
782  " }\n"
783  "\n"
784  " if(enabled) {\n"
785  " omp_set_schedule(old_kind, old_modifier);\n"
786  " }\n"
787  "\n"
788  " if(verbose) {\n"
789  " struct timespec diff;\n"
790  " for (i = 0; i < " << size << "; ++i) {\n"
791  " if ((end[i].tv_nsec - start[i].tv_nsec) < 0) {\n"
792  " diff.tv_sec = end[i].tv_sec - start[i].tv_sec - 1;\n"
793  " diff.tv_nsec = end[i].tv_nsec - start[i].tv_nsec + 1000000000;\n"
794  " } else {\n"
795  " diff.tv_sec = end[i].tv_sec - start[i].tv_sec;\n"
796  " diff.tv_nsec = end[i].tv_nsec - start[i].tv_nsec;\n"
797  " }\n"
798  " fprintf(stdout, \"## Thread %i, Job %li, started at %ld.%.9ld, ended at %ld.%.9ld, elapsed %ld.%.9ld\\n\",\n"
799  " thread_id[i], i, start[i].tv_sec, start[i].tv_nsec, end[i].tv_sec, end[i].tv_nsec, diff.tv_sec, diff.tv_nsec);\n"
800  " }\n"
801  " }\n";
802 
803 }
804 
805 template<class Base>
806 void ModelCSourceGen<Base>::startingJob(const std::string& jobName,
807  const JobType& type) {
808  if (_jobTimer != nullptr)
809  _jobTimer->startingJob(jobName, type);
810 }
811 
812 template<class Base>
814  if (_jobTimer != nullptr)
815  _jobTimer->finishedJob();
816 }
817 
822 template<>
824  return "double";
825 }
826 
827 template<>
828 inline std::string ModelCSourceGen<float>::baseTypeName() {
829  return "float";
830 }
831 
832 } // END cg namespace
833 } // END CppAD namespace
834 
835 #endif
std::vector< ModelCSourceGen< Base >::Color > colorByRow(const std::set< size_t > &columns, const SparsitySetType &sparsity)
virtual void generateGlobalDirectionalFunctionSource(const std::string &function, const std::string &function2_suffix, const std::string &function_sparsity, const std::map< size_t, std::vector< size_t > > &elements)
static void printFunctionDeclaration(std::ostringstream &out, const std::string &returnType, const std::string &functionName, const std::vector< std::string > &arguments, const std::vector< std::string > &arguments2={})
Definition: language_c.hpp:538