Mantid
Loading...
Searching...
No Matches
FrameworkManager.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
12
15#include "MantidKernel/Memory.h"
19
20#include <boost/algorithm/string/classification.hpp>
21#include <boost/algorithm/string/split.hpp>
22
23#include <Poco/ActiveResult.h>
24
25#include <clocale>
26#include <cstdarg>
27#include <memory>
28
29#include "tbb/global_control.h"
30
31#ifdef _WIN32
32#include <winsock2.h>
33#endif
34
35#ifdef __linux__
36#include <csignal>
37#include <execinfo.h>
38#endif
39
40namespace {
41// We use a raw pointer over a unique_ptr to avoid problems with static deallocation order of static
42// variables. In certain circumstances, e.g. unit testing, the shutdown method on FrameworkManager is
43// not called. In this situation unique_ptr causes the tbb::global_control object to be destroyed
44// *after* its own internal static data has been destroyed and we see a random segfault.
45// We have technically introduced a leak by not deleting this object in the situation where
46// `FrameworkManager::shutdown` is not called but the memory cannot be used again by the program since
47// it survives for the duration of the program. It will ultimately be reclaimed by the OS.
48tbb::global_control *GLOBAL_TBB_CONTROL = nullptr;
49} // namespace
50
51namespace Mantid {
54using Kernel::LibraryManagerImpl;
56namespace API {
57namespace {
59Kernel::Logger g_log("FrameworkManager");
61const char *PLUGINS_DIR_KEY = "framework.plugins.directory";
63const char *PLUGINS_EXCLUDE_KEY = "framework.plugins.exclude";
64} // namespace
65
66#ifdef __linux__
71void backtraceToStream(std::ostream &os) {
72 void *trace_elems[32];
73 int trace_elem_count(backtrace(trace_elems, 32));
74 char **stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
75 for (int i = 0; i < trace_elem_count; ++i) {
76 os << ' ' << stack_syms[i] << '\n';
77 }
78 free(stack_syms);
79}
80
86void terminateHandler() {
87 std::cerr << "\n********* UNHANDLED EXCEPTION *********\n";
88 try {
89 std::rethrow_exception(std::current_exception());
90 } catch (const std::exception &exc) {
91 std::cerr << " type: " << typeid(exc).name() << ";\n"
92 << " what(): " << exc.what() << "\n\n";
93 } catch (...) {
94 std::cerr << " what(): Unknown exception type. No more information "
95 "available\n\n";
96 }
97 std::cerr << "Backtrace:\n";
98 backtraceToStream(std::cerr);
99 exit(1);
100}
101
102#endif
103
106#ifdef __linux__
107 std::set_terminate(terminateHandler);
108#endif
111
112#ifdef _WIN32
113 WSADATA wsaData;
114 WSAStartup(MAKEWORD(2, 2), &wsaData);
115#endif
116
117#if defined(_MSC_VER) && _MSC_VER < 1900
118 // This causes the exponent to consist of two digits.
119 // VC++ >=1900 use standards conforming behaviour and only
120 // uses the number of digits required
121 _set_output_format(_TWO_DIGIT_EXPONENT);
122#endif
123
124 ConfigService::Instance();
125 g_log.notice() << Mantid::welcomeMessage() << '\n';
126 loadPlugins();
128
129 g_log.debug() << "FrameworkManager created.\n";
130
132}
133
137void FrameworkManagerImpl::loadPlugins() { loadPluginsUsingKey(PLUGINS_DIR_KEY, PLUGINS_EXCLUDE_KEY); }
138
143 // Set the number of threads to use for this process
144 auto maxCores = Kernel::ConfigService::Instance().getValue<int>("MultiThreaded.MaxCores");
145 if (maxCores.value_or(0) > 0) {
146 setNumOMPThreads(maxCores.value());
147 }
148}
149
155 g_log.debug() << "Setting maximum number of threads to " << nthreads << "\n";
156 PARALLEL_SET_NUM_THREADS(nthreads);
157 if (GLOBAL_TBB_CONTROL) {
158 delete GLOBAL_TBB_CONTROL; // Have to reset to change the number of threads at runtime
159 }
160
161 GLOBAL_TBB_CONTROL = new tbb::global_control(tbb::global_control::max_allowed_parallelism, nthreads);
162}
163
171
181
183 Kernel::UsageService::Instance().shutdown();
184 // Ensure we don't run into static init ordering issues with TBB
185 delete GLOBAL_TBB_CONTROL;
186 clear();
187}
188
192void FrameworkManagerImpl::clearAlgorithms() { AlgorithmManager::Instance().clear(); }
193
197void FrameworkManagerImpl::clearData() { AnalysisDataService::Instance().clear(); }
198
202void FrameworkManagerImpl::clearInstruments() { InstrumentDataService::Instance().clear(); }
203
209 PropertyManagerDataService::Instance().clear();
210}
211
218IAlgorithm_sptr FrameworkManagerImpl::exec(const std::string &algorithmName, int count, ...) {
219 if (count % 2 == 1) {
220 throw std::runtime_error("Must have an even number of parameter/value string arguments");
221 }
222
223 // Create the algorithm
224 auto alg = AlgorithmManager::Instance().createUnmanaged(algorithmName, -1);
225 alg->initialize();
226 if (!alg->isInitialized())
227 throw std::runtime_error(algorithmName + " was not initialized.");
228
229 va_list Params;
230 va_start(Params, count);
231 for (int i = 0; i < count; i += 2) {
232 std::string paramName = va_arg(Params, const char *);
233 std::string paramValue = va_arg(Params, const char *);
234 alg->setPropertyValue(paramName, paramValue);
235 }
236 va_end(Params);
237
238 alg->execute();
239 return alg;
240}
241
251 Workspace *space;
252 try {
253 space = AnalysisDataService::Instance().retrieve(wsName).get();
255 throw Kernel::Exception::NotFoundError("Unable to retrieve workspace", wsName);
256 }
257 return space;
258}
259
267bool FrameworkManagerImpl::deleteWorkspace(const std::string &wsName) {
268 bool retVal = false;
269 std::shared_ptr<Workspace> ws_sptr;
270 try {
271 ws_sptr = AnalysisDataService::Instance().retrieve(wsName);
273 g_log.error() << ex.what() << '\n';
274 return false;
275 }
276
277 std::shared_ptr<WorkspaceGroup> ws_grpsptr = std::dynamic_pointer_cast<WorkspaceGroup>(ws_sptr);
278 if (ws_grpsptr) {
279 // selected workspace is a group workspace
280 AnalysisDataService::Instance().deepRemoveGroup(wsName);
281 }
282 // Make sure we drop the references so the memory will get freed when we
283 // expect it to
284 ws_sptr.reset();
285 ws_grpsptr.reset();
286 try {
287 AnalysisDataService::Instance().remove(wsName);
288 retVal = true;
290 // workspace was not found
291 g_log.error() << "Workspace " << wsName << " could not be found.\n";
292 retVal = false;
293 }
294 return retVal;
295}
296
303void FrameworkManagerImpl::loadPluginsUsingKey(const std::string &locationKey, const std::string &excludeKey) {
304 const auto &cfgSvc = Kernel::ConfigService::Instance();
305 const auto pluginDir = cfgSvc.getString(locationKey);
306 if (pluginDir.length() > 0) {
307 std::vector<std::string> excludes;
308 const auto excludeStr = cfgSvc.getString(excludeKey);
309 boost::split(excludes, excludeStr, boost::is_any_of(";"));
310 g_log.debug("Loading libraries from '" + pluginDir + "', excluding '" + excludeStr + "'");
311 LibraryManager::Instance().openLibraries(pluginDir, LibraryManagerImpl::NonRecursive, excludes);
312 } else {
313 g_log.debug("No library directory found in key \"" + locationKey + "\"");
314 }
315}
316
321 // Some languages, for example German, using different decimal separators.
322 // By default C/C++ operations attempting to extract numbers from a stream
323 // will use the system locale. For those locales where numbers are formatted
324 // differently we see issues, particularly with opencascade, where Mantid
325 // will hang or throw an exception while trying to parse text.
326 //
327 // The following tells all numerical extraction operations to use classic
328 // C as the locale.
329 setlocale(LC_NUMERIC, "C");
330}
331
334 auto instrumentUpdates = Kernel::ConfigService::Instance().getValue<bool>("UpdateInstrumentDefinitions.OnStartup");
335
336 if (instrumentUpdates.value_or(false)) {
338 } else {
339 g_log.information() << "Instrument updates disabled - cannot update "
340 "instrument definitions.\n";
341 }
342
343 auto newVersionCheck = Kernel::ConfigService::Instance().getValue<bool>("CheckMantidVersion.OnStartup");
344 if (newVersionCheck.value_or(false)) {
346 } else {
347 g_log.information() << "Version check disabled.\n";
348 }
349
351}
352
354 auto &configSvc = ConfigService::Instance();
355 auto interval = configSvc.getValue<int>("Usage.BufferCheckInterval");
356 auto &usageSvc = UsageService::Instance();
357 if (interval.value_or(0) > 0) {
358 usageSvc.setInterval(interval.value());
359 }
360 auto enabled = configSvc.getValue<bool>("usagereports.enabled");
361 usageSvc.setEnabled(enabled.value_or(false));
362 usageSvc.registerStartup();
363}
364
367 try {
368 auto algDownloadInstrument = Mantid::API::AlgorithmManager::Instance().create("DownloadInstrument");
369 algDownloadInstrument->setAlgStartupLogging(false);
370 algDownloadInstrument->executeAsync();
372 g_log.debug() << "DowndloadInstrument algorithm is not available - cannot "
373 "update instrument definitions.\n";
374 }
375}
376
379 try {
380 auto algCheckVersion = Mantid::API::AlgorithmManager::Instance().create("CheckMantidVersion");
381 algCheckVersion->setAlgStartupLogging(false);
382 algCheckVersion->executeAsync();
384 g_log.debug() << "CheckMantidVersion algorithm is not available - cannot "
385 "check if a newer version is available.\n";
386 }
387}
388
389} // namespace API
390} // Namespace Mantid
std::string name
Definition Run.cpp:60
int count
counter
Definition Matrix.cpp:37
#define PARALLEL_SET_NUM_THREADS(MaxCores)
#define PARALLEL_GET_MAX_THREADS
Workspace * getWorkspace(const std::string &wsName)
Returns a shared pointer to the workspace requested.
std::shared_ptr< IAlgorithm > exec(const std::string &algorithmName, int count,...)
Creates an algorithm and runs it, with variadic arguments.
void updateInstrumentDefinitions()
Update instrument definitions from github.
void clearPropertyManagers()
Clear memory associated with the PropertyManagers.
void loadPlugins()
Load framework plugins.
void setNumOMPThreads(const int nthreads)
Set the number of OpenMP threads to the given value.
void asynchronousStartupTasks()
Starts asynchronous tasks that are done as part of Start-up.
void loadPluginsUsingKey(const std::string &locationKey, const std::string &excludeKey)
Load a set of plugins using a key from the ConfigService.
void clearInstruments()
Clear memory associated with the IDS.
FrameworkManagerImpl()
Private Constructor.
void clearData()
Clear memory associated with the ADS.
void shutdown()
shuts down and performs clean up tasks
void setGlobalNumericLocaleToC()
Set up the global locale.
int getNumOMPThreads() const
Returns the number of OpenMP threads that will be used.
void checkIfNewerVersionIsAvailable()
check if a newer version of Mantid is available
void setNumOMPThreadsToConfigValue()
Set the number of OpenMP threads to use based on the config value.
void clear()
Clears all memory associated with the AlgorithmManager, ADS & IDS.
bool deleteWorkspace(const std::string &wsName)
Deletes a workspace from the framework.
void clearAlgorithms()
Clear memory associated with the AlgorithmManager.
void setupUsageReporting()
Setup Usage Reporting if enabled.
Base Workspace Abstract Class.
Definition Workspace.h:29
Exception for when an item is not found in a collection.
Definition Exception.h:145
const char * what() const noexcept override
Writes out the range and limits.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
Kernel::Logger g_log("ExperimentInfo")
static logger object
MANTID_KERNEL_DLL void initAllocatorOptions()
Initialize platform-dependent options for memory management.
Definition Memory.cpp:286
Mantid::Kernel::SingletonHolder< ConfigServiceImpl > ConfigService
Mantid::Kernel::SingletonHolder< LibraryManagerImpl > LibraryManager
Mantid::Kernel::SingletonHolder< UsageServiceImpl > UsageService
Mantid::Kernel::SingletonHolder< PropertyManagerDataServiceImpl > PropertyManagerDataService
Helper class which provides the Collimation Length for SANS instruments.
MANTID_KERNEL_DLL std::string welcomeMessage()
Returns the welcome message for Mantid.