From faa12910552c82bf5cb92d700bd12817408d22aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= Date: Tue, 11 Apr 2023 15:29:12 +0200 Subject: [PATCH] use_dll: turn getPowerDeriv() and sign() into inline functions This allows the compiler to better optimize by inlining those call when worth it. --- src/DataTree.cc | 10 ++++++---- src/DataTree.hh | 9 +++++++-- src/ModelTree.hh | 34 +++++++++++----------------------- src/StaticModel.cc | 1 + 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/DataTree.cc b/src/DataTree.cc index 074d31a1..d90d6853 100644 --- a/src/DataTree.cc +++ b/src/DataTree.cc @@ -894,7 +894,8 @@ DataTree::writeCHelpersDefinition(ostream &output) const { if (isBinaryOpUsed(BinaryOpcode::powerDeriv)) output << "// The k-th derivative of x^p" << endl - << "double getPowerDeriv(double x, double p, int k)" << endl + << "inline double" << endl + << "getPowerDeriv(double x, double p, int k)" << endl << "{" << endl << " if (fabs(x) < " << power_deriv_near_zero << " && p > 0 && k > p && fabs(p-nearbyint(p)) < " << power_deriv_near_zero << ')' << endl << " return 0.0;" << endl @@ -908,7 +909,8 @@ DataTree::writeCHelpersDefinition(ostream &output) const << "}" << endl; if (isUnaryOpUsed(UnaryOpcode::sign)) - output << "double sign(double x)" << endl + output << "inline double" << endl + << "sign(double x)" << endl << "{" << endl << " return (x > 0) ? 1 : ((x < 0) ? -1 : 0);" << endl << "}" << endl; @@ -918,9 +920,9 @@ void DataTree::writeCHelpersDeclaration(ostream &output) const { if (isBinaryOpUsed(BinaryOpcode::powerDeriv)) - output << "double getPowerDeriv(double x, double p, int k);" << endl; + output << "extern inline double getPowerDeriv(double x, double p, int k);" << endl; if (isUnaryOpUsed(UnaryOpcode::sign)) - output << "double sign(double x);" << endl; + output << "extern inline double sign(double x);" << endl; } vector diff --git a/src/DataTree.hh b/src/DataTree.hh index 108fb253..c3f351ba 100644 --- a/src/DataTree.hh +++ b/src/DataTree.hh @@ -277,9 +277,14 @@ public: //! Returns the minimum lag (as a negative number) of the given symbol in the whole data tree (and not only in the equations !!) /*! Returns 0 if the symbol is not used */ int minLagForSymbol(int symb_id) const; - //! Writes definitions of C function helpers (getPowerDeriv(), sign()) + /* Writes definitions of C function helpers (getPowerDeriv(), sign()) as + inline functions */ void writeCHelpersDefinition(ostream &output) const; - //! Writes declarations of C function helpers (getPowerDeriv(), sign()) + /* Writes declarations of C function helpers (getPowerDeriv(), sign()) as + extern inline (external definition). Those need to be included in exactly + one translation unit. That external definition will be used or not, + depending on the optimization decision by the compiler. + See https://en.cppreference.com/w/c/language/inline */ void writeCHelpersDeclaration(ostream &output) const; //! Thrown when trying to access an unknown variable by deriv_id class UnknownDerivIDException diff --git a/src/ModelTree.hh b/src/ModelTree.hh index f1ab64ad..73b88516 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -973,7 +973,7 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext, output << "#include " << endl << R"(#include "mex.h")" << endl // Needed for calls to external functions << endl; - writeCHelpersDeclaration(output); + writeCHelpersDefinition(output); output << endl << prototype_tt << endl << "{" << endl @@ -1012,7 +1012,9 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext, output << "#include " << endl << R"(#include "mex.h")" << endl // Needed for calls to external functions << endl; - writeCHelpersDeclaration(output); + writeCHelpersDefinition(output); + if (i == 0) + writeCHelpersDeclaration(output); // Provide external definition of helpers in resid main file output << endl << prototype_main << endl << "{" << endl @@ -1041,10 +1043,6 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext, << R"(#include "mex.h")" << endl; for (const auto &it : header_files) output << "#include " << it.filename() << endl; - output << endl; - - writeCHelpersDefinition(output); - output << endl << "void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])" << endl << "{" << endl; @@ -2640,18 +2638,6 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext, } }; - /* Write source files for the derivative of the power function. - NB: The prefix (static/dynamic) is added to the filename (even though it’s - the same source between static and dynamic) to avoid a race condition when - static and dynamic are compiled in parallel. */ - filesystem::path helpers_src {model_src_dir / (prefix + "helpers.c")}; - open_file(helpers_src); - output << "#include " << endl << endl; - writeCHelpersDefinition(output); - output.close(); - auto helpers_object {compileMEX(model_src_dir, (prefix + "helpers"), - mexext, { helpers_src }, matlabroot, false)}; - size_t ttlen {0}; // Helper for dealing with y, x, params and steady_state inputs (shared with block case) @@ -2719,7 +2705,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext, output << "#include " << endl << R"(#include "mex.h")" << endl // Needed for calls to external functions << endl; - writeCHelpersDeclaration(output); + writeCHelpersDefinition(output); output << endl << prototype_tt << endl << "{" << endl @@ -2742,7 +2728,8 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext, output << "#include " << endl << R"(#include "mex.h")" << endl // Needed for calls to external functions << endl; - writeCHelpersDeclaration(output); + writeCHelpersDefinition(output); + writeCHelpersDeclaration(output); // Provide external definition of helpers in main file output << endl << prototype_main << endl << "{" << endl @@ -2831,7 +2818,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext, << "}" << endl; output.close(); - vector mex_input_files { helpers_object, main_object_file, source_mex }; + vector mex_input_files { main_object_file, source_mex }; for (int j {0}; j <= i; j++) mex_input_files.push_back(tt_object_files[j]); compileMEX(mex_dir, funcname, mexext, mex_input_files, matlabroot); @@ -2860,7 +2847,8 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext, output << "#include " << endl << R"(#include "mex.h")" << endl << endl; - writeCHelpersDeclaration(output); + writeCHelpersDefinition(output); + writeCHelpersDeclaration(output); // Provide external definition of helpers output << endl << "void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])" << endl << "{" << endl @@ -2924,7 +2912,7 @@ ModelTree::writeSparseModelCFiles(const string &basename, const string &mexext, } output << "}" << endl; output.close(); - compileMEX(block_dir, funcname, mexext, { source_mex, helpers_object }, matlabroot); + compileMEX(block_dir, funcname, mexext, { source_mex }, matlabroot); } } } diff --git a/src/StaticModel.cc b/src/StaticModel.cc index a923d322..7d3b9f79 100644 --- a/src/StaticModel.cc +++ b/src/StaticModel.cc @@ -921,6 +921,7 @@ StaticModel::writeRamseyMultipliersDerivativesCFile(const string &basename, cons << R"(#include "mex.h")" << endl // Needed for calls to external functions << endl; writeCHelpersDefinition(output); + writeCHelpersDeclaration(output); // Provide external definition of helpers output << endl << "void ramsey_multipliers_static_g1(const double *restrict y, const double *restrict x, const double *restrict params, double *restrict T, double *restrict g1m_v)" << endl << "{" << endl;