diff --git a/Framework/API/CMakeLists.txt b/Framework/API/CMakeLists.txt index 5cf25c750d09a7725241e29a9765dc93c935e112..6a55093e7bcf2b08b6b8533bb4f387c50677d69b 100644 --- a/Framework/API/CMakeLists.txt +++ b/Framework/API/CMakeLists.txt @@ -362,6 +362,15 @@ set ( INC_FILES inc/MantidAPI/Workspace_fwd.h ) +option(PROFILE_ALGORITHM_LINUX "Profile algorithm execution on Linux and OSX" OFF) +if(PROFILE_ALGORITHM_LINUX) + set(SRC_FILES "${SRC_FILES}" "src/AlgorithmExecuteProfile.cpp" "src/AlgoTimeRegister.cpp") + set(INC_FILES "${INC_FILES}" "inc/MantidAPI/AlgoTimeRegister.h") +else() + set(SRC_FILES "${SRC_FILES}" "src/AlgorithmExecute.cpp") +endif() +unset(PROFILE_ALGORITHM_LINUX CACHE) + set ( TEST_FILES # IkedaCarpenterModeratorTest.h ADSValidatorTest.h diff --git a/Framework/API/inc/MantidAPI/AlgoTimeRegister.h b/Framework/API/inc/MantidAPI/AlgoTimeRegister.h new file mode 100644 index 0000000000000000000000000000000000000000..3f5c1cb7fe10bf5a4d554ee54944b917342821d2 --- /dev/null +++ b/Framework/API/inc/MantidAPI/AlgoTimeRegister.h @@ -0,0 +1,62 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#ifndef MANTID_API_ALGOTIMEREGISTER_H_ +#define MANTID_API_ALGOTIMEREGISTER_H_ + +#include <mutex> +#include <thread> +#include <vector> + +#include "MantidAPI/DllConfig.h" + +class timespec; + +namespace Mantid { +namespace Instrumentation { + +/** AlgoTimeRegister : simple class to dump information about executed + * algorithms + */ +class AlgoTimeRegister { +public: + static AlgoTimeRegister globalAlgoTimeRegister; + static timespec diff(timespec start, timespec end); + struct Info { + std::string m_name; + std::thread::id m_threadId; + timespec m_begin; + timespec m_end; + + Info(const std::string &nm, const std::thread::id &id, const timespec &be, + const timespec &en) + : m_name(nm), m_threadId(id), m_begin(be), m_end(en) {} + }; + + class Dump { + AlgoTimeRegister &m_algoTimeRegister; + timespec m_regStart; + const std::string m_name; + + public: + Dump(AlgoTimeRegister &atr, const std::string &nm); + ~Dump(); + }; + + AlgoTimeRegister(); + ~AlgoTimeRegister(); + +private: + std::mutex m_mutex; + std::vector<Info> m_info; + timespec m_hstart; + std::chrono::high_resolution_clock::time_point m_start; +}; + +} // namespace Instrumentation +} // namespace Mantid + +#endif /* MANTID_API_ALGOTIMEREGISTER_H_ */ \ No newline at end of file diff --git a/Framework/API/inc/MantidAPI/Algorithm.h b/Framework/API/inc/MantidAPI/Algorithm.h index 37c4df0ab86e57e1c2c58dda569702dae656609a..e0d5939239f7596b6a3b8645b68152fedb5947de 100644 --- a/Framework/API/inc/MantidAPI/Algorithm.h +++ b/Framework/API/inc/MantidAPI/Algorithm.h @@ -216,7 +216,7 @@ public: /** @name IAlgorithm methods */ void initialize() override; - bool execute() override; + bool execute() override final; void executeAsChildAlg() override; std::map<std::string, std::string> validateInputs() override; bool isInitialized() const override; @@ -415,6 +415,8 @@ private: void logAlgorithmInfo() const; + bool executeInternal(); + bool executeAsyncImpl(const Poco::Void &i); bool doCallProcessGroups(Mantid::Types::Core::DateAndTime &start_time); diff --git a/Framework/API/src/AlgoTimeRegister.cpp b/Framework/API/src/AlgoTimeRegister.cpp new file mode 100644 index 0000000000000000000000000000000000000000..08fd1ca570adf65c37421d7df2cf7eaf8f6bf3b6 --- /dev/null +++ b/Framework/API/src/AlgoTimeRegister.cpp @@ -0,0 +1,59 @@ +#include "MantidAPI/AlgoTimeRegister.h" +#include "MantidKernel/MultiThreaded.h" +#include <fstream> +#include <time.h> + +namespace Mantid { +namespace Instrumentation { + +AlgoTimeRegister::Dump::Dump(AlgoTimeRegister &atr, const std::string &nm) + : m_algoTimeRegister(atr), m_name(nm) { + clock_gettime(CLOCK_MONOTONIC, &m_regStart); +} + +timespec AlgoTimeRegister::diff(timespec start, timespec end) { + timespec temp; + if ((end.tv_nsec - start.tv_nsec) < 0) { + temp.tv_sec = end.tv_sec - start.tv_sec - 1; + temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec - start.tv_sec; + temp.tv_nsec = end.tv_nsec - start.tv_nsec; + } + return temp; +} + +AlgoTimeRegister::Dump::~Dump() { + timespec regFinish; + clock_gettime(CLOCK_MONOTONIC, ®Finish); + { + std::lock_guard<std::mutex> lock(m_algoTimeRegister.m_mutex); + m_algoTimeRegister.m_info.emplace_back(m_name, std::this_thread::get_id(), + m_regStart, regFinish); + } +} + +AlgoTimeRegister::AlgoTimeRegister() + : m_start(std::chrono::high_resolution_clock::now()) { + clock_gettime(CLOCK_MONOTONIC, &m_hstart); +} + +AlgoTimeRegister::~AlgoTimeRegister() { + std::fstream fs; + fs.open("./algotimeregister.out", std::ios::out); + fs << "START_POINT: " + << std::chrono::duration_cast<std::chrono::nanoseconds>( + m_start.time_since_epoch()) + .count() + << " MAX_THREAD: " << PARALLEL_GET_MAX_THREADS << "\n"; + for (auto &elem : m_info) { + auto st = diff(m_hstart, elem.m_begin); + auto fi = diff(m_hstart, elem.m_end); + fs << elem.m_threadId << ">>" << elem.m_name << ":" + << std::size_t(st.tv_sec * 1000000000) + st.tv_nsec << "<>" + << std::size_t(fi.tv_sec * 1000000000) + fi.tv_nsec << "\n"; + } +} + +} // namespace Instrumentation +} // namespace Mantid diff --git a/Framework/API/src/Algorithm.cpp b/Framework/API/src/Algorithm.cpp index 7bf4718f14e411bddaa53c2fe382185b037c1d88..da1f1259134f3dec9881725508f88a34a8aa8d1b 100644 --- a/Framework/API/src/Algorithm.cpp +++ b/Framework/API/src/Algorithm.cpp @@ -434,17 +434,11 @@ void Algorithm::unlockWorkspaces() { } //--------------------------------------------------------------------------------------------- -/** The actions to be performed by the algorithm on a dataset. This method is - * invoked for top level algorithms by the application manager. - * This method invokes exec() method. - * For Child Algorithms either the execute() method or exec() method - * must be EXPLICITLY invoked by the parent algorithm. - * - * @throw runtime_error Thrown if algorithm or Child Algorithm cannot be - *executed - * @return true if executed successfully. +/** Invoced internally in execute() */ -bool Algorithm::execute() { + + +bool Algorithm::executeInternal() { Timer timer; AlgorithmManager::Instance().notifyAlgorithmStarting(this->getAlgorithmID()); { diff --git a/Framework/API/src/AlgorithmExecute.cpp b/Framework/API/src/AlgorithmExecute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e87618a4fc5ae57c125cb81b1c5ec8dbe25a5c0 --- /dev/null +++ b/Framework/API/src/AlgorithmExecute.cpp @@ -0,0 +1,27 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + + +#include "MantidAPI/Algorithm.h" + +namespace Mantid { +namespace API { +//--------------------------------------------------------------------------------------------- +/** The actions to be performed by the algorithm on a dataset. This method is + * invoked for top level algorithms by the application manager. + * This method invokes exec() method. + * For Child Algorithms either the execute() method or exec() method + * must be EXPLICITLY invoked by the parent algorithm. + * + * @throw runtime_error Thrown if algorithm or Child Algorithm cannot be + *executed + * @return true if executed successfully. + */ +bool Algorithm::execute() { + return executeInternal(); +} +} +} diff --git a/Framework/API/src/AlgorithmExecuteProfile.cpp b/Framework/API/src/AlgorithmExecuteProfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f5843ece8c82765cec85ae1182b1afb603bd27c --- /dev/null +++ b/Framework/API/src/AlgorithmExecuteProfile.cpp @@ -0,0 +1,32 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + + +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/AlgoTimeRegister.h" + +namespace Mantid { +Instrumentation::AlgoTimeRegister Instrumentation::AlgoTimeRegister::globalAlgoTimeRegister; +namespace API { + +//--------------------------------------------------------------------------------------------- +/** The actions to be performed by the algorithm on a dataset. This method is + * invoked for top level algorithms by the application manager. + * This method invokes exec() method. + * For Child Algorithms either the execute() method or exec() method + * must be EXPLICITLY invoked by the parent algorithm. + * + * @throw runtime_error Thrown if algorithm or Child Algorithm cannot be + *executed + * @return true if executed successfully. + */ +bool Algorithm::execute() { + Instrumentation::AlgoTimeRegister::AlgoTimeRegister::Dump + dmp(Instrumentation::AlgoTimeRegister::globalAlgoTimeRegister, name()); + return executeInternal(); +} +} +} \ No newline at end of file diff --git a/dev-docs/source/AlgorithmProfiler.rst b/dev-docs/source/AlgorithmProfiler.rst new file mode 100644 index 0000000000000000000000000000000000000000..357ae6d25b7b310b5c8ae0fd50990cf8da1d402a --- /dev/null +++ b/dev-docs/source/AlgorithmProfiler.rst @@ -0,0 +1,40 @@ +============================== +Work flows algorithm profiling +============================== + +.. contents:: Contents + :local: + +Summary +^^^^^^^ + +Due to the need of investigation of algorithms performance issues, the proper method +is introduced. It consists two to parts: special mantid build and analytical tool. +Available for Linux only. + +Mantid build +^^^^^^^^^^^^ + +To build mantid for profiling run ``cmake`` with the additional option ``-DPROFILE_ALGORITHM_LINUX=ON``. +Built in such a way mantid creates a dump file ``algotimeregister.out`` in the running directory. +This file contains the time stamps for start and finish of executed algorithms with ~nanocecond +precision in a very simple text format. + +Analysing tool +^^^^^^^^^^^^^^ + +The project is available here: https://github.com/nvaytet/mantid-profiler. It provides the nice graphical +tool to interpret the information from dumped file. + +Windows development +^^^^^^^^^^^^^^^^^^^ + +Precise timers are different for Linux and Windows (chrono is not good enough), so we need to treat them +separately. The suggestion is either to modify files ``Framework/API/inc/MantidAPI/AlgoTimeRegister.h`` and +``Framework/API/src/AlgoTimeRegister.cpp`` in manner ``#ifdef __WIN32`` or create the specific files with +the ``AlgoTimeRegister`` class for Windows and then in ``Framework/API/CMakeLists.txt`` edit the chunk that +describes option PROFILE_ALGORITHM_LINUX combined with OS defied flags e.g., also in this case +``Framework/API/src/AlgorithmExecuteProfile.cpp`` needs to be modified or substituted. +``${CMAKE_SYSTEM_NAME} MATCHES "Windows"``. QueryPerformanceCounter supposed to be used on windows, +instead of clock_gettime. +