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
40#ifdef MPI_BUILD
41#include <boost/mpi.hpp>
42#endif
43
44namespace {
45// We use a raw pointer over a unique_ptr to avoid problems with static deallocation order of static
46// variables. In certain circumstances, e.g. unit testing, the shutdown method on FrameworkManager is
47// not called. In this situation unique_ptr causes the tbb::global_control object to be destroyed
48// *after* its own internal static data has been destroyed and we see a random segfault.
49// We have technically introduced a leak by not deleting this object in the situation where
50// `FrameworkManager::shutdown` is not called but the memory cannot be used again by the program since
51// it survives for the duration of the program. It will ultimately be reclaimed by the OS.
52tbb::global_control *GLOBAL_TBB_CONTROL = nullptr;
53} // namespace
54
55namespace Mantid {
58using Kernel::LibraryManagerImpl;
60namespace API {
61namespace {
63Kernel::Logger g_log("FrameworkManager");
65const char *PLUGINS_DIR_KEY = "framework.plugins.directory";
67const char *PLUGINS_EXCLUDE_KEY = "framework.plugins.exclude";
68} // namespace
69
70#ifdef __linux__
75void backtraceToStream(std::ostream &os) {
76 void *trace_elems[32];
77 int trace_elem_count(backtrace(trace_elems, 32));
78 char **stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
79 for (int i = 0; i < trace_elem_count; ++i) {
80 os << ' ' << stack_syms[i] << '\n';
81 }
82 free(stack_syms);
83}
84
90void terminateHandler() {
91 std::cerr << "\n********* UNHANDLED EXCEPTION *********\n";
92 try {
93 std::rethrow_exception(std::current_exception());
94 } catch (const std::exception &exc) {
95 std::cerr << " type: " << typeid(exc).name() << ";\n"
96 << " what(): " << exc.what() << "\n\n";
97 } catch (...) {
98 std::cerr << " what(): Unknown exception type. No more information "
99 "available\n\n";
100 }
101 std::cerr << "Backtrace:\n";
102 backtraceToStream(std::cerr);
103 exit(1);
104}
105
106#endif
107
110#ifdef __linux__
111 std::set_terminate(terminateHandler);
112#endif
115
116#ifdef _WIN32
117 WSADATA wsaData;
118 WSAStartup(MAKEWORD(2, 2), &wsaData);
119#endif
120
121#if defined(_MSC_VER) && _MSC_VER < 1900
122 // This causes the exponent to consist of two digits.
123 // VC++ >=1900 use standards conforming behaviour and only
124 // uses the number of digits required
125 _set_output_format(_TWO_DIGIT_EXPONENT);
126#endif
127
128 ConfigService::Instance();
129 g_log.notice() << Mantid::welcomeMessage() << '\n';
130 loadPlugins();
132
133 g_log.debug() << "FrameworkManager created.\n";
134
136#ifdef MPI_BUILD
137 int initialized = 0;
138 MPI_Initialized(&initialized);
139 if (!initialized)
140 m_mpi_environment = std::make_unique<boost::mpi::environment>(argc, argv);
141#endif
142}
143
147void FrameworkManagerImpl::loadPlugins() { loadPluginsUsingKey(PLUGINS_DIR_KEY, PLUGINS_EXCLUDE_KEY); }
148
153 // Set the number of threads to use for this process
154 auto maxCores = Kernel::ConfigService::Instance().getValue<int>("MultiThreaded.MaxCores");
155 if (maxCores.value_or(0) > 0) {
156 setNumOMPThreads(maxCores.value());
157 }
158}
159
165 g_log.debug() << "Setting maximum number of threads to " << nthreads << "\n";
166 PARALLEL_SET_NUM_THREADS(nthreads);
167 if (GLOBAL_TBB_CONTROL) {
168 delete GLOBAL_TBB_CONTROL; // Have to reset to change the number of threads at runtime
169 }
170
171 GLOBAL_TBB_CONTROL = new tbb::global_control(tbb::global_control::max_allowed_parallelism, nthreads);
172}
173
181
191
193 Kernel::UsageService::Instance().shutdown();
194 // Ensure we don't run into static init ordering issues with TBB
195 delete GLOBAL_TBB_CONTROL;
196 clear();
197}
198
202void FrameworkManagerImpl::clearAlgorithms() { AlgorithmManager::Instance().clear(); }
203
207void FrameworkManagerImpl::clearData() { AnalysisDataService::Instance().clear(); }
208
212void FrameworkManagerImpl::clearInstruments() { InstrumentDataService::Instance().clear(); }
213
219 PropertyManagerDataService::Instance().clear();
220}
221
228IAlgorithm_sptr FrameworkManagerImpl::exec(const std::string &algorithmName, int count, ...) {
229 if (count % 2 == 1) {
230 throw std::runtime_error("Must have an even number of parameter/value string arguments");
231 }
232
233 // Create the algorithm
234 auto alg = AlgorithmManager::Instance().createUnmanaged(algorithmName, -1);
235 alg->initialize();
236 if (!alg->isInitialized())
237 throw std::runtime_error(algorithmName + " was not initialized.");
238
239 va_list Params;
240 va_start(Params, count);
241 for (int i = 0; i < count; i += 2) {
242 std::string paramName = va_arg(Params, const char *);
243 std::string paramValue = va_arg(Params, const char *);
244 alg->setPropertyValue(paramName, paramValue);
245 }
246 va_end(Params);
247
248 alg->execute();
249 return alg;
250}
251
261 Workspace *space;
262 try {
263 space = AnalysisDataService::Instance().retrieve(wsName).get();
265 throw Kernel::Exception::NotFoundError("Unable to retrieve workspace", wsName);
266 }
267 return space;
268}
269
277bool FrameworkManagerImpl::deleteWorkspace(const std::string &wsName) {
278 bool retVal = false;
279 std::shared_ptr<Workspace> ws_sptr;
280 try {
281 ws_sptr = AnalysisDataService::Instance().retrieve(wsName);
283 g_log.error() << ex.what() << '\n';
284 return false;
285 }
286
287 std::shared_ptr<WorkspaceGroup> ws_grpsptr = std::dynamic_pointer_cast<WorkspaceGroup>(ws_sptr);
288 if (ws_grpsptr) {
289 // selected workspace is a group workspace
290 AnalysisDataService::Instance().deepRemoveGroup(wsName);
291 }
292 // Make sure we drop the references so the memory will get freed when we
293 // expect it to
294 ws_sptr.reset();
295 ws_grpsptr.reset();
296 try {
297 AnalysisDataService::Instance().remove(wsName);
298 retVal = true;
300 // workspace was not found
301 g_log.error() << "Workspace " << wsName << " could not be found.\n";
302 retVal = false;
303 }
304 return retVal;
305}
306
313void FrameworkManagerImpl::loadPluginsUsingKey(const std::string &locationKey, const std::string &excludeKey) {
314 const auto &cfgSvc = Kernel::ConfigService::Instance();
315 const auto pluginDir = cfgSvc.getString(locationKey);
316 if (pluginDir.length() > 0) {
317 std::vector<std::string> excludes;
318 const auto excludeStr = cfgSvc.getString(excludeKey);
319 boost::split(excludes, excludeStr, boost::is_any_of(";"));
320 g_log.debug("Loading libraries from '" + pluginDir + "', excluding '" + excludeStr + "'");
321 LibraryManager::Instance().openLibraries(pluginDir, LibraryManagerImpl::NonRecursive, excludes);
322 } else {
323 g_log.debug("No library directory found in key \"" + locationKey + "\"");
324 }
325}
326
331 // Some languages, for example German, using different decimal separators.
332 // By default C/C++ operations attempting to extract numbers from a stream
333 // will use the system locale. For those locales where numbers are formatted
334 // differently we see issues, particularly with opencascade, where Mantid
335 // will hang or throw an exception while trying to parse text.
336 //
337 // The following tells all numerical extraction operations to use classic
338 // C as the locale.
339 setlocale(LC_NUMERIC, "C");
340}
341
344 auto instrumentUpdates = Kernel::ConfigService::Instance().getValue<bool>("UpdateInstrumentDefinitions.OnStartup");
345
346 if (instrumentUpdates.value_or(false)) {
348 } else {
349 g_log.information() << "Instrument updates disabled - cannot update "
350 "instrument definitions.\n";
351 }
352
353 auto newVersionCheck = Kernel::ConfigService::Instance().getValue<bool>("CheckMantidVersion.OnStartup");
354 if (newVersionCheck.value_or(false)) {
356 } else {
357 g_log.information() << "Version check disabled.\n";
358 }
359
361}
362
364 auto &configSvc = ConfigService::Instance();
365 auto interval = configSvc.getValue<int>("Usage.BufferCheckInterval");
366 auto &usageSvc = UsageService::Instance();
367 if (interval.value_or(0) > 0) {
368 usageSvc.setInterval(interval.value());
369 }
370 auto enabled = configSvc.getValue<bool>("usagereports.enabled");
371 usageSvc.setEnabled(enabled.value_or(false));
372 usageSvc.registerStartup();
373}
374
377 try {
378 auto algDownloadInstrument = Mantid::API::AlgorithmManager::Instance().create("DownloadInstrument");
379 algDownloadInstrument->setAlgStartupLogging(false);
380 algDownloadInstrument->executeAsync();
382 g_log.debug() << "DowndloadInstrument algorithm is not available - cannot "
383 "update instrument definitions.\n";
384 }
385}
386
389 try {
390 auto algCheckVersion = Mantid::API::AlgorithmManager::Instance().create("CheckMantidVersion");
391 algCheckVersion->setAlgStartupLogging(false);
392 algCheckVersion->executeAsync();
394 g_log.debug() << "CheckMantidVersion algorithm is not available - cannot "
395 "check if a newer version is available.\n";
396 }
397}
398
399} // namespace API
400} // 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.