Skip to content

Commit 4a2dcc0

Browse files
farahkhashmanjenkins
authored andcommitted
Merge branch 'master' into 'QPR-12101'
2 parents ed7e206 + e32af46 commit 4a2dcc0

28 files changed

Lines changed: 367 additions & 136 deletions

Docker/.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ DEBIAN_TAG=11.7
33
# it's recommended to include CMAKE_BUILD_TYPE and BOOST_VARIANT in QL_TAG, ORE_TAG, BOOST_TAG
44
# to distinguish a release build from a debug build
55

6-
QL_TAG=1.31.1_f5b9affc3
6+
QL_TAG=1.31.1_f5b9affc
77
ORE_TAG=latest
88

99
# debug or release

OREAnalytics/orea/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ app/analytics/simmanalytic.cpp
2626
app/analytics/varanalytic.cpp
2727
app/analytics/xvaanalytic.cpp
2828
app/analyticsmanager.cpp
29+
app/cleanupsingletons.cpp
2930
app/inputparameters.cpp
3031
app/marketcalibrationreport.cpp
3132
app/marketdatacsvloader.cpp
@@ -169,6 +170,7 @@ app/analytics/simmanalytic.hpp
169170
app/analytics/varanalytic.hpp
170171
app/analytics/xvaanalytic.hpp
171172
app/analyticsmanager.hpp
173+
app/cleanupsingletons.hpp
172174
app/inputparameters.hpp
173175
app/marketcalibrationreport.hpp
174176
app/marketdatacsvloader.hpp
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
Copyright (C) 2017 Quaternion Risk Management Ltd
3+
All rights reserved.
4+
5+
This file is part of ORE, a free-software/open-source library
6+
for transparent pricing and risk analysis - http://opensourcerisk.org
7+
8+
ORE is free software: you can redistribute it and/or modify it
9+
under the terms of the Modified BSD License. You should have received a
10+
copy of the license along with this program.
11+
The license is also available online at <http://opensourcerisk.org>
12+
13+
This program is distributed on the basis that it will form a useful
14+
contribution to risk analytics and model standardisation, but WITHOUT
15+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+
FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17+
*/
18+
19+
#include <orea/app/cleanupsingletons.hpp>
20+
#include <orea/engine/observationmode.hpp>
21+
22+
#include <ored/portfolio/scriptedtrade.hpp>
23+
#include <ored/utilities/calendarparser.hpp>
24+
#include <ored/utilities/currencyparser.hpp>
25+
#include <ored/utilities/indexnametranslator.hpp>
26+
#include <ored/utilities/log.hpp>
27+
28+
#include <qle/math/computeenvironment.hpp>
29+
#include <qle/math/randomvariable.hpp>
30+
#include <qle/pricingengines/mcmultilegbaseengine.hpp>
31+
#include <qle/utilities/savedobservablesettings.hpp>
32+
33+
namespace ore::analytics {
34+
35+
CleanUpThreadLocalSingletons::~CleanUpThreadLocalSingletons() {
36+
QuantLib::IndexManager::instance().clearHistories();
37+
QuantExt::DividendManager::instance().clearHistories();
38+
ore::analytics::ObservationMode::instance().setMode(ore::analytics::ObservationMode::Mode::None);
39+
QuantExt::ComputeEnvironment::instance().reset();
40+
QuantExt::RandomVariableStats::instance().reset();
41+
QuantExt::McEngineStats::instance().reset();
42+
}
43+
44+
CleanUpThreadGlobalSingletons::~CleanUpThreadGlobalSingletons() {
45+
ore::data::InstrumentConventions::instance().clear();
46+
ore::data::IndexNameTranslator::instance().clear();
47+
ore::data::CalendarParser::instance().reset();
48+
ore::data::CurrencyParser::instance().reset();
49+
ore::data::ScriptLibraryStorage::instance().clear();
50+
}
51+
52+
CleanUpLogSingleton::CleanUpLogSingleton(const bool removeLoggers, const bool clearIndependentLoggers)
53+
: removeLoggers_(removeLoggers), clearIndependentLoggers_(clearIndependentLoggers) {}
54+
55+
CleanUpLogSingleton::~CleanUpLogSingleton() {
56+
if (clearIndependentLoggers_)
57+
ore::data::Log::instance().clearAllIndependentLoggers();
58+
if (removeLoggers_)
59+
ore::data::Log::instance().removeAllLoggers();
60+
}
61+
62+
} // namespace ore::data
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright (C) 2017 Quaternion Risk Management Ltd
3+
All rights reserved.
4+
5+
This file is part of ORE, a free-software/open-source library
6+
for transparent pricing and risk analysis - http://opensourcerisk.org
7+
8+
ORE is free software: you can redistribute it and/or modify it
9+
under the terms of the Modified BSD License. You should have received a
10+
copy of the license along with this program.
11+
The license is also available online at <http://opensourcerisk.org>
12+
13+
This program is distributed on the basis that it will form a useful
14+
contribution to risk analytics and model standardisation, but WITHOUT
15+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+
FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17+
*/
18+
19+
#pragma once
20+
21+
#include <ql/settings.hpp>
22+
#include <qle/utilities/savedobservablesettings.hpp>
23+
24+
namespace ore::analytics {
25+
26+
class CleanUpThreadLocalSingletons {
27+
public:
28+
QuantLib::SavedSettings savedSettings;
29+
QuantExt::SavedObservableSettings savedObservableSettings;
30+
~CleanUpThreadLocalSingletons();
31+
};
32+
33+
class CleanUpThreadGlobalSingletons {
34+
public:
35+
~CleanUpThreadGlobalSingletons();
36+
};
37+
38+
class CleanUpLogSingleton {
39+
public:
40+
CleanUpLogSingleton(const bool removeLoggers = false, const bool clearIndependentLoggers = true);
41+
~CleanUpLogSingleton();
42+
43+
private:
44+
bool removeLoggers_, clearIndependentLoggers_;
45+
};
46+
47+
} // namespace ore::analytics

OREAnalytics/orea/app/oreapp.cpp

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#pragma warning(disable : 4503)
2626
#endif
2727

28+
#include <orea/app/cleanupsingletons.hpp>
2829
#include <orea/app/marketdatacsvloader.hpp>
2930
#include <orea/app/marketdatainmemoryloader.hpp>
3031
#include <orea/app/oreapp.hpp>
@@ -40,6 +41,7 @@
4041

4142
#include <qle/version.hpp>
4243

44+
4345
#include <ql/cashflows/floatingratecoupon.hpp>
4446
#include <ql/time/calendars/all.hpp>
4547
#include <ql/time/daycounters/all.hpp>
@@ -157,7 +159,7 @@ boost::shared_ptr<AggregationScenarioData> OREApp::getMarketCube(std::string cub
157159
}
158160

159161
std::vector<std::string> OREApp::getErrors() {
160-
return structuredLogger_->messages();
162+
return errorMessages_;
161163
}
162164

163165
Real OREApp::getRunTime() {
@@ -287,60 +289,57 @@ void OREApp::analytics() {
287289
LOG("ORE analytics done");
288290
}
289291

290-
OREApp::OREApp(boost::shared_ptr<Parameters> params, bool console,
291-
const boost::filesystem::path& logRootPath)
292-
: params_(params), inputs_(nullptr) {
293292

294-
if (console) {
293+
void OREApp::initFromParams() {
294+
if (console_) {
295295
ConsoleLog::instance().switchOn();
296296
}
297297

298-
string outputPath = params_->get("setup", "outputPath");
299-
string logFile = outputPath + "/" + params_->get("setup", "logFile");
300-
Size logMask = 15;
298+
outputPath_ = params_->get("setup", "outputPath");
299+
logFile_ = outputPath_ + "/" + params_->get("setup", "logFile");
300+
logMask_ = 15;
301301
// Get log mask if available
302302
if (params_->has("setup", "logMask")) {
303-
logMask = static_cast<Size>(parseInteger(params_->get("setup", "logMask")));
303+
logMask_ = static_cast<Size>(parseInteger(params_->get("setup", "logMask")));
304304
}
305305

306-
string progressLogFile, structuredLogFile;
307-
Size progressLogRotationSize = 0;
308-
bool progressLogToConsole = false;
309-
Size structuredLogRotationSize = 0;
306+
progressLogRotationSize_ = 0;
307+
progressLogToConsole_ = false;
308+
structuredLogRotationSize_ = 0;
310309

311310
if (params_->hasGroup("logging")) {
312-
string logFileOverride = params_->get("logging", "logFile", false);
313-
if (!logFileOverride.empty()) {
314-
logFile = outputPath + '/' + logFileOverride;
311+
string tmp = params_->get("logging", "logFile", false);
312+
if (!tmp.empty()) {
313+
logFile_ = outputPath_ + '/' + tmp;
315314
}
316-
string logMaskOverride = params_->get("logging", "logMask", false);
317-
if (!logMaskOverride.empty()) {
318-
logMask = static_cast<Size>(parseInteger(logMaskOverride));
315+
tmp = params_->get("logging", "logMask", false);
316+
if (!tmp.empty()) {
317+
logMask_ = static_cast<Size>(parseInteger(tmp));
319318
}
320-
progressLogFile = params_->get("logging", "progressLogFile", false);
321-
if (!progressLogFile.empty()) {
322-
progressLogFile = outputPath + '/' + progressLogFile;
319+
tmp = params_->get("logging", "progressLogFile", false);
320+
if (!tmp.empty()) {
321+
progressLogFile_ = outputPath_ + '/' + tmp;
323322
}
324-
string tmp = params_->get("logging", "progressLogRotationSize", false);
323+
tmp = params_->get("logging", "progressLogRotationSize", false);
325324
if (!tmp.empty()) {
326-
progressLogRotationSize = static_cast<Size>(parseInteger(tmp));
325+
progressLogRotationSize_ = static_cast<Size>(parseInteger(tmp));
327326
}
328327
tmp = params_->get("logging", "progressLogToConsole", false);
329328
if (!tmp.empty()) {
330-
progressLogToConsole = ore::data::parseBool(tmp);
329+
progressLogToConsole_ = ore::data::parseBool(tmp);
331330
}
332-
structuredLogFile = params_->get("logging", "structuredLogFile", false);
333-
if (!structuredLogFile.empty()) {
334-
structuredLogFile = outputPath + '/' + structuredLogFile;
331+
tmp = params_->get("logging", "structuredLogFile", false);
332+
if (!tmp.empty()) {
333+
structuredLogFile_ = outputPath_ + '/' + tmp;
335334
}
336335
tmp = params_->get("logging", "structuredLogRotationSize", false);
337336
if (!tmp.empty()) {
338-
structuredLogRotationSize = static_cast<Size>(parseInteger(tmp));
337+
structuredLogRotationSize_ = static_cast<Size>(parseInteger(tmp));
339338
}
340339
}
341340

342-
setupLog(outputPath, logFile, logMask, logRootPath, progressLogFile, progressLogRotationSize, progressLogToConsole,
343-
structuredLogFile, structuredLogRotationSize);
341+
setupLog(outputPath_, logFile_, logMask_, logRootPath_, progressLogFile_, progressLogRotationSize_, progressLogToConsole_,
342+
structuredLogFile_, structuredLogRotationSize_);
344343

345344
// Log the input parameters
346345
params_->log();
@@ -353,20 +352,18 @@ OREApp::OREApp(boost::shared_ptr<Parameters> params, bool console,
353352
CONSOLE("OK");
354353

355354
Settings::instance().evaluationDate() = inputs_->asof();
356-
}
357-
358-
OREApp::OREApp(const boost::shared_ptr<InputParameters>& inputs, const std::string& logFile, Size logLevel,
359-
bool console, const boost::filesystem::path& logRootPath)
360-
: params_(nullptr), inputs_(inputs) {
361-
355+
}
356+
357+
void OREApp::initFromInputs() {
362358
// Initialise Singletons
363359
Settings::instance().evaluationDate() = inputs_->asof();
364360
InstrumentConventions::instance().setConventions(inputs_->conventions());
365-
if (console) {
361+
if (console_) {
366362
ConsoleLog::instance().switchOn();
367363
}
368364

369-
setupLog(inputs_->resultsPath().string(), logFile, logLevel, logRootPath);
365+
outputPath_ = inputs_->resultsPath().string();
366+
setupLog(outputPath_, logFile_, logMask_, logRootPath_);
370367
}
371368

372369
OREApp::~OREApp() {
@@ -376,6 +373,24 @@ OREApp::~OREApp() {
376373

377374
void OREApp::run() {
378375

376+
// only one thread at a time should call run
377+
static std::mutex _s_mutex;
378+
std::lock_guard<std::mutex> lock(_s_mutex);
379+
380+
// clean up after finishing the run
381+
CleanUpThreadLocalSingletons cleanupThreadLocalSingletons;
382+
CleanUpThreadGlobalSingletons cleanupThreadGloablSingletons;
383+
CleanUpLogSingleton cleanupLogSingleton(true, true);
384+
385+
if (inputs_ == nullptr)
386+
initFromParams();
387+
else if (params_ == nullptr)
388+
initFromInputs();
389+
else {
390+
ALOG("both inputs are empty");
391+
return;
392+
}
393+
379394
runTimer_.start();
380395

381396
try {
@@ -389,13 +404,35 @@ void OREApp::run() {
389404

390405
runTimer_.stop();
391406

407+
// cache the error messages because we reset the loggers
408+
errorMessages_ = structuredLogger_->messages();
409+
392410
CONSOLE("run time: " << runTimer_.format(default_places, "%w") << " sec");
393411
CONSOLE("ORE done.");
394412
LOG("ORE done.");
395413
}
396414

397415
void OREApp::run(const std::vector<std::string>& marketData,
398416
const std::vector<std::string>& fixingData) {
417+
418+
// only one thread at a time should call run
419+
static std::mutex _s_mutex;
420+
std::lock_guard<std::mutex> lock(_s_mutex);
421+
422+
// clean up after finishing the run
423+
CleanUpThreadLocalSingletons cleanupThreadLocalSingletons;
424+
CleanUpThreadGlobalSingletons cleanupThreadGloablSingletons;
425+
CleanUpLogSingleton cleanupLogSingleton(true, true);
426+
427+
if (inputs_ == nullptr)
428+
initFromParams();
429+
else if (params_ == nullptr)
430+
initFromInputs();
431+
else {
432+
ALOG("both inputs are empty");
433+
return;
434+
}
435+
399436
runTimer_.start();
400437

401438
try {

OREAnalytics/orea/app/oreapp.hpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,14 @@ class OREApp {
4141
public:
4242
//! Constructor that uses ORE parameters and input data from files
4343
OREApp(boost::shared_ptr<Parameters> params, bool console = false,
44-
const boost::filesystem::path& = boost::filesystem::path());
44+
const boost::filesystem::path& logRootPath = boost::filesystem::path())
45+
: params_(params), inputs_(nullptr), console_(console), logRootPath_(logRootPath) {}
46+
4547
//! Constructor that assumes we have already assembled input parameters via API
4648
OREApp(const boost::shared_ptr<InputParameters>& inputs, const std::string& logFile, Size logLevel = 31,
47-
bool console = false, const boost::filesystem::path& = boost::filesystem::path());
49+
bool console = false, const boost::filesystem::path& logRootPath = boost::filesystem::path())
50+
: params_(nullptr), inputs_(inputs), logFile_(logFile), logMask_(logLevel), console_(console),
51+
logRootPath_(logRootPath) {}
4852

4953
//! Destructor
5054
virtual ~OREApp();
@@ -93,6 +97,9 @@ class OREApp {
9397
//! remove logs
9498
void closeLog();
9599

100+
void initFromParams();
101+
void initFromInputs();
102+
96103
//! ORE Input parameters
97104
boost::shared_ptr<Parameters> params_;
98105
boost::shared_ptr<InputParameters> inputs_;
@@ -101,6 +108,21 @@ class OREApp {
101108
boost::shared_ptr<AnalyticsManager> analyticsManager_;
102109
boost::shared_ptr<StructuredLogger> structuredLogger_;
103110
boost::timer::cpu_timer runTimer_;
111+
112+
//! Logging
113+
string logFile_;
114+
Size logMask_;
115+
bool console_;
116+
string outputPath_;
117+
boost::filesystem::path logRootPath_;
118+
string progressLogFile_ = "";
119+
QuantLib::Size progressLogRotationSize_ = 100 * 1024 * 1024;
120+
bool progressLogToConsole_ = false;
121+
string structuredLogFile_ = "";
122+
QuantLib::Size structuredLogRotationSize_ = 100 * 1024 * 1024;
123+
124+
// Cached error messages of a run
125+
std::vector<std::string> errorMessages_;
104126
};
105127

106128
class OREAppInputParameters : virtual public InputParameters {

0 commit comments

Comments
 (0)