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/split.hpp>
21
22#include <nexus/NeXusFile.hpp>
23
24#include <Poco/ActiveResult.h>
25
26#include <clocale>
27#include <cstdarg>
28#include <memory>
29
30// The below can be replaced with global_control when all platforms
31// have 2019U4
32#if __has_include("tbb/tbb_stddef.h")
33#include "tbb/tbb_stddef.h"
34#if TBB_INTERFACE_VERSION_MAJOR < 11
35#include "tbb/task_scheduler_init.h"
36#include <thread>
37#else
38#define TBB_HAS_GLOBAL_CONTROL
39#include "tbb/global_control.h"
40#endif
41#else
42#define TBB_HAS_GLOBAL_CONTROL
43#include "tbb/global_control.h"
44#endif
45
46#ifdef _WIN32
47#include <winsock2.h>
48#endif
49
50#ifdef __linux__
51#include <csignal>
52#include <execinfo.h>
53#endif
54
55#ifdef MPI_BUILD
56#include <boost/mpi.hpp>
57#endif
58
59namespace {
60#ifdef TBB_HAS_GLOBAL_CONTROL
61std::unique_ptr<tbb::global_control> m_globalTbbControl;
62#else
63thread_local std::unique_ptr<tbb::task_scheduler_init> m_globalTbbControl;
64#endif
65} // namespace
66
67namespace Mantid {
70using Kernel::LibraryManagerImpl;
72namespace API {
73namespace {
75Kernel::Logger g_log("FrameworkManager");
77const char *PLUGINS_DIR_KEY = "framework.plugins.directory";
79const char *PLUGINS_EXCLUDE_KEY = "framework.plugins.exclude";
80} // namespace
81
85// Prevent clang-tidy trying to change the signature for ext. interface
86// NOLINTNEXTLINE(readability-non-const-parameter)
87void NexusErrorFunction(void *, char *) {
88 // Do nothing.
89}
90
91#ifdef __linux__
96void backtraceToStream(std::ostream &os) {
97 void *trace_elems[32];
98 int trace_elem_count(backtrace(trace_elems, 32));
99 char **stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
100 for (int i = 0; i < trace_elem_count; ++i) {
101 os << ' ' << stack_syms[i] << '\n';
102 }
103 free(stack_syms);
104}
105
111void terminateHandler() {
112 std::cerr << "\n********* UNHANDLED EXCEPTION *********\n";
113 try {
114 std::rethrow_exception(std::current_exception());
115 } catch (const std::exception &exc) {
116 std::cerr << " what(): " << exc.what() << "\n\n";
117 } catch (...) {
118 std::cerr << " what(): Unknown exception type. No more information "
119 "available\n\n";
120 }
121 std::cerr << "Backtrace:\n";
122 backtraceToStream(std::cerr);
123 exit(1);
124}
125
126#endif
127
130#ifdef MPI_BUILD
131 : m_mpi_environment(argc, argv)
132#endif
133{
134#ifdef __linux__
135 std::set_terminate(terminateHandler);
136#endif
137 setGlobalNumericLocaleToC();
139
140#ifdef _WIN32
141 WSADATA wsaData;
142 WSAStartup(MAKEWORD(2, 2), &wsaData);
143#endif
144
145#if defined(_MSC_VER) && _MSC_VER < 1900
146 // This causes the exponent to consist of two digits.
147 // VC++ >=1900 use standards conforming behaviour and only
148 // uses the number of digits required
149 _set_output_format(_TWO_DIGIT_EXPONENT);
150#endif
151
153 g_log.notice() << Mantid::welcomeMessage() << '\n';
154 loadPlugins();
155 disableNexusOutput();
156 setNumOMPThreadsToConfigValue();
157
158#ifdef MPI_BUILD
159 g_log.notice() << "This MPI process is rank: " << boost::mpi::communicator().rank() << '\n';
160#endif
161
162 g_log.debug() << "FrameworkManager created.\n";
163
164 asynchronousStartupTasks();
165}
166
170void FrameworkManagerImpl::loadPlugins() { loadPluginsUsingKey(PLUGINS_DIR_KEY, PLUGINS_EXCLUDE_KEY); }
171
176 // Set the number of threads to use for this process
177 auto maxCores = Kernel::ConfigService::Instance().getValue<int>("MultiThreaded.MaxCores");
178 if (maxCores.get_value_or(0) > 0) {
179 setNumOMPThreads(maxCores.get());
180 }
181}
182
188 g_log.debug() << "Setting maximum number of threads to " << nthreads << "\n";
189 PARALLEL_SET_NUM_THREADS(nthreads);
190 if (m_globalTbbControl) {
191 m_globalTbbControl.reset(); // Have to reset to change the number of threads at runtime
192 }
193
194#ifdef TBB_HAS_GLOBAL_CONTROL
195 m_globalTbbControl = std::make_unique<tbb::global_control>(tbb::global_control::max_allowed_parallelism, nthreads);
196#else
197 m_globalTbbControl = std::make_unique<tbb::task_scheduler_init>(nthreads);
198#endif
199}
200
208
215 clearData();
217}
218
221 // Ensure we don't run into static init ordering issues with TBB
222 m_globalTbbControl.reset();
223 clear();
224}
225
230
235
240
247}
248
255IAlgorithm_sptr FrameworkManagerImpl::exec(const std::string &algorithmName, int count, ...) {
256 if (count % 2 == 1) {
257 throw std::runtime_error("Must have an even number of parameter/value string arguments");
258 }
259
260 // Create the algorithm
261 auto alg = AlgorithmManager::Instance().createUnmanaged(algorithmName, -1);
262 alg->initialize();
263 if (!alg->isInitialized())
264 throw std::runtime_error(algorithmName + " was not initialized.");
265
266 va_list Params;
267 va_start(Params, count);
268 for (int i = 0; i < count; i += 2) {
269 std::string paramName = va_arg(Params, const char *);
270 std::string paramValue = va_arg(Params, const char *);
271 alg->setPropertyValue(paramName, paramValue);
272 }
273 va_end(Params);
274
275 alg->execute();
276 return alg;
277}
278
288 Workspace *space;
289 try {
290 space = AnalysisDataService::Instance().retrieve(wsName).get();
292 throw Kernel::Exception::NotFoundError("Unable to retrieve workspace", wsName);
293 }
294 return space;
295}
296
304bool FrameworkManagerImpl::deleteWorkspace(const std::string &wsName) {
305 bool retVal = false;
306 std::shared_ptr<Workspace> ws_sptr;
307 try {
308 ws_sptr = AnalysisDataService::Instance().retrieve(wsName);
310 g_log.error() << ex.what() << '\n';
311 return false;
312 }
313
314 std::shared_ptr<WorkspaceGroup> ws_grpsptr = std::dynamic_pointer_cast<WorkspaceGroup>(ws_sptr);
315 if (ws_grpsptr) {
316 // selected workspace is a group workspace
317 AnalysisDataService::Instance().deepRemoveGroup(wsName);
318 }
319 // Make sure we drop the references so the memory will get freed when we
320 // expect it to
321 ws_sptr.reset();
322 ws_grpsptr.reset();
323 try {
324 AnalysisDataService::Instance().remove(wsName);
325 retVal = true;
327 // workspace was not found
328 g_log.error() << "Workspace " << wsName << " could not be found.\n";
329 retVal = false;
330 }
331 return retVal;
332}
333
340void FrameworkManagerImpl::loadPluginsUsingKey(const std::string &locationKey, const std::string &excludeKey) {
341 const auto &cfgSvc = Kernel::ConfigService::Instance();
342 const auto pluginDir = cfgSvc.getString(locationKey);
343 if (pluginDir.length() > 0) {
344 std::vector<std::string> excludes;
345 const auto excludeStr = cfgSvc.getString(excludeKey);
346 boost::split(excludes, excludeStr, boost::is_any_of(";"));
347 g_log.debug("Loading libraries from '" + pluginDir + "', excluding '" + excludeStr + "'");
348 LibraryManager::Instance().openLibraries(pluginDir, LibraryManagerImpl::NonRecursive, excludes);
349 } else {
350 g_log.debug("No library directory found in key \"" + locationKey + "\"");
351 }
352}
353
358 // Some languages, for example German, using different decimal separators.
359 // By default C/C++ operations attempting to extract numbers from a stream
360 // will use the system locale. For those locales where numbers are formatted
361 // differently we see issues, particularly with opencascade, where Mantid
362 // will hang or throw an exception while trying to parse text.
363 //
364 // The following tells all numerical extraction operations to use classic
365 // C as the locale.
366 setlocale(LC_NUMERIC, "C");
367}
368
371
374 auto instrumentUpdates = Kernel::ConfigService::Instance().getValue<bool>("UpdateInstrumentDefinitions.OnStartup");
375
376 if (instrumentUpdates.get_value_or(false)) {
378 } else {
379 g_log.information() << "Instrument updates disabled - cannot update "
380 "instrument definitions.\n";
381 }
382
383 auto newVersionCheck = Kernel::ConfigService::Instance().getValue<bool>("CheckMantidVersion.OnStartup");
384 if (newVersionCheck.get_value_or(false)) {
386 } else {
387 g_log.information() << "Version check disabled.\n";
388 }
389
391}
392
394 auto &configSvc = ConfigService::Instance();
395 auto interval = configSvc.getValue<int>("Usage.BufferCheckInterval");
396 auto &usageSvc = UsageService::Instance();
397 if (interval.get_value_or(0) > 0) {
398 usageSvc.setInterval(interval.get());
399 }
400 auto enabled = configSvc.getValue<bool>("usagereports.enabled");
401 usageSvc.setEnabled(enabled.get_value_or(false));
402 usageSvc.registerStartup();
403}
404
407 try {
408 auto algDownloadInstrument = Mantid::API::AlgorithmManager::Instance().create("DownloadInstrument");
409 algDownloadInstrument->setAlgStartupLogging(false);
410 algDownloadInstrument->executeAsync();
412 g_log.debug() << "DowndloadInstrument algorithm is not available - cannot "
413 "update instrument definitions.\n";
414 }
415}
416
419 try {
420 auto algCheckVersion = Mantid::API::AlgorithmManager::Instance().create("CheckMantidVersion");
421 algCheckVersion->setAlgStartupLogging(false);
422 algCheckVersion->executeAsync();
424 g_log.debug() << "CheckMantidVersion algorithm is not available - cannot "
425 "check if a newer version is available.\n";
426 }
427}
428
429} // namespace API
430} // Namespace Mantid
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 disableNexusOutput()
Silence NeXus output.
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:30
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.
Definition: Exception.cpp:105
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
Manage the lifetime of a class intended to be a singleton.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
Kernel::Logger g_log("ExperimentInfo")
static logger object
void NexusErrorFunction(void *, char *)
This is a function called every time NeXuS raises an error.
MANTID_KERNEL_DLL void initAllocatorOptions()
Initialize platform-dependent options for memory management.
Definition: Memory.cpp:282
Mantid::Kernel::SingletonHolder< ConfigServiceImpl > ConfigService
Mantid::Kernel::SingletonHolder< LibraryManagerImpl > LibraryManager
Mantid::Kernel::SingletonHolder< UsageServiceImpl > UsageService
Definition: UsageService.h:153
Helper class which provides the Collimation Length for SANS instruments.
MANTID_KERNEL_DLL std::string welcomeMessage()
Returns the welcome message for Mantid.