From 1be69449ef30c11f4ee60ae5af869e8f4f8f769e Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Fri, 5 Apr 2019 13:46:25 +0200 Subject: [PATCH] Fix: make easy_profiler not a required dependency on the system. We do so by pulling out the profiling macros in our own iclude file. In the future we might even be able to use this to build up further visualisations of the executing programm. --- README.md | 4 ++++ app/invoke_parallel/CMakeLists.txt | 5 ++++- app/invoke_parallel/main.cpp | 16 +++++++++------- cmake/SetupEasyProfiler.cmake | 12 +++++++----- lib/pls/CMakeLists.txt | 5 +++-- lib/pls/include/pls/internal/base/prohibit_new.h | 31 ------------------------------- lib/pls/include/pls/internal/helpers/profiler.h | 33 +++++++++++++++++++++++++++++++++ lib/pls/include/pls/internal/helpers/prohibit_new.h | 31 +++++++++++++++++++++++++++++++ lib/pls/include/pls/internal/scheduling/fork_join_task.h | 6 +++--- lib/pls/include/pls/internal/scheduling/root_task.h | 9 +++++---- lib/pls/include/pls/internal/scheduling/scheduler.h | 5 +++-- lib/pls/src/internal/scheduling/abstract_task.cpp | 20 ++++++++++---------- lib/pls/src/internal/scheduling/fork_join_task.cpp | 18 +++++++++--------- 13 files changed, 121 insertions(+), 74 deletions(-) delete mode 100644 lib/pls/include/pls/internal/base/prohibit_new.h create mode 100644 lib/pls/include/pls/internal/helpers/profiler.h create mode 100644 lib/pls/include/pls/internal/helpers/prohibit_new.h diff --git a/README.md b/README.md index 3026a8b..9b22f58 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,10 @@ Available Settings: - Only one sanitizer can be active at once - Enabling has a performance hit (do not use in releases) +commit | fft(1) | fft(2) +--- | --- | --- +[d2eff7da](https://lab.las3.de/gitlab/las3/development/scheduling/predictable_parallel_patterns/commit/d2eff7dafcd822a4da662c2b4606d504b8545483) | 12.5ms -5.3% | 6.5ms -5.3% + ### Testing diff --git a/app/invoke_parallel/CMakeLists.txt b/app/invoke_parallel/CMakeLists.txt index adcb6be..944f5ef 100644 --- a/app/invoke_parallel/CMakeLists.txt +++ b/app/invoke_parallel/CMakeLists.txt @@ -1,2 +1,5 @@ add_executable(invoke_parallel main.cpp) -target_link_libraries(invoke_parallel pls easy_profiler) +target_link_libraries(invoke_parallel pls) +if(EASY_PROFILER) + target_link_libraries(invoke_parallel easy_profiler) +endif() diff --git a/app/invoke_parallel/main.cpp b/app/invoke_parallel/main.cpp index e16b8f7..4ae48ef 100644 --- a/app/invoke_parallel/main.cpp +++ b/app/invoke_parallel/main.cpp @@ -1,7 +1,7 @@ #include -#include +#include -#include +#include static pls::static_scheduler_memory<8, 2 << 14> my_scheduler_memory; @@ -33,17 +33,19 @@ long fib(long n) { } int main() { - EASY_PROFILER_ENABLE; + PROFILE_ENABLE pls::scheduler scheduler{&my_scheduler_memory, 8}; long result; scheduler.perform_work([&] { - EASY_MAIN_THREAD; + PROFILE_MAIN_THREAD // Call looks just the same, only requirement is // the enclosure in the perform_work lambda. - result = fib(30); + for (int i = 0; i < 10; i++) { + result = fib(30); + std::cout << "Fib(30)=" << result << std::endl; + } }); - std::cout << "Fib(30)=" << result << std::endl; - profiler::dumpBlocksToFile("test_profile.prof"); + PROFILE_SAVE("test_profile.prof") } diff --git a/cmake/SetupEasyProfiler.cmake b/cmake/SetupEasyProfiler.cmake index ddadb5f..745fedc 100644 --- a/cmake/SetupEasyProfiler.cmake +++ b/cmake/SetupEasyProfiler.cmake @@ -1,17 +1,19 @@ -# Optional external dependencies -find_package(easy_profiler) - option(EASY_PROFILER "Enable the profiler" OFF) if(EASY_PROFILER) - if(easy_profiler_FOUND) + # Optional external dependencies + find_package(easy_profiler) + if(easy_profiler_FOUND) + # Do nothing, add definitions below else() message(WARNING "EasyProfiler dependency not found on system, DISABLING it!") set(EASY_PROFILER OFF) endif() endif() -if(NOT EASY_PROFILER) +if(EASY_PROFILER) + add_definitions(-DENABLE_EASY_PROFILER) +else() add_definitions(-DDISABLE_EASY_PROFILER) endif() diff --git a/lib/pls/CMakeLists.txt b/lib/pls/CMakeLists.txt index 31fb1eb..758a947 100644 --- a/lib/pls/CMakeLists.txt +++ b/lib/pls/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(pls STATIC src/pls.cpp include/pls/pls.h src/internal/base/spin_lock.cpp include/pls/internal/base/spin_lock.h src/internal/base/thread.cpp include/pls/internal/base/thread.h - include/pls/internal/base/prohibit_new.h + include/pls/internal/helpers/prohibit_new.h src/internal/scheduling/abstract_task.cpp include/pls/internal/scheduling/abstract_task.h src/internal/scheduling/scheduler.cpp include/pls/internal/scheduling/scheduler.h src/internal/scheduling/thread_state.cpp include/pls/internal/scheduling/thread_state.h @@ -16,7 +16,8 @@ add_library(pls STATIC src/internal/base/deque.cpp include/pls/internal/base/deque.h src/algorithms/invoke_parallel.cpp include/pls/algorithms/invoke_parallel.h include/pls/internal/base/error_handling.h - include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp) + include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp + include/pls/internal/helpers/profiler.h) # Add everything in `./include` to be in the include path of this project target_include_directories(pls diff --git a/lib/pls/include/pls/internal/base/prohibit_new.h b/lib/pls/include/pls/internal/base/prohibit_new.h deleted file mode 100644 index 4ea59cc..0000000 --- a/lib/pls/include/pls/internal/base/prohibit_new.h +++ /dev/null @@ -1,31 +0,0 @@ -// Prevents the use of the new operator by forcing a linker error if it is used. -// Simply include this in your application and the linker will tell you if you -// use new somewhere (even in third party code linked to your application). - -#ifndef PLS_PROHIBIT_NEW_H -#define PLS_PROHIBIT_NEW_H - -#include - -// Comment this out and set a debug point in the std::cout -// line to find out where the new is located in case you -// get an linker error. -#define NEW_LINK_ERROR - -#ifdef NEW_LINK_ERROR -// This will cause a linker error if new is used in the code. -// We also exit if it is somehow still called. -inline void * operator new (std::size_t) { - extern int bare_new_erroneously_called(); - exit(bare_new_erroneously_called() | 1); -} -#else -// Use this + debugging point to find out where we use a new -inline void * operator new (std::size_t) { -// extern int bare_new_erroneously_called(); - std::cout << "New called! Exiting application, no dynamic memory allocation allowed!"; - exit(1); -} -#endif - -#endif //PLS_PROHIBIT_NEW_H diff --git a/lib/pls/include/pls/internal/helpers/profiler.h b/lib/pls/include/pls/internal/helpers/profiler.h new file mode 100644 index 0000000..221994d --- /dev/null +++ b/lib/pls/include/pls/internal/helpers/profiler.h @@ -0,0 +1,33 @@ + +#ifndef PLS_PROFILER_H +#define PLS_PROFILER_H +#ifdef ENABLE_EASY_PROFILER + +#include + +#define PROFILE_WORK_BLOCK(msg) EASY_BLOCK(msg, profiler::colors::LightGreen) +#define PROFILE_FORK_JOIN_STEALING(msg) EASY_BLOCK(msg, profiler::colors::LightBlue) +#define PROFILE_STEALING(msg) EASY_BLOCK(msg, profiler::colors::Blue) +#define PROFILE_LOCK(msg) EASY_BLOCK(msg, profiler::colors::Red) + +#define PROFILE_END_BLOCK EASY_END_BLOCK + +#define PROFILE_SAVE(filename) profiler::dumpBlocksToFile(filename); +#define PROFILE_ENABLE EASY_PROFILER_ENABLE +#define PROFILE_MAIN_THREAD EASY_MAIN_THREAD + +#else //ENABLE_EASY_PROFILER + +#define PROFILE_WORK_BLOCK(msg) +#define PROFILE_FORK_JOIN_STEALING(msg) +#define PROFILE_STEALING(msg) +#define PROFILE_LOCK(msg) + +#define PROFILE_END_BLOCK + +#define PROFILE_SAVE(filename) +#define PROFILE_ENABLE +#define PROFILE_MAIN_THREAD + +#endif //ENABLE_EASY_PROFILER +#endif //PLS_PROFILER_H diff --git a/lib/pls/include/pls/internal/helpers/prohibit_new.h b/lib/pls/include/pls/internal/helpers/prohibit_new.h new file mode 100644 index 0000000..4ea59cc --- /dev/null +++ b/lib/pls/include/pls/internal/helpers/prohibit_new.h @@ -0,0 +1,31 @@ +// Prevents the use of the new operator by forcing a linker error if it is used. +// Simply include this in your application and the linker will tell you if you +// use new somewhere (even in third party code linked to your application). + +#ifndef PLS_PROHIBIT_NEW_H +#define PLS_PROHIBIT_NEW_H + +#include + +// Comment this out and set a debug point in the std::cout +// line to find out where the new is located in case you +// get an linker error. +#define NEW_LINK_ERROR + +#ifdef NEW_LINK_ERROR +// This will cause a linker error if new is used in the code. +// We also exit if it is somehow still called. +inline void * operator new (std::size_t) { + extern int bare_new_erroneously_called(); + exit(bare_new_erroneously_called() | 1); +} +#else +// Use this + debugging point to find out where we use a new +inline void * operator new (std::size_t) { +// extern int bare_new_erroneously_called(); + std::cout << "New called! Exiting application, no dynamic memory allocation allowed!"; + exit(1); +} +#endif + +#endif //PLS_PROHIBIT_NEW_H diff --git a/lib/pls/include/pls/internal/scheduling/fork_join_task.h b/lib/pls/include/pls/internal/scheduling/fork_join_task.h index 36f5ccd..830772f 100644 --- a/lib/pls/include/pls/internal/scheduling/fork_join_task.h +++ b/lib/pls/include/pls/internal/scheduling/fork_join_task.h @@ -2,7 +2,7 @@ #ifndef PLS_TBB_LIKE_TASK_H #define PLS_TBB_LIKE_TASK_H -#include +#include "pls/internal/helpers/profiler.h" #include "pls/internal/base/aligned_stack.h" #include "pls/internal/base/deque.h" @@ -86,7 +86,7 @@ namespace pls { last_stolen_{nullptr} {}; void execute() override { - EASY_BLOCK("execute fork_join_task", profiler::colors::LightGreen); + PROFILE_WORK_BLOCK("execute fork_join_task"); // Bind this instance to our OS thread my_stack_ = base::this_thread::state()->task_stack_; @@ -102,7 +102,7 @@ namespace pls { template void fork_join_sub_task::spawn_child(const T& task) { - EASY_FUNCTION(profiler::colors::Blue) + PROFILE_FORK_JOIN_STEALING("spawn_child") static_assert(std::is_base_of::value, "Only pass fork_join_sub_task subclasses!"); T* new_task = tbb_task_->my_stack_->push(task); diff --git a/lib/pls/include/pls/internal/scheduling/root_task.h b/lib/pls/include/pls/internal/scheduling/root_task.h index cdb7f0b..6834b6b 100644 --- a/lib/pls/include/pls/internal/scheduling/root_task.h +++ b/lib/pls/include/pls/internal/scheduling/root_task.h @@ -2,12 +2,13 @@ #ifndef PLS_ROOT_MASTER_TASK_H #define PLS_ROOT_MASTER_TASK_H -#include #include -#include "abstract_task.h" +#include "pls/internal/helpers/profiler.h" #include "pls/internal/base/spin_lock.h" +#include "abstract_task.h" + namespace pls { namespace internal { namespace scheduling { @@ -30,7 +31,7 @@ namespace pls { } void execute() override { - EASY_BLOCK("execute root_task", profiler::colors::LightGreen); + PROFILE_WORK_BLOCK("execute root_task"); function_(); finished_ = 1; } @@ -54,7 +55,7 @@ namespace pls { master_task_{master_task} {} void execute() override { - EASY_BLOCK("execute root_task", profiler::colors::LightGreen); + PROFILE_WORK_BLOCK("execute root_task"); do { steal_work(); } while (!master_task_->finished()); diff --git a/lib/pls/include/pls/internal/scheduling/scheduler.h b/lib/pls/include/pls/internal/scheduling/scheduler.h index b0e7136..55e72b5 100644 --- a/lib/pls/include/pls/internal/scheduling/scheduler.h +++ b/lib/pls/include/pls/internal/scheduling/scheduler.h @@ -2,10 +2,11 @@ #ifndef PLS_SCHEDULER_H #define PLS_SCHEDULER_H -#include #include #include +#include "pls/internal/helpers/profiler.h" + #include "pls/internal/base/aligned_stack.h" #include "pls/internal/base/thread.h" #include "pls/internal/base/barrier.h" @@ -34,7 +35,7 @@ namespace pls { template void perform_work(Function work_section) { - EASY_FUNCTION(); + PROFILE_WORK_BLOCK("scheduler::perform_work") root_task master{work_section}; // Push root task on stacks diff --git a/lib/pls/src/internal/scheduling/abstract_task.cpp b/lib/pls/src/internal/scheduling/abstract_task.cpp index 7cf7dca..3b75bd0 100644 --- a/lib/pls/src/internal/scheduling/abstract_task.cpp +++ b/lib/pls/src/internal/scheduling/abstract_task.cpp @@ -1,4 +1,4 @@ -#include +#include "pls/internal/helpers/profiler.h" #include "pls/internal/scheduling/thread_state.h" #include "pls/internal/scheduling/abstract_task.h" @@ -8,7 +8,7 @@ namespace pls { namespace internal { namespace scheduling { bool abstract_task::steal_work() { - EASY_FUNCTION(profiler::colors::Orange); + PROFILE_STEALING("abstract_task::steal_work") auto my_state = base::this_thread::state(); auto my_scheduler = my_state->scheduler_; @@ -18,19 +18,19 @@ namespace pls { auto target_state = my_scheduler->thread_state_for(target); // TODO: Cleaner Locking Using std::guarded_lock - EASY_BLOCK("Acquire Thread Lock", profiler::colors::Red) + PROFILE_LOCK("Acquire Thread Lock") target_state->lock_.lock(); - EASY_END_BLOCK; + PROFILE_END_BLOCK // Dig down to our level - EASY_BLOCK("Go to our level") + PROFILE_STEALING("Go to our level") abstract_task* current_task = target_state->root_task_; while (current_task != nullptr && current_task->depth() < depth()) { current_task = current_task->child_task_; } - EASY_END_BLOCK; + PROFILE_END_BLOCK - EASY_BLOCK("Internal Steal") + PROFILE_STEALING("Internal Steal") if (current_task != nullptr) { // See if it equals our type and depth of task if (current_task->unique_id_ == unique_id_ && @@ -45,12 +45,12 @@ namespace pls { current_task = current_task->child_task_; } } - EASY_END_BLOCK; + PROFILE_END_BLOCK; // Execute 'top level task steal' if possible // (only try deeper tasks to keep depth restricted stealing) - EASY_BLOCK("Top Level Steal") + PROFILE_STEALING("Top Level Steal") while (current_task != nullptr) { auto lock = &target_state->lock_; if (current_task->split_task(lock)) { @@ -60,7 +60,7 @@ namespace pls { current_task = current_task->child_task_; } - EASY_END_BLOCK; + PROFILE_END_BLOCK; target_state->lock_.unlock(); } diff --git a/lib/pls/src/internal/scheduling/fork_join_task.cpp b/lib/pls/src/internal/scheduling/fork_join_task.cpp index e4c9719..1f1360c 100644 --- a/lib/pls/src/internal/scheduling/fork_join_task.cpp +++ b/lib/pls/src/internal/scheduling/fork_join_task.cpp @@ -1,4 +1,4 @@ -#include +#include "pls/internal/helpers/profiler.h" #include "pls/internal/scheduling/scheduler.h" #include "pls/internal/scheduling/fork_join_task.h" @@ -21,11 +21,11 @@ namespace pls { stack_state_{nullptr} {} void fork_join_sub_task::execute() { - EASY_BLOCK("execute sub_task", profiler::colors::Green); + PROFILE_WORK_BLOCK("execute sub_task") tbb_task_->currently_executing_ = this; execute_internal(); tbb_task_->currently_executing_ = nullptr; - EASY_END_BLOCK; + PROFILE_END_BLOCK wait_for_all(); if (parent_ != nullptr) { @@ -47,17 +47,17 @@ namespace pls { void fork_join_sub_task::wait_for_all() { while (ref_count_ > 0) { - EASY_BLOCK("get local sub task", profiler::colors::Blue) + PROFILE_STEALING("get local sub task") fork_join_sub_task* local_task = tbb_task_->get_local_sub_task(); - EASY_END_BLOCK + PROFILE_END_BLOCK if (local_task != nullptr) { local_task->execute(); } else { // Try to steal work. // External steal will be executed implicitly if success - EASY_BLOCK("steal work", profiler::colors::Blue) + PROFILE_STEALING("steal work") bool internal_steal_success = tbb_task_->steal_work(); - EASY_END_BLOCK + PROFILE_END_BLOCK if (internal_steal_success) { tbb_task_->last_stolen_->execute(); } @@ -75,7 +75,7 @@ namespace pls { } bool fork_join_task::internal_stealing(abstract_task* other_task) { - EASY_FUNCTION(profiler::colors::Blue); + PROFILE_STEALING("fork_join_task::internal_stealin") auto cast_other_task = reinterpret_cast(other_task); auto stolen_sub_task = cast_other_task->get_stolen_sub_task(); @@ -93,7 +93,7 @@ namespace pls { } bool fork_join_task::split_task(base::spin_lock* lock) { - EASY_FUNCTION(profiler::colors::Blue); + PROFILE_STEALING("fork_join_task::split_task") fork_join_sub_task* stolen_sub_task = get_stolen_sub_task(); if (stolen_sub_task == nullptr) { return false; -- libgit2 0.26.0