CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
20namespace CppAD {
21namespace cg {
22
23template<class Base>
24const std::string ModelCSourceGen<Base>::FUNCTION_FORWAD_ZERO = "forward_zero";
25
26template<class Base>
27const std::string ModelCSourceGen<Base>::FUNCTION_JACOBIAN = "jacobian";
28
29template<class Base>
30const std::string ModelCSourceGen<Base>::FUNCTION_HESSIAN = "hessian";
31
32template<class Base>
33const std::string ModelCSourceGen<Base>::FUNCTION_FORWARD_ONE = "forward_one";
34
35template<class Base>
36const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_ONE = "reverse_one";
37
38template<class Base>
39const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_TWO = "reverse_two";
40
41template<class Base>
42const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_JACOBIAN = "sparse_jacobian";
43
44template<class Base>
45const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_HESSIAN = "sparse_hessian";
46
47template<class Base>
48const std::string ModelCSourceGen<Base>::FUNCTION_JACOBIAN_SPARSITY = "jacobian_sparsity";
49
50template<class Base>
51const std::string ModelCSourceGen<Base>::FUNCTION_HESSIAN_SPARSITY = "hessian_sparsity";
52
53template<class Base>
54const std::string ModelCSourceGen<Base>::FUNCTION_HESSIAN_SPARSITY2 = "hessian_sparsity2";
55
56template<class Base>
57const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_FORWARD_ONE = "sparse_forward_one";
58
59template<class Base>
60const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_REVERSE_ONE = "sparse_reverse_one";
61
62template<class Base>
63const std::string ModelCSourceGen<Base>::FUNCTION_SPARSE_REVERSE_TWO = "sparse_reverse_two";
64
65template<class Base>
66const std::string ModelCSourceGen<Base>::FUNCTION_FORWARD_ONE_SPARSITY = "forward_one_sparsity";
67
68template<class Base>
69const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_ONE_SPARSITY = "reverse_one_sparsity";
70
71template<class Base>
72const std::string ModelCSourceGen<Base>::FUNCTION_REVERSE_TWO_SPARSITY = "sparse_reverse_two_sparsity";
73
74template<class Base>
75const std::string ModelCSourceGen<Base>::FUNCTION_INFO = "info";
76
77template<class Base>
78const std::string ModelCSourceGen<Base>::FUNCTION_ATOMIC_FUNC_NAMES = "atomic_functions";
79
80template<class Base>
81const std::string ModelCSourceGen<Base>::CONST = "const";
82
83template<class Base>
84VariableNameGenerator<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
91template<class Base>
92const 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
100template<class Base>
101void 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
160template<class Base>
161void 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
191template<class Base>
192void 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
216template<class Base>
217void 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
237template<class Base>
238bool ModelCSourceGen<Base>::isAtomicsUsed() {
239 if (_zeroEvaluated) {
240 return _atomicFunctions.size() > 0;
241 } else {
242 return !getAtomicsInfo().empty();
243 }
244}
245
246template<class Base>
247const 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
255template<class Base>
256std::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
313template<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
359template<class Base>
360template<class T>
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
372template<class Base>
373void 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
388template<class Base>
389void 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
414template<class Base>
415void 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
497template<class Base>
498void 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
562template<class Base>
563inline 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
568template<class Base>
569inline 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
584template<class Base>
585inline 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
604template<class Base>
605inline 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
610template<class Base>
611inline 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
625template<class Base>
626inline 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
645template<class Base>
646void 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
664template<class Base>
665void 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
702template<class Base>
703void 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
721template<class Base>
722void 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
729template<class Base>
730void 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
750template<class Base>
751void 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
769template<class Base>
770void 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
805template<class Base>
806void ModelCSourceGen<Base>::startingJob(const std::string& jobName,
807 const JobType& type) {
808 if (_jobTimer != nullptr)
809 _jobTimer->startingJob(jobName, type);
810}
811
812template<class Base>
813inline void ModelCSourceGen<Base>::finishedJob() {
814 if (_jobTimer != nullptr)
815 _jobTimer->finishedJob();
816}
817
822template<>
824 return "double";
825}
826
827template<>
828inline std::string ModelCSourceGen<float>::baseTypeName() {
829 return "float";
830}
831
832} // END cg namespace
833} // END CppAD namespace
834
835#endif
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={})
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)
std::vector< ModelCSourceGen< Base >::Color > colorByRow(const std::set< size_t > &columns, const SparsitySetType &sparsity)