Commit a5a5490a authored by MichelJuillard's avatar MichelJuillard
Browse files

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
parent 16a29d58
function dyn_mex(win_compiler,basename,force)
% Compile Dynare model dlls when model option use_dll is used
% if C file is fresher than mex file
%
% INPUTS
% o win_compiler str compiler used under Windows (unused under Linux or OSX):
% 'msvc' (MS Visual C)
% 'cygwin'
% o basename str filenames base
% o force bool recompile if 1
%
% OUTPUTS
% none
%
% Copyright (C) 2015 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
Dc = dir([basename '_dynamic.c']);
Dmex = dir([basename '_dynamic.' mexext]);
% compile only if date of C file is greater than date of mex file
% and force is not True
if (Dmex.datenum > Dc.datenum) && ~force
disp('Mex files are newer than the source: not recompiled')
return
end
if ~exist('OCTAVE_VERSION')
% Some mex commands are enclosed in an eval(), because otherwise it will make Octave fail
if ispc
if msvc
% MATLAB/Windows + Microsoft Visual C++
eval(['mex -O LINKFLAGS="$LINKFLAGS /export:Dynamic" ' basename '_dynamic.c ' basename '_dynamic_mex.c'])
eval(['mex -O LINKFLAGS="$LINKFLAGS /export:Dynamic" ' basename '_static.c ' basename '_static_mex.c'])
elseif cygwin
% MATLAB/Windows + Cygwin g++
eval(['mex -O PRELINK_CMDS1="echo EXPORTS > mex.def & echo ' ...
'mexFunction >> mex.def & echo Dynamic >> mex.def" ' ...
basename '_dynamic.c ' basename '_dynamic_mex.c'])
eval(['mex -O PRELINK_CMDS1="echo EXPORTS > mex.def & echo ' ...
'mexFunction >> mex.def & echo Dynamic >> mex.def" ' ...
basename '_static.c ' basename '_static_mex.c'])
else
error(['When using the USE_DLL option, you must give either ' ...
'''cygwin'' or ''msvc'' option to the ''dynare'' command'])
end
elseif isunix
% MATLAB/Linux
if matlab_ver_less_than('8.3')
eval(['mex -O LDFLAGS=''-pthread -shared -Wl,--no-undefined'' ' ...
basename '_dynamic.c ' basename '_dynamic_mex.c'])
eval(['mex -O LDFLAGS=''-pthread -shared -Wl,--no-undefined'' ' ...
basename '_static.c ' basename '_static_mex.c'])
else
eval(['mex -O LINKEXPORT='''' ' basename '_dynamic.c ' basename '_dynamic_mex.c'])
eval(['mex -O LINKEXPORT='''' ' basename '_static.c ' basename '_static_mex.c'])
end
elseif ismac
% MATLAB/MacOS
if matlab_ver_less_than('8.3')
if matlab_ver_less_than('8.1')
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'])
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'])
else
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'])
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'])
end
else
eval(['mex -O LINKEXPORT='''' ' basename '_dynamic.c ' ...
basename '_dynamic_mex.c'])
eval(['mex -O LINKEXPORT='''' ' basename '_static.c ' basename ...
'_static_mex.c'])
end
end
else
% Octave
eval(['mex ' basename '_dynamic.c ' basename '_dynamic_mex.c'])
eval(['mex ' basename '_static.c ' basename '_static_mex.c'])
end
......@@ -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;
}
......@@ -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
......
......@@ -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;
}
......@@ -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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment