From 5b42483e81cd6a217f25a45b2d39d68462546f37 Mon Sep 17 00:00:00 2001 From: Michel Juillard <michel.juillard@mjui.fr> Date: Sun, 10 May 2015 18:16:11 +0200 Subject: [PATCH] adding feature to recompile MEX files only if the model has changed (not activated yet) detail of compilation code moved from preprocessor (ModFile.cc) to ./matlab/utilities/general/dyn_mex.m --- DynamicModel.cc | 94 ++++++++++++++++++++++++ DynamicModel.hh | 3 + ModFile.cc | 191 +++++++++++++++++++++--------------------------- ModFile.hh | 9 +++ 4 files changed, 188 insertions(+), 109 deletions(-) diff --git a/DynamicModel.cc b/DynamicModel.cc index f4957557..74d7a2c6 100644 --- a/DynamicModel.cc +++ b/DynamicModel.cc @@ -4221,5 +4221,99 @@ DynamicModel::dynamicOnlyEquationsNbr() const return eqs.size(); } +#ifndef PRIVATE_BUFFER_SIZE +#define PRIVATE_BUFFER_SIZE 1024 +#endif + +bool +DynamicModel::isChecksumMatching(const string &basename) const +{ + boost::crc_32_type result; + + std::stringstream buffer; + + // Write equation tags + for (size_t i = 0; i < equation_tags.size(); i++) + buffer << " " << equation_tags[i].first + 1 + << equation_tags[i].second.first + << equation_tags[i].second.second; + + ExprNodeOutputType buffer_type = oCDynamicModel; + + for (int eq = 0; eq < (int) equations.size(); eq++) + { + BinaryOpNode *eq_node = equations[eq]; + expr_t lhs = eq_node->get_arg1(); + expr_t rhs = eq_node->get_arg2(); + + // Test if the right hand side of the equation is empty. + double vrhs = 1.0; + try + { + vrhs = rhs->eval(eval_context_t()); + } + catch (ExprNode::EvalException &e) + { + } + + if (vrhs != 0) // The right hand side of the equation is not empty ==> residual=lhs-rhs; + { + buffer << "lhs ="; + lhs->writeOutput(buffer, buffer_type, temporary_terms); + buffer << ";" << endl; + + buffer << "rhs ="; + rhs->writeOutput(buffer, buffer_type, temporary_terms); + buffer << ";" << endl; + + buffer << "residual" << LEFT_ARRAY_SUBSCRIPT(buffer_type) + << eq + ARRAY_SUBSCRIPT_OFFSET(buffer_type) + << RIGHT_ARRAY_SUBSCRIPT(buffer_type) + << "= lhs-rhs;" << endl; + } + else // The right hand side of the equation is empty ==> residual=lhs; + { + buffer << "residual" << LEFT_ARRAY_SUBSCRIPT(buffer_type) + << eq + ARRAY_SUBSCRIPT_OFFSET(buffer_type) + << RIGHT_ARRAY_SUBSCRIPT(buffer_type) + << " = "; + lhs->writeOutput(buffer, buffer_type, temporary_terms); + buffer << ";" << endl; + } + } + char private_buffer[PRIVATE_BUFFER_SIZE]; + while(buffer) + { + buffer.get(private_buffer,PRIVATE_BUFFER_SIZE); + result.process_bytes(private_buffer,strlen(private_buffer)); + } + fstream checksum_file; + + string filename = basename + "/checksum"; + + // checksum_file.open(filename.c_str(), ios::in | ios::out | ios::binary); + checksum_file.open(filename.c_str(), ios::in | ios::binary); + unsigned int old_checksum = 0; + if (checksum_file.is_open()) + { + checksum_file >> old_checksum; + std::cout << "old_checksum " << old_checksum << endl; + } + if ((!checksum_file.is_open()) || (old_checksum != result.checksum())) + { + checksum_file.close(); + checksum_file.open(filename.c_str(), ios::out | ios::binary); + if (!checksum_file.is_open()) + { + cerr << "ERROR: Can't open file " << filename << endl; + exit(EXIT_FAILURE); + } + checksum_file << result.checksum(); + checksum_file.close(); + return false; + } + + return true; +} diff --git a/DynamicModel.hh b/DynamicModel.hh index 8efbc5d3..d96a7d50 100644 --- a/DynamicModel.hh +++ b/DynamicModel.hh @@ -24,6 +24,7 @@ using namespace std; #define ZERO_BAND 1e-8 #include <fstream> +#include <boost/crc.hpp> #include "StaticModel.hh" @@ -479,6 +480,8 @@ public: void writeSecondDerivativesC_csr(const string &basename, bool cuda) const; //! Writes C file containing third order derivatives of model evaluated at steady state (compressed sparse column) void writeThirdDerivativesC_csr(const string &basename, bool cuda) const; + + bool isChecksumMatching(const string &basename) const; }; //! Classes to re-order derivatives for various sparse storage formats diff --git a/ModFile.cc b/ModFile.cc index 6d9eca0e..9f8f73f5 100644 --- a/ModFile.cc +++ b/ModFile.cc @@ -469,55 +469,55 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output) // Compute static model and its derivatives dynamic_model.toStatic(static_model); if (!no_static) - { - if (mod_file_struct.stoch_simul_present - || mod_file_struct.estimation_present || mod_file_struct.osr_present - || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present - || mod_file_struct.calib_smoother_present) - static_model.set_cutoff_to_zero(); - - const bool static_hessian = mod_file_struct.identification_present - || mod_file_struct.estimation_analytic_derivation; - const bool paramsDerivatives = mod_file_struct.identification_present - || mod_file_struct.estimation_analytic_derivation; - static_model.computingPass(global_eval_context, no_tmp_terms, static_hessian, - false, paramsDerivatives, block, byte_code); - } + { + if (mod_file_struct.stoch_simul_present + || mod_file_struct.estimation_present || mod_file_struct.osr_present + || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present + || mod_file_struct.calib_smoother_present) + static_model.set_cutoff_to_zero(); + + const bool static_hessian = mod_file_struct.identification_present + || mod_file_struct.estimation_analytic_derivation; + const bool paramsDerivatives = mod_file_struct.identification_present + || mod_file_struct.estimation_analytic_derivation; + static_model.computingPass(global_eval_context, no_tmp_terms, static_hessian, + false, paramsDerivatives, block, byte_code); + } // Set things to compute for dynamic model if (mod_file_struct.perfect_foresight_solver_present || mod_file_struct.check_present - || mod_file_struct.stoch_simul_present - || mod_file_struct.estimation_present || mod_file_struct.osr_present - || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present - || mod_file_struct.calib_smoother_present) - { - if (mod_file_struct.perfect_foresight_solver_present) - dynamic_model.computingPass(true, false, false, false, global_eval_context, no_tmp_terms, block, use_dll, byte_code); - else - { - if (mod_file_struct.stoch_simul_present - || mod_file_struct.estimation_present || mod_file_struct.osr_present - || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present - || mod_file_struct.calib_smoother_present) - dynamic_model.set_cutoff_to_zero(); - if (mod_file_struct.order_option < 1 || mod_file_struct.order_option > 3) - { - cerr << "ERROR: Incorrect order option..." << endl; - exit(EXIT_FAILURE); - } - bool hessian = mod_file_struct.order_option >= 2 - || mod_file_struct.identification_present - || mod_file_struct.estimation_analytic_derivation - || output == second - || output == third; - bool thirdDerivatives = mod_file_struct.order_option == 3 - || mod_file_struct.estimation_analytic_derivation - || output == third; - bool paramsDerivatives = mod_file_struct.identification_present || mod_file_struct.estimation_analytic_derivation; - dynamic_model.computingPass(true, hessian, thirdDerivatives, paramsDerivatives, global_eval_context, no_tmp_terms, block, use_dll, byte_code); - } - } - else // No computing task requested, compute derivatives up to 2nd order by default - dynamic_model.computingPass(true, true, false, false, global_eval_context, no_tmp_terms, block, use_dll, byte_code); + || mod_file_struct.stoch_simul_present + || mod_file_struct.estimation_present || mod_file_struct.osr_present + || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present + || mod_file_struct.calib_smoother_present) + { + if (mod_file_struct.perfect_foresight_solver_present) + dynamic_model.computingPass(true, false, false, false, global_eval_context, no_tmp_terms, block, use_dll, byte_code); + else + { + if (mod_file_struct.stoch_simul_present + || mod_file_struct.estimation_present || mod_file_struct.osr_present + || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present + || mod_file_struct.calib_smoother_present) + dynamic_model.set_cutoff_to_zero(); + if (mod_file_struct.order_option < 1 || mod_file_struct.order_option > 3) + { + cerr << "ERROR: Incorrect order option..." << endl; + exit(EXIT_FAILURE); + } + bool hessian = mod_file_struct.order_option >= 2 + || mod_file_struct.identification_present + || mod_file_struct.estimation_analytic_derivation + || output == second + || output == third; + bool thirdDerivatives = mod_file_struct.order_option == 3 + || mod_file_struct.estimation_analytic_derivation + || output == third; + bool paramsDerivatives = mod_file_struct.identification_present || mod_file_struct.estimation_analytic_derivation; + dynamic_model.computingPass(true, hessian, thirdDerivatives, paramsDerivatives, global_eval_context, no_tmp_terms, block, use_dll, byte_code); + } + } + else // No computing task requested, compute derivatives up to 2nd order by default + dynamic_model.computingPass(true, true, false, false, global_eval_context, no_tmp_terms, block, use_dll, byte_code); } for (vector<Statement *>::iterator it = statements.begin(); @@ -649,18 +649,23 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo << " error('DYNARE: Can''t find bytecode DLL. Please compile it or remove the ''bytecode'' option.')" << endl << "end" << endl; - // Erase possible remnants of previous runs - unlink((basename + "_dynamic.m").c_str()); - unlink((basename + "_dynamic.cod").c_str()); - unlink((basename + "_dynamic.bin").c_str()); - - unlink((basename + "_static.m").c_str()); - unlink((basename + "_static.cod").c_str()); - unlink((basename + "_static.bin").c_str()); + bool hasModelChanged = !dynamic_model.isChecksumMatching(basename); + + if (hasModelChanged) + { + // Erase possible remnants of previous runs + unlink((basename + "_dynamic.m").c_str()); + unlink((basename + "_dynamic.cod").c_str()); + unlink((basename + "_dynamic.bin").c_str()); - unlink((basename + "_steadystate2.m").c_str()); - unlink((basename + "_set_auxiliary_variables.m").c_str()); + unlink((basename + "_static.m").c_str()); + unlink((basename + "_static.cod").c_str()); + unlink((basename + "_static.bin").c_str()); + unlink((basename + "_steadystate2.m").c_str()); + unlink((basename + "_set_auxiliary_variables.m").c_str()); + } + if (!use_dll) { mOutputFile << "erase_compiled_function('" + basename + "_static');" << endl; @@ -697,53 +702,19 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo // Compile the dynamic MEX file for use_dll option if (use_dll) { - mOutputFile << "if ~exist('OCTAVE_VERSION')" << endl; - // Some mex commands are enclosed in an eval(), because otherwise it will make Octave fail #if defined(_WIN32) || defined(__CYGWIN32__) if (msvc) // MATLAB/Windows + Microsoft Visual C++ - mOutputFile << " eval('mex -O LINKFLAGS=\"$LINKFLAGS /export:Dynamic\" " << basename << "_dynamic.c " << basename << "_dynamic_mex.c')" << endl - << " eval('mex -O LINKFLAGS=\"$LINKFLAGS /export:Static\" " << basename << "_static.c "<< basename << "_static_mex.c')" << endl; + mOutputFile << "dyn_mex('msvc', '" << basename << ", 1)" << endl; else if (cygwin) // MATLAB/Windows + Cygwin g++ - mOutputFile << " eval('mex -O PRELINK_CMDS1=\"echo EXPORTS > mex.def & echo mexFunction >> mex.def & echo Dynamic >> mex.def\" " << basename << "_dynamic.c " << basename << "_dynamic_mex.c')" << endl - << " eval('mex -O PRELINK_CMDS1=\"echo EXPORTS > mex.def & echo mexFunction >> mex.def & echo Static >> mex.def\" " << basename << "_static.c "<< basename << "_static_mex.c')" << endl; + mOutputFile << "dyn_mex('cygwin', '" << basename << "', 1)" << endl; else mOutputFile << " error('When using the USE_DLL option, you must give either ''cygwin'' or ''msvc'' option to the ''dynare'' command')" << endl; #else -# ifdef __linux__ - // MATLAB/Linux - mOutputFile << " if matlab_ver_less_than('8.3')" << endl - << " eval('mex -O LDFLAGS=''-pthread -shared -Wl,--no-undefined'' " << basename << "_dynamic.c " << basename << "_dynamic_mex.c')" << endl - << " eval('mex -O LDFLAGS=''-pthread -shared -Wl,--no-undefined'' " << basename << "_static.c "<< basename << "_static_mex.c')" << endl - << " else" << endl - << " eval('mex -O LINKEXPORT='''' " << basename << "_dynamic.c " << basename << "_dynamic_mex.c')" << endl - << " eval('mex -O LINKEXPORT='''' " << basename << "_static.c "<< basename << "_static_mex.c')" << endl - << " end" << endl; -# else // MacOS - // MATLAB/MacOS - mOutputFile << " if matlab_ver_less_than('8.3')" << endl - << " if matlab_ver_less_than('8.1')" << endl - << " eval('mex -O LDFLAGS=''-Wl,-twolevel_namespace -undefined error -arch \\$ARCHS -Wl,-syslibroot,\\$SDKROOT -mmacosx-version-min=\\$MACOSX_DEPLOYMENT_TARGET -bundle'' " - << basename << "_dynamic.c " << basename << "_dynamic_mex.c')" << endl - << " eval('mex -O LDFLAGS=''-Wl,-twolevel_namespace -undefined error -arch \\$ARCHS -Wl,-syslibroot,\\$SDKROOT -mmacosx-version-min=\\$MACOSX_DEPLOYMENT_TARGET -bundle'' " - << basename << "_static.c " << basename << "_static_mex.c')" << endl - << " else" << endl - << " eval('mex -O LDFLAGS=''-Wl,-twolevel_namespace -undefined error -arch \\$ARCHS -Wl,-syslibroot,\\$MW_SDKROOT -mmacosx-version-min=\\$MACOSX_DEPLOYMENT_TARGET -bundle'' " - << basename << "_dynamic.c " << basename << "_dynamic_mex.c')" << endl - << " eval('mex -O LDFLAGS=''-Wl,-twolevel_namespace -undefined error -arch \\$ARCHS -Wl,-syslibroot,\\$MW_SDKROOT -mmacosx-version-min=\\$MACOSX_DEPLOYMENT_TARGET -bundle'' " - << basename << "_static.c " << basename << "_static_mex.c')" << endl - << " end" << endl - << " else" << endl - << " eval('mex -O LINKEXPORT='''' " << basename << "_dynamic.c " << basename << "_dynamic_mex.c')" << endl - << " eval('mex -O LINKEXPORT='''' " << basename << "_static.c "<< basename << "_static_mex.c')" << endl - << " end" << endl; -# endif + // other configurations + mOutputFile << "dyn_mex('', '" << basename << "', 1)" << endl; #endif - mOutputFile << "else" << endl // Octave - << " mex " << basename << "_dynamic.c " << basename << "_dynamic_mex.c" << endl - << " mex " << basename << "_static.c " << basename << "_static_mex.c" << endl - << "end" << endl; } // Add path for block option with M-files @@ -824,22 +795,24 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo mOutputFile.close(); - // Create static and dynamic files - if (dynamic_model.equation_number() > 0) + if (hasModelChanged) { - if (!no_static) - { - static_model.writeStaticFile(basename, block, byte_code, use_dll); - static_model.writeParamsDerivativesFile(basename); - } + // Create static and dynamic files + if (dynamic_model.equation_number() > 0) + { + if (!no_static) + { + static_model.writeStaticFile(basename, block, byte_code, use_dll); + static_model.writeParamsDerivativesFile(basename); + } - dynamic_model.writeDynamicFile(basename, block, byte_code, use_dll, mod_file_struct.order_option); - dynamic_model.writeParamsDerivativesFile(basename); - } - - // Create steady state file - steady_state_model.writeSteadyStateFile(basename, mod_file_struct.ramsey_model_present); + dynamic_model.writeDynamicFile(basename, block, byte_code, use_dll, mod_file_struct.order_option); + dynamic_model.writeParamsDerivativesFile(basename); + } + // Create steady state file + steady_state_model.writeSteadyStateFile(basename, mod_file_struct.ramsey_model_present); + } + cout << "done" << endl; } - diff --git a/ModFile.hh b/ModFile.hh index 722ea534..0a384931 100644 --- a/ModFile.hh +++ b/ModFile.hh @@ -24,6 +24,8 @@ using namespace std; #include <ostream> #include <ctime> +#include <iostream> +#include <sstream> #include "SymbolTable.hh" #include "NumericalConstants.hh" @@ -37,6 +39,11 @@ using namespace std; #include "WarningConsolidation.hh" #include "ExtendedPreprocessorTypes.hh" +// for checksum computation +#ifndef PRIVATE_BUFFER_SIZE +#define PRIVATE_BUFFER_SIZE 1024 +#endif + //! The abstract representation of a "mod" file class ModFile { @@ -153,6 +160,8 @@ public: //! Writes Cpp output files only => No further Matlab processing void writeCCOutputFiles(const string &basename) const; void writeModelCC(const string &basename) const; + + void computeChecksum(); }; #endif // ! MOD_FILE_HH -- GitLab