From 9e5b6dd2577db26fa5d3a8c33c9b0f146aded731 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 29 Jul 2021 17:24:31 +0200 Subject: [PATCH 01/47] start profiling - cmake option - cpu timings in call --- cmake/megamol_options.cmake | 5 +++++ core/include/mmcore/Call.h | 13 +++++++++++++ core/src/Call.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/cmake/megamol_options.cmake b/cmake/megamol_options.cmake index 99fc2baaa5..1b09cc1737 100644 --- a/cmake/megamol_options.cmake +++ b/cmake/megamol_options.cmake @@ -45,6 +45,11 @@ if(ENABLE_CUDA) set(CMAKE_CUDA_ARCHITECTURES FALSE) endif() +option(ENABLE_PROFILING "Enable profiling code" OFF) +if (ENABLE_PROFILING) + add_compile_definitions(PROFILING) +endif() + # GLFW option(USE_GLFW "Use GLFW" ON) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index f2e3f0d63a..7769c1003a 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -12,6 +12,9 @@ #endif /* (defined(_MSC_VER) && (_MSC_VER > 1000)) */ #include +#ifdef PROFILING +#include +#endif #include "mmcore/api/MegaMolCore.std.h" @@ -109,6 +112,16 @@ namespace core { /** The function id mapping */ unsigned int *funcMap; +#ifdef PROFILING + std::vector last_cpu_time; + std::vector avg_cpu_time; + std::vector num_cpu_time_samples; + + std::vector last_gpu_time; + std::vector avg_gpu_time; + std::vector num_gpu_time_samples; +#endif PROFILING + }; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 2657dfe0e3..58b74d8199 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -16,6 +16,11 @@ # include "mmcore/view/Renderer3DModuleGL.h" # include "vislib/graphics/gl/IncludeAllGL.h" #endif +#ifdef PROFILING +# include "mmcore/view/Renderer3DModuleGL.h" +# include "mmcore/view/Renderer2DModule.h" +# include +#endif #include "mmcore/utility/log/Log.h" using namespace megamol::core; @@ -65,8 +70,31 @@ bool Call::operator()(unsigned int func) { glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 1234, -1, output.c_str()); // megamol::core::utility::log::Log::DefaultLog.WriteInfo("called %s::%s", p3->ClassName(), f); } +#endif +#ifdef PROFILING + const auto f = this->callee->GetCallbackFuncName(func); + const auto parent = this->callee->Parent().get(); + const auto gl_1 = dynamic_cast(parent); + const auto gl_2 = dynamic_cast(parent); + const std::clock_t c_start = std::clock(); + const auto paranoid_size = std::max(static_cast(last_cpu_time.size()), func + 1); + last_cpu_time.resize(paranoid_size, 0.0); + avg_cpu_time.resize(paranoid_size, 0.0); + num_cpu_time_samples.resize(paranoid_size, 0); + last_gpu_time.resize(paranoid_size, 0.0); + avg_gpu_time.resize(paranoid_size, 0.0); + num_gpu_time_samples.resize(paranoid_size, 0); + + if (gl_1 || gl_2) { + // todo gl query and stuff + } #endif res = this->callee->InCall(this->funcMap[func], *this); +#ifdef PROFILING + const std::clock_t c_end = std::clock(); + last_cpu_time[func] = 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC; + avg_cpu_time[func] = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]) / ++num_cpu_time_samples[func]; +#endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS if (p2 || p3 || p3_2) glPopDebugGroup(); #endif From b8de2ccc8dc6cf367530335f08bfe5f12db13e1b Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 29 Jul 2021 17:39:09 +0200 Subject: [PATCH 02/47] Call: profiling data getters profile in modules instead? --- core/include/mmcore/Call.h | 39 ++++++++++++++++++++++++++++++++ core/include/mmcore/CalleeSlot.h | 1 + 2 files changed, 40 insertions(+) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 7769c1003a..e7650b45fa 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -99,6 +99,45 @@ namespace core { return this->className; } +#ifdef PROFILING + inline double GetLastCPUTime(uint32_t func) const { + if (func < last_cpu_time.size()) + return last_cpu_time[func]; + else + return -1.0; + } + inline double GetAverageCPUTime(uint32_t func) const { + if (func < avg_cpu_time.size()) + return avg_cpu_time[func]; + else + return -1.0; + } + inline uint32_t GetNumCPUSamples(uint32_t func) const { + if (func < num_cpu_time_samples.size()) + return num_cpu_time_samples[func]; + else + return 0; + } + inline double GetLastGPUTime(uint32_t func) const { + if (func < last_gpu_time.size()) + return last_gpu_time[func]; + else + return -1.0; + } + inline double GetAverageGPUTime(uint32_t func) const { + if (func < avg_gpu_time.size()) + return avg_gpu_time[func]; + else + return -1.0; + } + inline uint32_t GetNumGPUSamples(uint32_t func) const { + if (func < num_gpu_time_samples.size()) + return num_gpu_time_samples[func]; + else + return 0; + } +#endif + private: /** The callee connected by this call */ diff --git a/core/include/mmcore/CalleeSlot.h b/core/include/mmcore/CalleeSlot.h index 952cd2e151..2801aff59d 100644 --- a/core/include/mmcore/CalleeSlot.h +++ b/core/include/mmcore/CalleeSlot.h @@ -335,6 +335,7 @@ namespace core { virtual bool CallMe(Module *owner, Call& call) { C *c = dynamic_cast(owner); if (c == NULL) return false; + // TODO alternatively, profiling could be done here and data stored in the module? return (c->*func)(call); } From 75f2299723c34a8a0d8775393dd9e05b53df0255 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 29 Jul 2021 18:20:21 +0200 Subject: [PATCH 03/47] gpu profile queries --- core/include/mmcore/Call.h | 15 +++++++++++++++ core/src/Call.cpp | 23 ++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index e7650b45fa..4fdc0c8e41 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -14,6 +14,7 @@ #include #ifdef PROFILING #include +#include #endif #include "mmcore/api/MegaMolCore.std.h" @@ -159,6 +160,20 @@ namespace core { std::vector last_gpu_time; std::vector avg_gpu_time; std::vector num_gpu_time_samples; + + class my_query_id { + public: + my_query_id(); + ~my_query_id(); + uint32_t Get() { + return the_id; + } + private: + uint32_t the_id = 0; + }; + std::array, 2> queries; + uint32_t query_start_buffer = 1; + uint32_t query_read_buffer = 0; #endif PROFILING }; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 58b74d8199..23c4b9eb44 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -51,6 +51,18 @@ Call::~Call(void) { } +#ifdef PROFILING +Call::my_query_id::my_query_id() { + glGenQueries(1, &the_id); + glBeginQuery(GL_TIME_ELAPSED, the_id); +} +Call::my_query_id::~my_query_id() { + glDeleteQueries(1, &the_id); +} + +#endif + + /* * Call::operator() */ @@ -86,7 +98,9 @@ bool Call::operator()(unsigned int func) { num_gpu_time_samples.resize(paranoid_size, 0); if (gl_1 || gl_2) { - // todo gl query and stuff + queries[query_start_buffer].resize(paranoid_size); + queries[query_read_buffer].resize(paranoid_size); + glBeginQuery(GL_TIME_ELAPSED, queries[query_start_buffer][func].Get()); } #endif res = this->callee->InCall(this->funcMap[func], *this); @@ -94,6 +108,13 @@ bool Call::operator()(unsigned int func) { const std::clock_t c_end = std::clock(); last_cpu_time[func] = 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC; avg_cpu_time[func] = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]) / ++num_cpu_time_samples[func]; + if (gl_1 || gl_2) { + GLuint64 time; + glGetQueryObjectui64v(queries[query_read_buffer][func].Get(), GL_QUERY_RESULT, &time); + last_gpu_time[func] = time / 1000000.0; + avg_gpu_time[func] = (avg_gpu_time[func] * num_gpu_time_samples[func] + last_gpu_time[func]) / ++num_gpu_time_samples[func]; + std::swap(query_start_buffer, query_read_buffer); + } #endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS if (p2 || p3 || p3_2) glPopDebugGroup(); From c7b8b636a62ba78cb638556785e183ae266ca812 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 29 Jul 2021 18:44:13 +0200 Subject: [PATCH 04/47] pipe profiling values to gui --- core/include/mmcore/Call.h | 8 +++++++- plugins/gui/src/graph/Call.cpp | 24 +++++++++++++++++++++- plugins/gui/src/graph/Call.h | 23 +++++++++++++++++++++ plugins/gui/src/graph/GraphCollection.cpp | 25 +++++++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 4fdc0c8e41..f04784b610 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -136,7 +136,13 @@ namespace core { return num_gpu_time_samples[func]; else return 0; - } + } + + inline uint32_t GetFuncCount() const { + /// XXX assert(last_cpu_time.size() == avg_cpu_time.size() == num_cpu_time_samples.size() == last_gpu_time.size() == + /// avg_gpu_time.size() == num_gpu_time_samples.size()); + return static_cast(last_cpu_time.size()); + } #endif private: diff --git a/plugins/gui/src/graph/Call.cpp b/plugins/gui/src/graph/Call.cpp index 6b97fab051..eaa4a756a8 100644 --- a/plugins/gui/src/graph/Call.cpp +++ b/plugins/gui/src/graph/Call.cpp @@ -26,7 +26,11 @@ megamol::gui::Call::Call(ImGuiID uid, const std::string& class_name, const std:: , gui_selected(false) , caller_slot_name() , callee_slot_name() - , gui_tooltip() { + , gui_tooltip() +#ifdef PROFILING + , profiling() +#endif // PROFILING +{ this->connected_callslots.emplace(CallSlotType::CALLER, nullptr); this->connected_callslots.emplace(CallSlotType::CALLEE, nullptr); @@ -270,7 +274,25 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr // Hover Tooltip if (!state.interact.call_show_slots_label) { if (state.interact.call_hovered_uid == this->uid) { +#ifdef PROFILING + auto tooltip_text = slots_label; + std::stringstream profstream; + profstream << std::fixed << std::setprecision(15); + auto func_cnt = this->profiling.size(); + for (size_t i = 0; i < func_cnt; i++) { + profstream << "\n--- Callback #" << i + << " ---\nLastCPUTime : " << this->profiling[i].lcput + << "\nAverageCPUTime: " << this->profiling[i].acput + << "\nNumCPUSamples: " << this->profiling[i].ncpus + << "\nLastGPUTime: " << this->profiling[i].lgput + << "\nAverageGPUTime: " << this->profiling[i].agput + << "\nNumGPUSamples: " << this->profiling[i].ngpus; + } + tooltip_text += profstream.str(); + this->gui_tooltip.ToolTip(tooltip_text); +#else this->gui_tooltip.ToolTip(slots_label, ImGui::GetID(button_label.c_str()), 0.5f, 5.0f); +#endif // PROFILING } else { this->gui_tooltip.Reset(); } diff --git a/plugins/gui/src/graph/Call.h b/plugins/gui/src/graph/Call.h index ad13c63d5b..78b02e3f09 100644 --- a/plugins/gui/src/graph/Call.h +++ b/plugins/gui/src/graph/Call.h @@ -68,6 +68,23 @@ namespace gui { return std::string(this->caller_slot_name + this->slot_name_separator + this->callee_slot_name); } +#ifdef PROFILING + + struct Profiling { + double lcput; + double acput; + uint32_t ncpus; + double lgput; + double agput; + uint32_t ngpus; + }; + + void SetProfilingValues(const std::vector& p) { + this->profiling = p; + } + +#endif // PROFILING + private: // VARIABLES -------------------------------------------------------------- @@ -85,6 +102,12 @@ namespace gui { std::string callee_slot_name; HoverToolTip gui_tooltip; + +#ifdef PROFILING + + std::vector profiling; + +#endif // PROFILING }; diff --git a/plugins/gui/src/graph/GraphCollection.cpp b/plugins/gui/src/graph/GraphCollection.cpp index 9995ee45ce..ba91f01090 100644 --- a/plugins/gui/src/graph/GraphCollection.cpp +++ b/plugins/gui/src/graph/GraphCollection.cpp @@ -634,6 +634,31 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( } } + +#ifdef PROFILING + + // Sync profiling values from core calls to gui calls ... + for (auto& ccall : megamol_graph.ListCalls()) { + for (auto& gcall : graph_ptr->Calls()) { + if (gcall->ClassName() == ccall.request.className) { + auto func_count = ccall.callPtr->GetFuncCount(); + std::vector prof; + prof.resize(func_count); + for (uint32_t i = 0; i < func_count; i++) { + prof[i].lcput = ccall.callPtr->GetLastCPUTime(i); + prof[i].acput = ccall.callPtr->GetAverageCPUTime(i); + prof[i].ncpus = ccall.callPtr->GetNumCPUSamples(i); + prof[i].lgput = ccall.callPtr->GetLastGPUTime(i); + prof[i].agput = ccall.callPtr->GetAverageGPUTime(i); + prof[i].ngpus = ccall.callPtr->GetNumGPUSamples(i); + } + gcall->SetProfilingValues(prof); + } + } + } + +#endif // PROFILING + if (gui_graph_changed) { graph_ptr->ClearSyncQueue(); megamol::core::utility::log::Log::DefaultLog.WriteInfo( From 38dec04b5e12d72f481e44273adb168e11d8087e Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 29 Jul 2021 19:07:25 +0200 Subject: [PATCH 05/47] weird stuff for gl perf, but cannot work like this --- core/include/mmcore/Call.h | 10 +++++++++- core/src/Call.cpp | 31 +++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 4fdc0c8e41..18aa9cfcaa 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -165,11 +165,19 @@ namespace core { public: my_query_id(); ~my_query_id(); - uint32_t Get() { + my_query_id(const my_query_id&); + uint32_t Get() const { return the_id; } + bool Started() const { + return started; + } + void Start() { + started = true; + } private: uint32_t the_id = 0; + bool started = false; }; std::array, 2> queries; uint32_t query_start_buffer = 1; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 23c4b9eb44..3f6a2cd854 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -54,12 +54,13 @@ Call::~Call(void) { #ifdef PROFILING Call::my_query_id::my_query_id() { glGenQueries(1, &the_id); - glBeginQuery(GL_TIME_ELAPSED, the_id); } Call::my_query_id::~my_query_id() { glDeleteQueries(1, &the_id); } - +Call::my_query_id::my_query_id(const my_query_id&) { + glGenQueries(1, &the_id); +} #endif @@ -98,9 +99,13 @@ bool Call::operator()(unsigned int func) { num_gpu_time_samples.resize(paranoid_size, 0); if (gl_1 || gl_2) { - queries[query_start_buffer].resize(paranoid_size); - queries[query_read_buffer].resize(paranoid_size); - glBeginQuery(GL_TIME_ELAPSED, queries[query_start_buffer][func].Get()); + // you can only have one query per target in flight. no idea what to do really. + + //queries[query_start_buffer].resize(paranoid_size); + //queries[query_read_buffer].resize(paranoid_size); + //auto& q = queries[query_start_buffer][func]; + //glBeginQuery(GL_TIME_ELAPSED, q.Get()); + //q.Start(); } #endif res = this->callee->InCall(this->funcMap[func], *this); @@ -109,11 +114,17 @@ bool Call::operator()(unsigned int func) { last_cpu_time[func] = 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC; avg_cpu_time[func] = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]) / ++num_cpu_time_samples[func]; if (gl_1 || gl_2) { - GLuint64 time; - glGetQueryObjectui64v(queries[query_read_buffer][func].Get(), GL_QUERY_RESULT, &time); - last_gpu_time[func] = time / 1000000.0; - avg_gpu_time[func] = (avg_gpu_time[func] * num_gpu_time_samples[func] + last_gpu_time[func]) / ++num_gpu_time_samples[func]; - std::swap(query_start_buffer, query_read_buffer); + //GLuint64 time; + //auto& q = queries[query_read_buffer][func]; + //if (q.Started()) { + // int done = 0; + // glGetQueryObjectiv(q.Get(), GL_QUERY_RESULT_AVAILABLE, &done); + // ASSERT(done); + // glGetQueryObjectui64v(q.Get(), GL_QUERY_RESULT, &time); + // last_gpu_time[func] = static_cast(time / 1000000.0); + // avg_gpu_time[func] = (avg_gpu_time[func] * num_gpu_time_samples[func] + last_gpu_time[func]) / ++num_gpu_time_samples[func]; + //} + //std::swap(query_start_buffer, query_read_buffer); } #endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS From 6a8edc1638a67f0185a8912930d6e6c717fd592e Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 29 Jul 2021 19:22:33 +0200 Subject: [PATCH 06/47] hiding GPU info since it's no use anyway ATM --- core/src/Call.cpp | 4 ++-- plugins/gui/src/graph/Call.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 3f6a2cd854..dbfb00ae83 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -111,8 +111,8 @@ bool Call::operator()(unsigned int func) { res = this->callee->InCall(this->funcMap[func], *this); #ifdef PROFILING const std::clock_t c_end = std::clock(); - last_cpu_time[func] = 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC; - avg_cpu_time[func] = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]) / ++num_cpu_time_samples[func]; + last_cpu_time[func] = 1000.0 * (static_cast(c_end-c_start) / CLOCKS_PER_SEC); + avg_cpu_time[func] = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]) / (++num_cpu_time_samples[func]); if (gl_1 || gl_2) { //GLuint64 time; //auto& q = queries[query_read_buffer][func]; diff --git a/plugins/gui/src/graph/Call.cpp b/plugins/gui/src/graph/Call.cpp index eaa4a756a8..c70d936265 100644 --- a/plugins/gui/src/graph/Call.cpp +++ b/plugins/gui/src/graph/Call.cpp @@ -283,10 +283,10 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr profstream << "\n--- Callback #" << i << " ---\nLastCPUTime : " << this->profiling[i].lcput << "\nAverageCPUTime: " << this->profiling[i].acput - << "\nNumCPUSamples: " << this->profiling[i].ncpus - << "\nLastGPUTime: " << this->profiling[i].lgput - << "\nAverageGPUTime: " << this->profiling[i].agput - << "\nNumGPUSamples: " << this->profiling[i].ngpus; + << "\nNumCPUSamples: " << this->profiling[i].ncpus; + //<< "\nLastGPUTime: " << this->profiling[i].lgput + //<< "\nAverageGPUTime: " << this->profiling[i].agput + //<< "\nNumGPUSamples: " << this->profiling[i].ngpus; } tooltip_text += profstream.str(); this->gui_tooltip.ToolTip(tooltip_text); From 46a76373dd40af011f41444940690ab161188ea7 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 29 Jul 2021 19:35:56 +0200 Subject: [PATCH 07/47] moved profiling values from tooltip to context menu of calls --- plugins/gui/src/graph/Call.cpp | 73 +++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/plugins/gui/src/graph/Call.cpp b/plugins/gui/src/graph/Call.cpp index eaa4a756a8..dd5c3be95e 100644 --- a/plugins/gui/src/graph/Call.cpp +++ b/plugins/gui/src/graph/Call.cpp @@ -267,32 +267,67 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr ImGui::PushTextWrapPos(ImGui::GetFontSize() * 13.0f); ImGui::TextUnformatted(this->description.c_str()); ImGui::PopTextWrapPos(); - +#ifdef PROFILING + ImGui::Separator(); + ImGui::TextUnformatted("Profiling"); + ImGui::SameLine(); + ImGui::TextDisabled("[Callback #:]"); + ImGui::BeginTabBar("profiling", ImGuiTabBarFlags_AutoSelectNewTabs); + auto func_cnt = this->profiling.size(); + for (size_t i = 0; i < func_cnt; i++) { + auto tab_label = std::to_string(i); + if (ImGui::BeginTabItem(tab_label.c_str(), nullptr, ImGuiTabItemFlags_None)) { + if (ImGui::BeginTable(("table_" + tab_label).c_str(), 2, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableColumnFlags_NoResize, + ImVec2(ImGui::GetTextLineHeightWithSpacing() * 15.0f, 0.0f))) { + ImGui::TableSetupColumn( + ("column_" + tab_label).c_str(), ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("LastCPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].lcput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("AverageCPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].acput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("NumCPUSamples"); + ImGui::TableNextColumn(); + ImGui::Text("%i", this->profiling[i].ncpus); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("LastGPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].lgput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("AverageGPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].agput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("NumGPUSamples"); + ImGui::TableNextColumn(); + ImGui::Text("%i", this->profiling[i].ngpus); + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } + } + ImGui::EndTabBar(); +#endif // PROFILING ImGui::EndPopup(); } // Hover Tooltip if (!state.interact.call_show_slots_label) { if (state.interact.call_hovered_uid == this->uid) { -#ifdef PROFILING - auto tooltip_text = slots_label; - std::stringstream profstream; - profstream << std::fixed << std::setprecision(15); - auto func_cnt = this->profiling.size(); - for (size_t i = 0; i < func_cnt; i++) { - profstream << "\n--- Callback #" << i - << " ---\nLastCPUTime : " << this->profiling[i].lcput - << "\nAverageCPUTime: " << this->profiling[i].acput - << "\nNumCPUSamples: " << this->profiling[i].ncpus - << "\nLastGPUTime: " << this->profiling[i].lgput - << "\nAverageGPUTime: " << this->profiling[i].agput - << "\nNumGPUSamples: " << this->profiling[i].ngpus; - } - tooltip_text += profstream.str(); - this->gui_tooltip.ToolTip(tooltip_text); -#else this->gui_tooltip.ToolTip(slots_label, ImGui::GetID(button_label.c_str()), 0.5f, 5.0f); -#endif // PROFILING + } else { this->gui_tooltip.Reset(); } From 9fe7c76e04c86a11473415f057e8885823279cb4 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 30 Jul 2021 13:30:39 +0200 Subject: [PATCH 08/47] moved profiling info into call label --- plugins/gui/src/graph/Call.cpp | 148 ++++++++++++++-------- plugins/gui/src/graph/Call.h | 3 + plugins/gui/src/graph/GraphCollection.cpp | 11 +- 3 files changed, 106 insertions(+), 56 deletions(-) diff --git a/plugins/gui/src/graph/Call.cpp b/plugins/gui/src/graph/Call.cpp index dd5c3be95e..8d053b7d04 100644 --- a/plugins/gui/src/graph/Call.cpp +++ b/plugins/gui/src/graph/Call.cpp @@ -29,6 +29,7 @@ megamol::gui::Call::Call(ImGuiID uid, const std::string& class_name, const std:: , gui_tooltip() #ifdef PROFILING , profiling() + , show_profiling_data(false) #endif // PROFILING { @@ -228,8 +229,18 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr if (state.interact.call_show_label && state.interact.call_show_slots_label) { rect_size.y += (ImGui::GetFontSize() + style.ItemSpacing.y); } +#ifdef PROFILING + rect_size.x += ImGui::GetFrameHeightWithSpacing(); + rect_size.y = ImGui::GetFrameHeightWithSpacing() + style.ItemSpacing.y; +#endif ImVec2 call_rect_min = ImVec2(call_center.x - (rect_size.x / 2.0f), call_center.y - (rect_size.y / 2.0f)); +#ifdef PROFILING + if (this->show_profiling_data) { + rect_size = ImVec2((ImGui::GetFrameHeight() * 10.0f + style.ItemSpacing.x * 2.0f), + (ImGui::GetFrameHeight() * 9.0f + style.ItemSpacing.x)); + } +#endif ImVec2 call_rect_max = ImVec2((call_rect_min.x + rect_size.x), (call_rect_min.y + rect_size.y)); std::string button_label = "call_" + std::to_string(this->uid); @@ -267,59 +278,6 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr ImGui::PushTextWrapPos(ImGui::GetFontSize() * 13.0f); ImGui::TextUnformatted(this->description.c_str()); ImGui::PopTextWrapPos(); -#ifdef PROFILING - ImGui::Separator(); - ImGui::TextUnformatted("Profiling"); - ImGui::SameLine(); - ImGui::TextDisabled("[Callback #:]"); - ImGui::BeginTabBar("profiling", ImGuiTabBarFlags_AutoSelectNewTabs); - auto func_cnt = this->profiling.size(); - for (size_t i = 0; i < func_cnt; i++) { - auto tab_label = std::to_string(i); - if (ImGui::BeginTabItem(tab_label.c_str(), nullptr, ImGuiTabItemFlags_None)) { - if (ImGui::BeginTable(("table_" + tab_label).c_str(), 2, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableColumnFlags_NoResize, - ImVec2(ImGui::GetTextLineHeightWithSpacing() * 15.0f, 0.0f))) { - ImGui::TableSetupColumn( - ("column_" + tab_label).c_str(), ImGuiTableColumnFlags_WidthStretch); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("LastCPUTime"); - ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].lcput); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("AverageCPUTime"); - ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].acput); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("NumCPUSamples"); - ImGui::TableNextColumn(); - ImGui::Text("%i", this->profiling[i].ncpus); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("LastGPUTime"); - ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].lgput); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("AverageGPUTime"); - ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].agput); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("NumGPUSamples"); - ImGui::TableNextColumn(); - ImGui::Text("%i", this->profiling[i].ngpus); - ImGui::EndTable(); - } - ImGui::EndTabItem(); - } - } - ImGui::EndTabBar(); -#endif // PROFILING ImGui::EndPopup(); } @@ -377,6 +335,27 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr // Draw Text ImVec2 text_pos_left_upper = (call_center + ImVec2(-(class_name_width / 2.0f), -0.5f * ImGui::GetFontSize())); +#ifdef PROFILING + // ImGui::PushFont(state.canvas.gui_font_ptr); + text_pos_left_upper = call_rect_min + style.ItemSpacing; + ImGui::SetCursorScreenPos(text_pos_left_upper); + if (ImGui::ArrowButton( + "###profiling", ((this->show_profiling_data) ? (ImGuiDir_Down) : (ImGuiDir_Up)))) { + this->show_profiling_data = !this->show_profiling_data; + } + this->gui_tooltip.ToolTip("Profiling"); + if (this->show_profiling_data) { + text_pos_left_upper.y += ImGui::GetFrameHeight(); + ImGui::SetCursorScreenPos(text_pos_left_upper); + this->draw_profiling_data(); + } + text_pos_left_upper.x += ImGui::GetFrameHeightWithSpacing(); + text_pos_left_upper.y += (ImGui::GetFrameHeight() - ImGui::GetFontSize()) * 0.5f; + if (this->show_profiling_data) { + text_pos_left_upper.y -= ImGui::GetFrameHeight(); + } + // ImGui::PopFont(); +#endif if (state.interact.call_show_label && state.interact.call_show_slots_label) { text_pos_left_upper.y -= (0.5f * ImGui::GetFontSize()); } @@ -417,3 +396,66 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr return; } } + +#ifdef PROFILING + +void megamol::gui::Call::draw_profiling_data() { + + const float width = ImGui::GetFrameHeight() * 10.0f; + const float height = ImGui::GetFrameHeight() * 8.0f; + + ImGui::BeginChild("call_profiling_info", ImVec2(width, height), false, ImGuiWindowFlags_NoMove); + + ImGui::TextUnformatted("Profiling"); + ImGui::SameLine(); + ImGui::TextDisabled("[Callback #:]"); + ImGui::BeginTabBar("profiling", ImGuiTabBarFlags_AutoSelectNewTabs); + auto func_cnt = this->profiling.size(); + for (size_t i = 0; i < func_cnt; i++) { + auto tab_label = std::to_string(i); + if (ImGui::BeginTabItem(tab_label.c_str(), nullptr, ImGuiTabItemFlags_None)) { + if (ImGui::BeginTable(("table_" + tab_label).c_str(), 2, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableColumnFlags_NoResize, + ImVec2(0.0f, 0.0f))) { + ImGui::TableSetupColumn(("column_" + tab_label).c_str(), ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("LastCPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].lcput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("AverageCPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].acput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("NumCPUSamples"); + ImGui::TableNextColumn(); + ImGui::Text("%i", this->profiling[i].ncpus); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("LastGPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].lgput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("AverageGPUTime"); + ImGui::TableNextColumn(); + ImGui::Text("%f", this->profiling[i].agput); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("NumGPUSamples"); + ImGui::TableNextColumn(); + ImGui::Text("%i", this->profiling[i].ngpus); + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } + } + ImGui::EndTabBar(); + + ImGui::EndChild(); +} + +#endif // PROFILING diff --git a/plugins/gui/src/graph/Call.h b/plugins/gui/src/graph/Call.h index 78b02e3f09..945602b073 100644 --- a/plugins/gui/src/graph/Call.h +++ b/plugins/gui/src/graph/Call.h @@ -106,8 +106,11 @@ namespace gui { #ifdef PROFILING std::vector profiling; + bool show_profiling_data; + void draw_profiling_data(); #endif // PROFILING + }; diff --git a/plugins/gui/src/graph/GraphCollection.cpp b/plugins/gui/src/graph/GraphCollection.cpp index ba91f01090..750fbeb9b7 100644 --- a/plugins/gui/src/graph/GraphCollection.cpp +++ b/plugins/gui/src/graph/GraphCollection.cpp @@ -515,10 +515,12 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( std::string from; std::string to; ImGuiID uid = GUI_INVALID_ID; + std::weak_ptr ptr; }; std::vector gui_graph_call_info; for (auto& call_ptr : graph_ptr->Calls()) { CallInfo call_info; + call_info.ptr = call_ptr; call_info.class_name = call_ptr->ClassName(); call_info.uid = call_ptr->UID(); bool valid_callslot = false; @@ -602,6 +604,7 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( // REMOVE deleted calls from GUI graph ------------------------------------------ for (auto& call_info : gui_graph_call_info) { if (!megamol_graph.FindCall(call_info.from, call_info.to)) { + call_info.ptr.reset(); graph_ptr->DeleteCall(call_info.uid); gui_graph_changed = true; } @@ -639,8 +642,10 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( // Sync profiling values from core calls to gui calls ... for (auto& ccall : megamol_graph.ListCalls()) { - for (auto& gcall : graph_ptr->Calls()) { - if (gcall->ClassName() == ccall.request.className) { + for (auto& gcall : gui_graph_call_info) { + if (gcall.class_name == ccall.request.className && + gui_utils::CaseInsensitiveStringCompare(gcall.from, ccall.request.from) && + gui_utils::CaseInsensitiveStringCompare(gcall.to, ccall.request.to)) { auto func_count = ccall.callPtr->GetFuncCount(); std::vector prof; prof.resize(func_count); @@ -652,7 +657,7 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( prof[i].agput = ccall.callPtr->GetAverageGPUTime(i); prof[i].ngpus = ccall.callPtr->GetNumGPUSamples(i); } - gcall->SetProfilingValues(prof); + gcall.ptr.lock()->SetProfilingValues(prof); } } } From 5fa5e47ea4b28fa58889895e749d3de3ee42a1be Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 30 Jul 2021 17:31:41 +0200 Subject: [PATCH 09/47] operator precedence... --- core/src/Call.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/Call.cpp b/core/src/Call.cpp index dbfb00ae83..26982cf616 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -112,7 +112,9 @@ bool Call::operator()(unsigned int func) { #ifdef PROFILING const std::clock_t c_end = std::clock(); last_cpu_time[func] = 1000.0 * (static_cast(c_end-c_start) / CLOCKS_PER_SEC); - avg_cpu_time[func] = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]) / (++num_cpu_time_samples[func]); + const auto total = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]); + num_cpu_time_samples[func]++; + avg_cpu_time[func] = total / static_cast(num_cpu_time_samples[func]); if (gl_1 || gl_2) { //GLuint64 time; //auto& q = queries[query_read_buffer][func]; From 106ae26ad9a1dda3c4fedce1fc833e197d0fc234 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 30 Jul 2021 18:49:59 +0200 Subject: [PATCH 10/47] profiling info fine tuning --- plugins/gui/src/graph/Call.cpp | 21 +++++++++++---------- plugins/gui/src/graph/Call.h | 1 - 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/gui/src/graph/Call.cpp b/plugins/gui/src/graph/Call.cpp index 8d053b7d04..6fa65b7a2b 100644 --- a/plugins/gui/src/graph/Call.cpp +++ b/plugins/gui/src/graph/Call.cpp @@ -237,8 +237,8 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr ImVec2(call_center.x - (rect_size.x / 2.0f), call_center.y - (rect_size.y / 2.0f)); #ifdef PROFILING if (this->show_profiling_data) { - rect_size = ImVec2((ImGui::GetFrameHeight() * 10.0f + style.ItemSpacing.x * 2.0f), - (ImGui::GetFrameHeight() * 9.0f + style.ItemSpacing.x)); + rect_size = ImVec2((ImGui::GetFrameHeight() * 12.0f + style.ItemSpacing.x * 2.0f), + (ImGui::GetFrameHeight() * 9.5f + style.ItemSpacing.x)); } #endif ImVec2 call_rect_max = ImVec2((call_rect_min.x + rect_size.x), (call_rect_min.y + rect_size.y)); @@ -401,10 +401,11 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr void megamol::gui::Call::draw_profiling_data() { - const float width = ImGui::GetFrameHeight() * 10.0f; - const float height = ImGui::GetFrameHeight() * 8.0f; + const float width = ImGui::GetFrameHeight() * 12.0f; + const float height = ImGui::GetFrameHeight() * 8.5f; - ImGui::BeginChild("call_profiling_info", ImVec2(width, height), false, ImGuiWindowFlags_NoMove); + ImGui::BeginChild("call_profiling_info", ImVec2(width, height), false, + ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoMove); ImGui::TextUnformatted("Profiling"); ImGui::SameLine(); @@ -422,12 +423,12 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::TableNextColumn(); ImGui::TextUnformatted("LastCPUTime"); ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].lcput); + ImGui::Text("%.12f", this->profiling[i].lcput); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted("AverageCPUTime"); ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].acput); + ImGui::Text("%.12f", this->profiling[i].acput); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted("NumCPUSamples"); @@ -437,17 +438,17 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::TableNextColumn(); ImGui::TextUnformatted("LastGPUTime"); ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].lgput); + ImGui::Text("%.12f", this->profiling[i].lgput); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted("AverageGPUTime"); ImGui::TableNextColumn(); - ImGui::Text("%f", this->profiling[i].agput); + ImGui::Text("%.12f", this->profiling[i].agput); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted("NumGPUSamples"); ImGui::TableNextColumn(); - ImGui::Text("%i", this->profiling[i].ngpus); + ImGui::Text("%.12i", this->profiling[i].ngpus); ImGui::EndTable(); } ImGui::EndTabItem(); diff --git a/plugins/gui/src/graph/Call.h b/plugins/gui/src/graph/Call.h index 945602b073..c99b37dcb9 100644 --- a/plugins/gui/src/graph/Call.h +++ b/plugins/gui/src/graph/Call.h @@ -110,7 +110,6 @@ namespace gui { void draw_profiling_data(); #endif // PROFILING - }; From 5528b6927fedad279b599a08d80c2f6870445f71 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 3 Aug 2021 12:32:59 +0200 Subject: [PATCH 11/47] cheaper and less weird at runtime - less dynamic querying - keep track of callback names --- core/include/mmcore/Call.h | 24 +++++++++++++++++++++++ core/src/Call.cpp | 16 ++------------- core/src/MegaMolGraph.cpp | 15 ++++++++++++++ plugins/gui/src/graph/Call.cpp | 4 ++-- plugins/gui/src/graph/Call.h | 1 + plugins/gui/src/graph/GraphCollection.cpp | 1 + 6 files changed, 45 insertions(+), 16 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index c592ba8f27..9044dbb9df 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -15,6 +15,8 @@ #ifdef PROFILING #include #include +#include +#include #endif #include "mmcore/api/MegaMolCore.std.h" @@ -143,6 +145,13 @@ namespace core { /// avg_gpu_time.size() == num_gpu_time_samples.size()); return static_cast(last_cpu_time.size()); } + inline std::string GetFuncName(uint32_t i) const { + if (i < last_cpu_time.size()) { + return callback_names[i]; + } else { + return "out of bounds"; + } + } #endif private: @@ -159,6 +168,18 @@ namespace core { unsigned int *funcMap; #ifdef PROFILING + friend class MegaMolGraph; + void setProfilingInfo(std::vector names, bool usesGL) { + callback_names = std::move(names); + last_cpu_time.resize(callback_names.size()); + avg_cpu_time.resize(callback_names.size()); + num_cpu_time_samples.resize(callback_names.size()); + last_gpu_time.resize(callback_names.size()); + avg_gpu_time.resize(callback_names.size()); + num_gpu_time_samples.resize(callback_names.size()); + uses_gl = true; + } + std::vector last_cpu_time; std::vector avg_cpu_time; std::vector num_cpu_time_samples; @@ -166,6 +187,8 @@ namespace core { std::vector last_gpu_time; std::vector avg_gpu_time; std::vector num_gpu_time_samples; + std::vector callback_names; + bool uses_gl = false; class my_query_id { public: @@ -188,6 +211,7 @@ namespace core { std::array, 2> queries; uint32_t query_start_buffer = 1; uint32_t query_read_buffer = 0; + static std::map glCalls; #endif PROFILING }; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 26982cf616..068280864b 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -85,20 +85,8 @@ bool Call::operator()(unsigned int func) { } #endif #ifdef PROFILING - const auto f = this->callee->GetCallbackFuncName(func); - const auto parent = this->callee->Parent().get(); - const auto gl_1 = dynamic_cast(parent); - const auto gl_2 = dynamic_cast(parent); const std::clock_t c_start = std::clock(); - const auto paranoid_size = std::max(static_cast(last_cpu_time.size()), func + 1); - last_cpu_time.resize(paranoid_size, 0.0); - avg_cpu_time.resize(paranoid_size, 0.0); - num_cpu_time_samples.resize(paranoid_size, 0); - last_gpu_time.resize(paranoid_size, 0.0); - avg_gpu_time.resize(paranoid_size, 0.0); - num_gpu_time_samples.resize(paranoid_size, 0); - - if (gl_1 || gl_2) { + if (uses_gl) { // you can only have one query per target in flight. no idea what to do really. //queries[query_start_buffer].resize(paranoid_size); @@ -115,7 +103,7 @@ bool Call::operator()(unsigned int func) { const auto total = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]); num_cpu_time_samples[func]++; avg_cpu_time[func] = total / static_cast(num_cpu_time_samples[func]); - if (gl_1 || gl_2) { + if (uses_gl) { //GLuint64 time; //auto& q = queries[query_read_buffer][func]; //if (q.Started()) { diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index 3cd4a3db42..a5cfced960 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -12,6 +12,10 @@ #include #include // std::accumulate +// TODO if GL enabled +#include "mmcore/view/Renderer2DModule.h" +#include "mmcore/view/Renderer3DModuleGL.h" + // splits a string of the form "::one::two::three::" into an array of strings {"one", "two", "three"} static std::vector splitPathName(std::string const& path) { std::vector result; @@ -358,6 +362,17 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req return false; } +#ifdef PROFILING + std::vector callbacks(call_description->FunctionCount()); + for (uint32_t x = 0; x < call_description->FunctionCount(); ++x) { + callbacks[x] = call_description->FunctionName(x); + } + // TODO if gl enabled, else both vars = false + const auto gl_1 = dynamic_cast(to_slot.second.get()); + const auto gl_2 = dynamic_cast(to_slot.second.get()); + call->setProfilingInfo(callbacks, gl_1 || gl_2); +#endif + log("create call: " + request.from + " -> " + request.to + " (" + std::string(call_description->ClassName()) + ")"); this->call_list_.emplace_front(CallInstance_t{call, request}); diff --git a/plugins/gui/src/graph/Call.cpp b/plugins/gui/src/graph/Call.cpp index 6fa65b7a2b..4aec416d17 100644 --- a/plugins/gui/src/graph/Call.cpp +++ b/plugins/gui/src/graph/Call.cpp @@ -410,10 +410,10 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::TextUnformatted("Profiling"); ImGui::SameLine(); ImGui::TextDisabled("[Callback #:]"); - ImGui::BeginTabBar("profiling", ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::BeginTabBar("profiling", ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_FittingPolicyScroll); auto func_cnt = this->profiling.size(); for (size_t i = 0; i < func_cnt; i++) { - auto tab_label = std::to_string(i); + auto& tab_label = this->profiling[i].name; if (ImGui::BeginTabItem(tab_label.c_str(), nullptr, ImGuiTabItemFlags_None)) { if (ImGui::BeginTable(("table_" + tab_label).c_str(), 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableColumnFlags_NoResize, diff --git a/plugins/gui/src/graph/Call.h b/plugins/gui/src/graph/Call.h index c99b37dcb9..8467e3bc4f 100644 --- a/plugins/gui/src/graph/Call.h +++ b/plugins/gui/src/graph/Call.h @@ -77,6 +77,7 @@ namespace gui { double lgput; double agput; uint32_t ngpus; + std::string name; }; void SetProfilingValues(const std::vector& p) { diff --git a/plugins/gui/src/graph/GraphCollection.cpp b/plugins/gui/src/graph/GraphCollection.cpp index 750fbeb9b7..094222b3ac 100644 --- a/plugins/gui/src/graph/GraphCollection.cpp +++ b/plugins/gui/src/graph/GraphCollection.cpp @@ -656,6 +656,7 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( prof[i].lgput = ccall.callPtr->GetLastGPUTime(i); prof[i].agput = ccall.callPtr->GetAverageGPUTime(i); prof[i].ngpus = ccall.callPtr->GetNumGPUSamples(i); + prof[i].name = ccall.callPtr->GetFuncName(i); } gcall.ptr.lock()->SetProfilingValues(prof); } From 79f46cd3c984590dff7f2ca98b61bb4fff6088a4 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Tue, 3 Aug 2021 15:30:53 +0200 Subject: [PATCH 12/47] minor changes in gui call for profiling --- plugins/gui/src/graph/Call.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/plugins/gui/src/graph/Call.cpp b/plugins/gui/src/graph/Call.cpp index 4aec416d17..b9413aea87 100644 --- a/plugins/gui/src/graph/Call.cpp +++ b/plugins/gui/src/graph/Call.cpp @@ -10,6 +10,10 @@ #include "InterfaceSlot.h" #include "Module.h" +#ifdef PROFILING +#define PROFILING_CHILD_WIDTH (12.0f) +#define PROFILING_CHILD_HEIGHT (8.5f) +#endif using namespace megamol; using namespace megamol::gui; @@ -237,8 +241,9 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr ImVec2(call_center.x - (rect_size.x / 2.0f), call_center.y - (rect_size.y / 2.0f)); #ifdef PROFILING if (this->show_profiling_data) { - rect_size = ImVec2((ImGui::GetFrameHeight() * 12.0f + style.ItemSpacing.x * 2.0f), - (ImGui::GetFrameHeight() * 9.5f + style.ItemSpacing.x)); + rect_size = + ImVec2(((ImGui::GetFrameHeight() * PROFILING_CHILD_WIDTH) + style.ItemSpacing.x * 2.0f), + (ImGui::GetFrameHeight() * (PROFILING_CHILD_HEIGHT + 1.0f) + style.ItemSpacing.x)); } #endif ImVec2 call_rect_max = ImVec2((call_rect_min.x + rect_size.x), (call_rect_min.y + rect_size.y)); @@ -401,15 +406,13 @@ void megamol::gui::Call::Draw(megamol::gui::PresentPhase phase, megamol::gui::Gr void megamol::gui::Call::draw_profiling_data() { - const float width = ImGui::GetFrameHeight() * 12.0f; - const float height = ImGui::GetFrameHeight() * 8.5f; - - ImGui::BeginChild("call_profiling_info", ImVec2(width, height), false, - ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoMove); + ImGui::BeginChild("call_profiling_info", + ImVec2((ImGui ::GetFrameHeight() * PROFILING_CHILD_WIDTH), (ImGui::GetFrameHeight() * PROFILING_CHILD_HEIGHT)), + false, ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoMove); ImGui::TextUnformatted("Profiling"); ImGui::SameLine(); - ImGui::TextDisabled("[Callback #:]"); + ImGui::TextDisabled("[Callback Name]"); ImGui::BeginTabBar("profiling", ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_FittingPolicyScroll); auto func_cnt = this->profiling.size(); for (size_t i = 0; i < func_cnt; i++) { From 23eded00a49eee9d3218f659af30e074fee973c0 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 3 Aug 2021 20:01:35 +0200 Subject: [PATCH 13/47] fixed program flow a bit - query is probably best fetched before it is used again - TODO: still need double-buffering - lazy init of my_query_id internal class is so bad. --- core/include/mmcore/Call.h | 43 ++++++++++++++++--- core/src/Call.cpp | 36 +++++++--------- core/src/MegaMolGraph.cpp | 3 ++ .../opengl_glfw/OpenGL_GLFW_Service.cpp | 22 ++++++++++ 4 files changed, 79 insertions(+), 25 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 9044dbb9df..45e7ce5b06 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -17,11 +17,15 @@ #include #include #include +namespace megamol { +namespace frontend { + class OpenGL_GLFW_Service; +} +} #endif #include "mmcore/api/MegaMolCore.std.h" - namespace megamol { namespace core { @@ -169,6 +173,8 @@ namespace core { #ifdef PROFILING friend class MegaMolGraph; + friend class megamol::frontend::OpenGL_GLFW_Service; + void setProfilingInfo(std::vector names, bool usesGL) { callback_names = std::move(names); last_cpu_time.resize(callback_names.size()); @@ -178,6 +184,24 @@ namespace core { avg_gpu_time.resize(callback_names.size()); num_gpu_time_samples.resize(callback_names.size()); uses_gl = true; + all_calls.push_back(this); + resetGLProfiling(); + } + static void resetGLProfiling() { + if (!all_calls.empty()) { + starting_call = 0; + starting_func = 0; + } else { + starting_call = -1; + starting_func = -1; + } + } + static void advanceGLProfiling() { + starting_func = (starting_func + 1) % all_calls[starting_call]->GetFuncCount(); + if (starting_func == 0) { + // we wrapped, advance to next call! + starting_call = (starting_call + 1) % all_calls.size(); + } } std::vector last_cpu_time; @@ -204,14 +228,23 @@ namespace core { void Start() { started = true; } + void Stop() { + started = false; + } private: uint32_t the_id = 0; bool started = false; }; - std::array, 2> queries; - uint32_t query_start_buffer = 1; - uint32_t query_read_buffer = 0; - static std::map glCalls; + + // todo these are so slow, we need double buffering all the same. best wrap starting_call and func inside the query and vary across the current frame + + // there is only one query. it needs to be fetched and the result assigned + // to starting_call at the end of the frame. + static my_query_id *query; + // who can use the query this frame? + static std::vector all_calls; + static int32_t starting_call, starting_func; + #endif PROFILING }; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 068280864b..c0fd504f56 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -25,6 +25,11 @@ using namespace megamol::core; +std::vector Call::all_calls; +int32_t Call::starting_call = -1; +int32_t Call::starting_func = -1; +Call::my_query_id *Call::query = nullptr; + /* * Call::Call */ @@ -48,6 +53,8 @@ Call::~Call(void) { } megamol::core::utility::log::Log::DefaultLog.WriteMsg(megamol::core::utility::log::Log::LEVEL_INFO + 350, "destructed call \"%s\"\n", typeid(*this).name()); ARY_SAFE_DELETE(this->funcMap); + all_calls.erase(std::remove(all_calls.begin(), all_calls.end(), this)); + resetGLProfiling(); } @@ -87,35 +94,24 @@ bool Call::operator()(unsigned int func) { #ifdef PROFILING const std::clock_t c_start = std::clock(); if (uses_gl) { - // you can only have one query per target in flight. no idea what to do really. - - //queries[query_start_buffer].resize(paranoid_size); - //queries[query_read_buffer].resize(paranoid_size); - //auto& q = queries[query_start_buffer][func]; - //glBeginQuery(GL_TIME_ELAPSED, q.Get()); - //q.Start(); + if (this == all_calls[starting_call] && func == starting_func) { + glBeginQuery(GL_TIME_ELAPSED, query->Get()); + query->Start(); + } } #endif res = this->callee->InCall(this->funcMap[func], *this); #ifdef PROFILING + if (uses_gl) { + if (this == all_calls[starting_call] && func == starting_func) { + glEndQuery(GL_TIME_ELAPSED); + } + } const std::clock_t c_end = std::clock(); last_cpu_time[func] = 1000.0 * (static_cast(c_end-c_start) / CLOCKS_PER_SEC); const auto total = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]); num_cpu_time_samples[func]++; avg_cpu_time[func] = total / static_cast(num_cpu_time_samples[func]); - if (uses_gl) { - //GLuint64 time; - //auto& q = queries[query_read_buffer][func]; - //if (q.Started()) { - // int done = 0; - // glGetQueryObjectiv(q.Get(), GL_QUERY_RESULT_AVAILABLE, &done); - // ASSERT(done); - // glGetQueryObjectui64v(q.Get(), GL_QUERY_RESULT, &time); - // last_gpu_time[func] = static_cast(time / 1000000.0); - // avg_gpu_time[func] = (avg_gpu_time[func] * num_gpu_time_samples[func] + last_gpu_time[func]) / ++num_gpu_time_samples[func]; - //} - //std::swap(query_start_buffer, query_read_buffer); - } #endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS if (p2 || p3 || p3_2) glPopDebugGroup(); diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index a5cfced960..3655b41605 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -370,6 +370,9 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req // TODO if gl enabled, else both vars = false const auto gl_1 = dynamic_cast(to_slot.second.get()); const auto gl_2 = dynamic_cast(to_slot.second.get()); + if ((gl_1 || gl_2) && core::Call::query == nullptr) { + core::Call::query = new core::Call::my_query_id(); + } call->setProfilingInfo(callbacks, gl_1 || gl_2); #endif diff --git a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp index d37ccbfb02..fc6cf8818c 100644 --- a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp +++ b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp @@ -37,6 +37,10 @@ #include #include +#ifdef PROFILING +#include +#include "mmcore/Call.h" +#endif #include "mmcore/utility/log/Log.h" static const std::string service_name = "OpenGL_GLFW_Service: "; @@ -782,6 +786,24 @@ void OpenGL_GLFW_Service::postGraphRender() { ::glfwSwapBuffers(m_pimpl->glfwContextWindowPtr); +#ifdef PROFILING + GLuint64 time; + auto q = core::Call::query; + if (q->Started()) { + int done = 0; + glGetQueryObjectiv(q->Get(), GL_QUERY_RESULT_AVAILABLE, &done); + assert(done); + glGetQueryObjectui64v(q->Get(), GL_QUERY_RESULT, &time); + q->Stop(); + auto& c = core::Call::all_calls[core::Call::starting_call]; + c->last_gpu_time[core::Call::starting_func] = static_cast(time / 1000000.0); + const auto total = c->avg_gpu_time[core::Call::starting_func] * c->num_gpu_time_samples[core::Call::starting_func] + c->last_gpu_time[core::Call::starting_func]; + c->num_gpu_time_samples[core::Call::starting_func]++; + c->avg_gpu_time[core::Call::starting_func] = total / c->num_gpu_time_samples[core::Call::starting_func]; + } + core::Call::advanceGLProfiling(); // important! regardless of whether the last call was actually profiled! +#endif + //::glfwMakeContextCurrent(window_ptr); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT); //::glfwMakeContextCurrent(nullptr); From 5278a6a90b989706760c08ca226e8492e16d72ae Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Wed, 4 Aug 2021 10:31:06 +0200 Subject: [PATCH 14/47] compile fix for disabled profiling --- core/src/Call.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/Call.cpp b/core/src/Call.cpp index c0fd504f56..fabf94ab09 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -25,10 +25,12 @@ using namespace megamol::core; +#ifdef PROFILING std::vector Call::all_calls; int32_t Call::starting_call = -1; int32_t Call::starting_func = -1; Call::my_query_id *Call::query = nullptr; +#endif /* * Call::Call @@ -53,8 +55,10 @@ Call::~Call(void) { } megamol::core::utility::log::Log::DefaultLog.WriteMsg(megamol::core::utility::log::Log::LEVEL_INFO + 350, "destructed call \"%s\"\n", typeid(*this).name()); ARY_SAFE_DELETE(this->funcMap); +#ifdef PROFILING all_calls.erase(std::remove(all_calls.begin(), all_calls.end(), this)); resetGLProfiling(); +#endif } From d1c78447cf937d6a68aa0734ad8dc2f9a901ad72 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 4 Aug 2021 13:07:50 +0200 Subject: [PATCH 15/47] moved implementation to PerformanceQueryManager - still exlodes though. --- core/include/mmcore/Call.h | 64 +++---------- core/include/mmcore/PerformanceQueryManager.h | 45 +++++++++ core/src/Call.cpp | 34 ++----- core/src/MegaMolGraph.cpp | 4 +- core/src/PerformanceQueryManager.cpp | 95 +++++++++++++++++++ .../opengl_glfw/OpenGL_GLFW_Service.cpp | 16 +--- 6 files changed, 164 insertions(+), 94 deletions(-) create mode 100644 core/include/mmcore/PerformanceQueryManager.h create mode 100644 core/src/PerformanceQueryManager.cpp diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 45e7ce5b06..e1c98a1269 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -17,11 +17,7 @@ #include #include #include -namespace megamol { -namespace frontend { - class OpenGL_GLFW_Service; -} -} +#include "PerformanceQueryManager.h" #endif #include "mmcore/api/MegaMolCore.std.h" @@ -156,6 +152,14 @@ namespace core { return "out of bounds"; } } + static void InitializeQueryManager() { + if (qm == nullptr) { + qm = new PerformanceQueryManager(); + } + } + static void CollectGPUPerformance() { + qm->Collect(); + } #endif private: @@ -173,7 +177,7 @@ namespace core { #ifdef PROFILING friend class MegaMolGraph; - friend class megamol::frontend::OpenGL_GLFW_Service; + friend class PerformanceQueryManager; void setProfilingInfo(std::vector names, bool usesGL) { callback_names = std::move(names); @@ -183,24 +187,9 @@ namespace core { last_gpu_time.resize(callback_names.size()); avg_gpu_time.resize(callback_names.size()); num_gpu_time_samples.resize(callback_names.size()); - uses_gl = true; - all_calls.push_back(this); - resetGLProfiling(); - } - static void resetGLProfiling() { - if (!all_calls.empty()) { - starting_call = 0; - starting_func = 0; - } else { - starting_call = -1; - starting_func = -1; - } - } - static void advanceGLProfiling() { - starting_func = (starting_func + 1) % all_calls[starting_call]->GetFuncCount(); - if (starting_func == 0) { - // we wrapped, advance to next call! - starting_call = (starting_call + 1) % all_calls.size(); + uses_gl = usesGL; + if (usesGL) { + qm->AddCall(this); } } @@ -214,37 +203,12 @@ namespace core { std::vector callback_names; bool uses_gl = false; - class my_query_id { - public: - my_query_id(); - ~my_query_id(); - my_query_id(const my_query_id&); - uint32_t Get() const { - return the_id; - } - bool Started() const { - return started; - } - void Start() { - started = true; - } - void Stop() { - started = false; - } - private: - uint32_t the_id = 0; - bool started = false; - }; - // todo these are so slow, we need double buffering all the same. best wrap starting_call and func inside the query and vary across the current frame // there is only one query. it needs to be fetched and the result assigned // to starting_call at the end of the frame. - static my_query_id *query; + static PerformanceQueryManager *qm; // who can use the query this frame? - static std::vector all_calls; - static int32_t starting_call, starting_func; - #endif PROFILING }; diff --git a/core/include/mmcore/PerformanceQueryManager.h b/core/include/mmcore/PerformanceQueryManager.h new file mode 100644 index 0000000000..7ba1d93fb6 --- /dev/null +++ b/core/include/mmcore/PerformanceQueryManager.h @@ -0,0 +1,45 @@ +#pragma once + +#ifdef PROFILING +#include +#include + +namespace megamol { +namespace core { +class Call; + +class PerformanceQueryManager { +public: + PerformanceQueryManager(); + ~PerformanceQueryManager(); + PerformanceQueryManager(const PerformanceQueryManager&); + + bool Start(megamol::core::Call *c, uint32_t frameId, int32_t funcIdx); + void Stop(uint32_t frameId); + void Collect(); + + void AddCall(megamol::core::Call *c); + void RemoveCall(megamol::core::Call *c); + + void ResetGLProfiling(); + void AdvanceGLProfiling(); + +private: + struct query_info { + uint32_t id = 0; + bool started = false; + int32_t call_idx = -1; + int32_t func_idx = -1; + + }; + std::array query_infos; + std::vector all_calls; + int32_t starting_call = -1, starting_func = -1; + + uint32_t next_query = 0; +}; + +#endif + +} // namespace core +} // namespace megamol diff --git a/core/src/Call.cpp b/core/src/Call.cpp index c0fd504f56..457b2657cb 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -19,16 +19,14 @@ #ifdef PROFILING # include "mmcore/view/Renderer3DModuleGL.h" # include "mmcore/view/Renderer2DModule.h" +#include "mmcore/CoreInstance.h" # include #endif #include "mmcore/utility/log/Log.h" using namespace megamol::core; -std::vector Call::all_calls; -int32_t Call::starting_call = -1; -int32_t Call::starting_func = -1; -Call::my_query_id *Call::query = nullptr; +PerformanceQueryManager *Call::qm = nullptr; /* * Call::Call @@ -53,24 +51,10 @@ Call::~Call(void) { } megamol::core::utility::log::Log::DefaultLog.WriteMsg(megamol::core::utility::log::Log::LEVEL_INFO + 350, "destructed call \"%s\"\n", typeid(*this).name()); ARY_SAFE_DELETE(this->funcMap); - all_calls.erase(std::remove(all_calls.begin(), all_calls.end(), this)); - resetGLProfiling(); + qm->RemoveCall(this); } -#ifdef PROFILING -Call::my_query_id::my_query_id() { - glGenQueries(1, &the_id); -} -Call::my_query_id::~my_query_id() { - glDeleteQueries(1, &the_id); -} -Call::my_query_id::my_query_id(const my_query_id&) { - glGenQueries(1, &the_id); -} -#endif - - /* * Call::operator() */ @@ -93,19 +77,15 @@ bool Call::operator()(unsigned int func) { #endif #ifdef PROFILING const std::clock_t c_start = std::clock(); + bool gl_started = false; if (uses_gl) { - if (this == all_calls[starting_call] && func == starting_func) { - glBeginQuery(GL_TIME_ELAPSED, query->Get()); - query->Start(); - } + gl_started = qm->Start(this, this->callee->GetCoreInstance()->GetFrameID(), func); } #endif res = this->callee->InCall(this->funcMap[func], *this); #ifdef PROFILING - if (uses_gl) { - if (this == all_calls[starting_call] && func == starting_func) { - glEndQuery(GL_TIME_ELAPSED); - } + if (gl_started) { + qm->Stop(this->callee->GetCoreInstance()->GetFrameID()); } const std::clock_t c_end = std::clock(); last_cpu_time[func] = 1000.0 * (static_cast(c_end-c_start) / CLOCKS_PER_SEC); diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index 3655b41605..9b75357305 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -370,8 +370,8 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req // TODO if gl enabled, else both vars = false const auto gl_1 = dynamic_cast(to_slot.second.get()); const auto gl_2 = dynamic_cast(to_slot.second.get()); - if ((gl_1 || gl_2) && core::Call::query == nullptr) { - core::Call::query = new core::Call::my_query_id(); + if ((gl_1 || gl_2)) { + core::Call::InitializeQueryManager(); } call->setProfilingInfo(callbacks, gl_1 || gl_2); #endif diff --git a/core/src/PerformanceQueryManager.cpp b/core/src/PerformanceQueryManager.cpp new file mode 100644 index 0000000000..1075ce3083 --- /dev/null +++ b/core/src/PerformanceQueryManager.cpp @@ -0,0 +1,95 @@ +#ifdef PROFILING +#include +#include +#include "mmcore/Call.h" +#include "mmcore/PerformanceQueryManager.h" +#include "vislib/graphics/gl/IncludeAllGL.h" + +using namespace megamol::core; + +PerformanceQueryManager::PerformanceQueryManager() { + glGenQueries(1, &query_infos[0].id); + glGenQueries(1, &query_infos[1].id); +} +PerformanceQueryManager::~PerformanceQueryManager() { + glDeleteQueries(1, &query_infos[0].id); + glDeleteQueries(1, &query_infos[1].id); +} +PerformanceQueryManager::PerformanceQueryManager(const PerformanceQueryManager&) { + glGenQueries(1, &query_infos[0].id); + glGenQueries(1, &query_infos[1].id); +} + +void PerformanceQueryManager::AddCall(megamol::core::Call* c) { + all_calls.push_back(c); + ResetGLProfiling(); +} + +void PerformanceQueryManager::RemoveCall(megamol::core::Call* c) { + all_calls.erase(std::remove(all_calls.begin(), all_calls.end(), c)); + ResetGLProfiling(); +} + +void PerformanceQueryManager::ResetGLProfiling() { + if (!all_calls.empty()) { + starting_call = 0; + starting_func = 0; + } else { + starting_call = -1; + starting_func = -1; + } +} + +void PerformanceQueryManager::AdvanceGLProfiling() { + starting_func = (starting_func + 1) % all_calls[starting_call]->GetFuncCount(); + if (starting_func == 0) { + // we wrapped, advance to next call! + starting_call = (starting_call + 1) % all_calls.size(); + } +} + + +bool PerformanceQueryManager::Start(Call* c, uint32_t frameId, int32_t funcIdx) { + const auto idx = next_query; + if (c == all_calls[starting_call] && funcIdx == starting_func && !query_infos[idx].started) { + glBeginQuery(GL_TIME_ELAPSED, query_infos[idx].id); + query_infos[idx].started = true; + query_infos[idx].call_idx = starting_call; + query_infos[idx].func_idx = starting_func; + next_query = (next_query + 1) % 2; + } + return query_infos[idx].started; +} + +void PerformanceQueryManager::Stop(uint32_t frameId) { + glEndQuery(GL_TIME_ELAPSED); +} + +void PerformanceQueryManager::Collect() { + // collect next query because that is what will be used next frame and needs to be freed up! + const uint32_t the_query = next_query; + auto& qi = query_infos[the_query]; + if (qi.started) { + int done = 0; + GLuint64 time; + const auto oid = qi.id; + glGetQueryObjectiv(oid, GL_QUERY_RESULT_AVAILABLE, &done); + if (!done) { + assert(done); + } + glGetQueryObjectui64v(oid, GL_QUERY_RESULT, &time); + const auto the_func = qi.func_idx; + const auto the_call = qi.call_idx; + qi.started = false; + auto c = all_calls[the_call]; + c->last_gpu_time[the_func] = static_cast(time / 1000000.0); + const auto total = c->avg_gpu_time[the_func] * c->num_gpu_time_samples[the_func] + c->last_gpu_time[the_func]; + c->num_gpu_time_samples[the_func]++; + c->avg_gpu_time[the_func] = total / c->num_gpu_time_samples[the_func]; + } + AdvanceGLProfiling(); // important! regardless of whether the last call was actually profiled! +} + + +#endif + diff --git a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp index fc6cf8818c..9e2259e86e 100644 --- a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp +++ b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp @@ -787,21 +787,7 @@ void OpenGL_GLFW_Service::postGraphRender() { ::glfwSwapBuffers(m_pimpl->glfwContextWindowPtr); #ifdef PROFILING - GLuint64 time; - auto q = core::Call::query; - if (q->Started()) { - int done = 0; - glGetQueryObjectiv(q->Get(), GL_QUERY_RESULT_AVAILABLE, &done); - assert(done); - glGetQueryObjectui64v(q->Get(), GL_QUERY_RESULT, &time); - q->Stop(); - auto& c = core::Call::all_calls[core::Call::starting_call]; - c->last_gpu_time[core::Call::starting_func] = static_cast(time / 1000000.0); - const auto total = c->avg_gpu_time[core::Call::starting_func] * c->num_gpu_time_samples[core::Call::starting_func] + c->last_gpu_time[core::Call::starting_func]; - c->num_gpu_time_samples[core::Call::starting_func]++; - c->avg_gpu_time[core::Call::starting_func] = total / c->num_gpu_time_samples[core::Call::starting_func]; - } - core::Call::advanceGLProfiling(); // important! regardless of whether the last call was actually profiled! + core::Call::CollectGPUPerformance(); #endif //::glfwMakeContextCurrent(window_ptr); From db9792780dddba21c16a1e45b550bdd7bad3c1e2 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 4 Aug 2021 15:53:50 +0200 Subject: [PATCH 16/47] performance queries work - TODO: identifying calls by their pointer seems to be a bad idea --- core/include/mmcore/PerformanceQueryManager.h | 3 ++- core/src/Call.cpp | 6 ++--- core/src/PerformanceQueryManager.cpp | 25 ++++++++++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/core/include/mmcore/PerformanceQueryManager.h b/core/include/mmcore/PerformanceQueryManager.h index 7ba1d93fb6..b83421818f 100644 --- a/core/include/mmcore/PerformanceQueryManager.h +++ b/core/include/mmcore/PerformanceQueryManager.h @@ -36,7 +36,8 @@ class PerformanceQueryManager { std::vector all_calls; int32_t starting_call = -1, starting_func = -1; - uint32_t next_query = 0; + int32_t next_query = 0; + int32_t running_query = -1; }; #endif diff --git a/core/src/Call.cpp b/core/src/Call.cpp index f6bd35d386..ea3f5c9da6 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -42,6 +42,9 @@ Call::Call(void) : callee(nullptr), caller(nullptr), className(nullptr), funcMap * Call::~Call */ Call::~Call(void) { +#ifdef PROFILING + qm->RemoveCall(this); +#endif if (this->caller != nullptr) { CallerSlot* cr = this->caller; this->caller = nullptr; // DO NOT DELETE @@ -53,9 +56,6 @@ Call::~Call(void) { } megamol::core::utility::log::Log::DefaultLog.WriteMsg(megamol::core::utility::log::Log::LEVEL_INFO + 350, "destructed call \"%s\"\n", typeid(*this).name()); ARY_SAFE_DELETE(this->funcMap); -#ifdef PROFILING - qm->RemoveCall(this); -#endif } diff --git a/core/src/PerformanceQueryManager.cpp b/core/src/PerformanceQueryManager.cpp index 1075ce3083..cda344da5f 100644 --- a/core/src/PerformanceQueryManager.cpp +++ b/core/src/PerformanceQueryManager.cpp @@ -4,6 +4,7 @@ #include "mmcore/Call.h" #include "mmcore/PerformanceQueryManager.h" #include "vislib/graphics/gl/IncludeAllGL.h" +#include "mmcore/utility/log/Log.h" using namespace megamol::core; @@ -56,13 +57,22 @@ bool PerformanceQueryManager::Start(Call* c, uint32_t frameId, int32_t funcIdx) query_infos[idx].started = true; query_infos[idx].call_idx = starting_call; query_infos[idx].func_idx = starting_func; + running_query = idx; next_query = (next_query + 1) % 2; + //utility::log::Log::DefaultLog.WriteInfo("[PerfQueryMan] frame %u: started GL query for call %u, func %u in query %u", + // frameId, starting_call, starting_func, running_query); } return query_infos[idx].started; } void PerformanceQueryManager::Stop(uint32_t frameId) { - glEndQuery(GL_TIME_ELAPSED); + if (running_query > -1 && query_infos[running_query].started) { + auto& qi = query_infos[running_query]; + glEndQuery(GL_TIME_ELAPSED); + //utility::log::Log::DefaultLog.WriteInfo("[PerfQueryMan] frame %u: stopped GL query for call %u, func %u in query %u", + // frameId, qi.call_idx, qi.func_idx, running_query); + running_query = -1; + } } void PerformanceQueryManager::Collect() { @@ -70,13 +80,15 @@ void PerformanceQueryManager::Collect() { const uint32_t the_query = next_query; auto& qi = query_infos[the_query]; if (qi.started) { + //utility::log::Log::DefaultLog.WriteInfo("[PerfQueryMan] frame %u: collecting GL query for call %u, func %u in query %u", + // 0, qi.call_idx, qi.func_idx, the_query); int done = 0; GLuint64 time; const auto oid = qi.id; - glGetQueryObjectiv(oid, GL_QUERY_RESULT_AVAILABLE, &done); - if (!done) { - assert(done); - } + do { + // for some reason, one frame is not enough for the query to come back, so we really need to block. + glGetQueryObjectiv(oid, GL_QUERY_RESULT_AVAILABLE, &done); + } while (!done); glGetQueryObjectui64v(oid, GL_QUERY_RESULT, &time); const auto the_func = qi.func_idx; const auto the_call = qi.call_idx; @@ -87,7 +99,8 @@ void PerformanceQueryManager::Collect() { c->num_gpu_time_samples[the_func]++; c->avg_gpu_time[the_func] = total / c->num_gpu_time_samples[the_func]; } - AdvanceGLProfiling(); // important! regardless of whether the last call was actually profiled! + AdvanceGLProfiling(); // important! regardless of whether the last call was actually profiled! we need to advance + // through the graph though } From f4b23c37530272d87314d6470c2b1b86b11a6e92 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 4 Aug 2021 16:08:51 +0200 Subject: [PATCH 17/47] only remove gl calls --- core/src/Call.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/Call.cpp b/core/src/Call.cpp index ea3f5c9da6..c68aae001b 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -43,7 +43,9 @@ Call::Call(void) : callee(nullptr), caller(nullptr), className(nullptr), funcMap */ Call::~Call(void) { #ifdef PROFILING - qm->RemoveCall(this); + if (uses_gl) { + qm->RemoveCall(this); + } #endif if (this->caller != nullptr) { CallerSlot* cr = this->caller; From a947b88e6f100028647a11b3a50c146b3672098f Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 4 Aug 2021 16:21:32 +0200 Subject: [PATCH 18/47] cleanup --- core/include/mmcore/CalleeSlot.h | 1 - 1 file changed, 1 deletion(-) diff --git a/core/include/mmcore/CalleeSlot.h b/core/include/mmcore/CalleeSlot.h index 2801aff59d..952cd2e151 100644 --- a/core/include/mmcore/CalleeSlot.h +++ b/core/include/mmcore/CalleeSlot.h @@ -335,7 +335,6 @@ namespace core { virtual bool CallMe(Module *owner, Call& call) { C *c = dynamic_cast(owner); if (c == NULL) return false; - // TODO alternatively, profiling could be done here and data stored in the module? return (c->*func)(call); } From e6d75797448361dac776f6bd1c4ec086badeb35b Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 4 Aug 2021 16:42:21 +0200 Subject: [PATCH 19/47] use HPET instead --- core/src/Call.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/Call.cpp b/core/src/Call.cpp index c68aae001b..997f09d630 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -82,7 +82,7 @@ bool Call::operator()(unsigned int func) { } #endif #ifdef PROFILING - const std::clock_t c_start = std::clock(); + const auto startTime = std::chrono::high_resolution_clock::now(); bool gl_started = false; if (uses_gl) { gl_started = qm->Start(this, this->callee->GetCoreInstance()->GetFrameID(), func); @@ -93,8 +93,9 @@ bool Call::operator()(unsigned int func) { if (gl_started) { qm->Stop(this->callee->GetCoreInstance()->GetFrameID()); } - const std::clock_t c_end = std::clock(); - last_cpu_time[func] = 1000.0 * (static_cast(c_end-c_start) / CLOCKS_PER_SEC); + const auto endTime = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diffMillis = endTime - startTime; + last_cpu_time[func] = diffMillis.count(); const auto total = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]); num_cpu_time_samples[func]++; avg_cpu_time[func] = total / static_cast(num_cpu_time_samples[func]); From 8e47bf0abdc01ec464e5a0627d497891bf35062a Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 4 Aug 2021 17:19:53 +0200 Subject: [PATCH 20/47] lazy init guard --- core/include/mmcore/Call.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index e1c98a1269..083beefec8 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -158,7 +158,9 @@ namespace core { } } static void CollectGPUPerformance() { - qm->Collect(); + if (qm != nullptr) { + qm->Collect(); + } } #endif From f48085348025cc23a107613dede6e9026892e6ec Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 31 Aug 2021 19:16:06 +0200 Subject: [PATCH 21/47] performance averages and buffer refactored --- core/include/mmcore/Call.h | 31 ++++++----- core/include/mmcore/PerformanceHistory.h | 68 ++++++++++++++++++++++++ core/src/Call.cpp | 9 ++-- core/src/PerformanceHistory.cpp | 46 ++++++++++++++++ 4 files changed, 136 insertions(+), 18 deletions(-) create mode 100644 core/include/mmcore/PerformanceHistory.h create mode 100644 core/src/PerformanceHistory.cpp diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 083beefec8..85d8804938 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -18,6 +18,7 @@ #include #include #include "PerformanceQueryManager.h" +#include "PerformanceHistory.h" #endif #include "mmcore/api/MegaMolCore.std.h" @@ -104,20 +105,20 @@ namespace core { #ifdef PROFILING inline double GetLastCPUTime(uint32_t func) const { - if (func < last_cpu_time.size()) - return last_cpu_time[func]; + if (func < callback_names.size()) + return cpu_history[func].last_value(); else return -1.0; } inline double GetAverageCPUTime(uint32_t func) const { - if (func < avg_cpu_time.size()) - return avg_cpu_time[func]; + if (func < callback_names.size()) + return cpu_history[func].average(); else return -1.0; } inline uint32_t GetNumCPUSamples(uint32_t func) const { - if (func < num_cpu_time_samples.size()) - return num_cpu_time_samples[func]; + if (func < callback_names.size()) + return cpu_history[func].samples(); else return 0; } @@ -143,10 +144,10 @@ namespace core { inline uint32_t GetFuncCount() const { /// XXX assert(last_cpu_time.size() == avg_cpu_time.size() == num_cpu_time_samples.size() == last_gpu_time.size() == /// avg_gpu_time.size() == num_gpu_time_samples.size()); - return static_cast(last_cpu_time.size()); + return static_cast(callback_names.size()); } inline std::string GetFuncName(uint32_t i) const { - if (i < last_cpu_time.size()) { + if (i < callback_names.size()) { return callback_names[i]; } else { return "out of bounds"; @@ -183,9 +184,10 @@ namespace core { void setProfilingInfo(std::vector names, bool usesGL) { callback_names = std::move(names); - last_cpu_time.resize(callback_names.size()); - avg_cpu_time.resize(callback_names.size()); - num_cpu_time_samples.resize(callback_names.size()); + //last_cpu_time.resize(callback_names.size()); + //avg_cpu_time.resize(callback_names.size()); + //num_cpu_time_samples.resize(callback_names.size()); + cpu_history.resize(callback_names.size()); last_gpu_time.resize(callback_names.size()); avg_gpu_time.resize(callback_names.size()); num_gpu_time_samples.resize(callback_names.size()); @@ -195,9 +197,10 @@ namespace core { } } - std::vector last_cpu_time; - std::vector avg_cpu_time; - std::vector num_cpu_time_samples; + //std::vector last_cpu_time; + //std::vector avg_cpu_time; + //std::vector num_cpu_time_samples; + std::vector cpu_history; std::vector last_gpu_time; std::vector avg_gpu_time; diff --git a/core/include/mmcore/PerformanceHistory.h b/core/include/mmcore/PerformanceHistory.h new file mode 100644 index 0000000000..bc0422c2b0 --- /dev/null +++ b/core/include/mmcore/PerformanceHistory.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +namespace megamol { +namespace core { + +class PerformanceHistory { +public: + static constexpr uint32_t buffer_length = 100; + + PerformanceHistory(); + + void push_value(double val); + + void reset(); + + double operator[](int index) const; + + double last_value() const { + // do we want to treat the special case? + //if (num_samples > 0) { + // return time_buffer[last_index]; + //} else { + // return std::numeric_limits::infinity(); + //} + + // or just like this... + //return time_buffer[last_index]; + + // or even better + return time_buffer[offset(next_index, buffer_length - 1)]; + } + + double average() const { + return avg_time; + } + + double buffer_average() const { + return window_avg; + } + + uint32_t samples() const { + return num_samples; + } + +private: + static int offset(const int index, const int offset); + + static int next_wrap(const int index) { + return offset(index, 1); + } + static int prev_wrap(const int index) { + return offset(index, -1); + } + + std::array time_buffer{}; + int next_index = 0; + //int last_index = 0; + double avg_time = 0; + double window_total = 0; + double window_avg = 0; + uint32_t num_samples = 0; +}; + +} +} diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 997f09d630..1bbeca25b7 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -95,10 +95,11 @@ bool Call::operator()(unsigned int func) { } const auto endTime = std::chrono::high_resolution_clock::now(); const std::chrono::duration diffMillis = endTime - startTime; - last_cpu_time[func] = diffMillis.count(); - const auto total = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]); - num_cpu_time_samples[func]++; - avg_cpu_time[func] = total / static_cast(num_cpu_time_samples[func]); + cpu_history[func].push_value(diffMillis.count()); + //last_cpu_time[func] = diffMillis.count(); + //const auto total = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]); + //num_cpu_time_samples[func]++; + //avg_cpu_time[func] = total / static_cast(num_cpu_time_samples[func]); #endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS if (p2 || p3 || p3_2) glPopDebugGroup(); diff --git a/core/src/PerformanceHistory.cpp b/core/src/PerformanceHistory.cpp new file mode 100644 index 0000000000..5441613eb8 --- /dev/null +++ b/core/src/PerformanceHistory.cpp @@ -0,0 +1,46 @@ +#include "mmcore/PerformanceHistory.h" + +using namespace megamol::core; + +PerformanceHistory::PerformanceHistory() { + reset(); +} + +void PerformanceHistory::push_value(double val) { + + // general question: window_total might be prone to drift, but the average of many values + // every frame for many callbacks is much too expensive, isn't it? + + // remove the window sum component that is going to be overwritten + // array starts zeroed so unused samples do not change the result here + window_total -= time_buffer[next_index]; + window_total += val; + // until we have at least a sample everywhere, the average is over num_samples only + window_avg = window_total / std::min(buffer_length, num_samples); + + time_buffer[next_index] = val; + const auto total = avg_time * num_samples + val; + num_samples++; + avg_time = total / static_cast(num_samples); + //last_index = next_index; + next_index = next_wrap(next_index); +} + +void PerformanceHistory::reset() { + next_index = 0; + //last_index = 0; + time_buffer.fill(0.0); + num_samples = 0; + avg_time = 0; + window_total = 0; + window_avg = 0; +} + +double PerformanceHistory::operator[](int index) const { + return time_buffer[offset(next_index, index)]; +} + +int PerformanceHistory::offset(const int index, const int offset) { + auto o = offset % buffer_length; + return (index + offset + buffer_length) % megamol::core::PerformanceHistory::buffer_length; +} From 367d1c132971ae017e60d235e6f85de84498315a Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 1 Sep 2021 12:15:32 +0200 Subject: [PATCH 22/47] history also for GPU --- core/include/mmcore/Call.h | 26 ++++++++------------------ core/src/Call.cpp | 5 +---- core/src/PerformanceQueryManager.cpp | 5 +---- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 85d8804938..b432e1c814 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -123,20 +123,20 @@ namespace core { return 0; } inline double GetLastGPUTime(uint32_t func) const { - if (func < last_gpu_time.size()) - return last_gpu_time[func]; + if (func < callback_names.size()) + return gpu_history[func].last_value(); else return -1.0; } inline double GetAverageGPUTime(uint32_t func) const { - if (func < avg_gpu_time.size()) - return avg_gpu_time[func]; + if (func < callback_names.size()) + return gpu_history[func].average(); else return -1.0; } inline uint32_t GetNumGPUSamples(uint32_t func) const { - if (func < num_gpu_time_samples.size()) - return num_gpu_time_samples[func]; + if (func < callback_names.size()) + return gpu_history[func].samples(); else return 0; } @@ -184,27 +184,17 @@ namespace core { void setProfilingInfo(std::vector names, bool usesGL) { callback_names = std::move(names); - //last_cpu_time.resize(callback_names.size()); - //avg_cpu_time.resize(callback_names.size()); - //num_cpu_time_samples.resize(callback_names.size()); cpu_history.resize(callback_names.size()); - last_gpu_time.resize(callback_names.size()); - avg_gpu_time.resize(callback_names.size()); - num_gpu_time_samples.resize(callback_names.size()); + gpu_history.resize(callback_names.size()); uses_gl = usesGL; if (usesGL) { qm->AddCall(this); } } - //std::vector last_cpu_time; - //std::vector avg_cpu_time; - //std::vector num_cpu_time_samples; std::vector cpu_history; + std::vector gpu_history; - std::vector last_gpu_time; - std::vector avg_gpu_time; - std::vector num_gpu_time_samples; std::vector callback_names; bool uses_gl = false; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 1bbeca25b7..b99f0781bb 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -96,10 +96,7 @@ bool Call::operator()(unsigned int func) { const auto endTime = std::chrono::high_resolution_clock::now(); const std::chrono::duration diffMillis = endTime - startTime; cpu_history[func].push_value(diffMillis.count()); - //last_cpu_time[func] = diffMillis.count(); - //const auto total = (avg_cpu_time[func] * num_cpu_time_samples[func] + last_cpu_time[func]); - //num_cpu_time_samples[func]++; - //avg_cpu_time[func] = total / static_cast(num_cpu_time_samples[func]); + #endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS if (p2 || p3 || p3_2) glPopDebugGroup(); diff --git a/core/src/PerformanceQueryManager.cpp b/core/src/PerformanceQueryManager.cpp index cda344da5f..ce84efe831 100644 --- a/core/src/PerformanceQueryManager.cpp +++ b/core/src/PerformanceQueryManager.cpp @@ -94,10 +94,7 @@ void PerformanceQueryManager::Collect() { const auto the_call = qi.call_idx; qi.started = false; auto c = all_calls[the_call]; - c->last_gpu_time[the_func] = static_cast(time / 1000000.0); - const auto total = c->avg_gpu_time[the_func] * c->num_gpu_time_samples[the_func] + c->last_gpu_time[the_func]; - c->num_gpu_time_samples[the_func]++; - c->avg_gpu_time[the_func] = total / c->num_gpu_time_samples[the_func]; + c->gpu_history[the_func].push_value(static_cast(time / 1000000.0)); } AdvanceGLProfiling(); // important! regardless of whether the last call was actually profiled! we need to advance // through the graph though From 28dd755c70066578d9af4f973d17b89f74c3dd00 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 1 Sep 2021 12:30:56 +0200 Subject: [PATCH 23/47] cleanup / off-by-one --- core/include/mmcore/Call.h | 3 +++ core/src/PerformanceHistory.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index b432e1c814..6c04da2149 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -104,6 +104,9 @@ namespace core { } #ifdef PROFILING + static uint32_t GetSampleHistoryLength() { + return PerformanceHistory::buffer_length; + } inline double GetLastCPUTime(uint32_t func) const { if (func < callback_names.size()) return cpu_history[func].last_value(); diff --git a/core/src/PerformanceHistory.cpp b/core/src/PerformanceHistory.cpp index 5441613eb8..29bc67cd2b 100644 --- a/core/src/PerformanceHistory.cpp +++ b/core/src/PerformanceHistory.cpp @@ -15,20 +15,20 @@ void PerformanceHistory::push_value(double val) { // array starts zeroed so unused samples do not change the result here window_total -= time_buffer[next_index]; window_total += val; - // until we have at least a sample everywhere, the average is over num_samples only - window_avg = window_total / std::min(buffer_length, num_samples); time_buffer[next_index] = val; const auto total = avg_time * num_samples + val; num_samples++; avg_time = total / static_cast(num_samples); - //last_index = next_index; + + // until we have at least a sample everywhere, the average is over num_samples only + window_avg = window_total / std::min(buffer_length, num_samples); + next_index = next_wrap(next_index); } void PerformanceHistory::reset() { next_index = 0; - //last_index = 0; time_buffer.fill(0.0); num_samples = 0; avg_time = 0; From e0ebe8af50a3bc3185fe735c6388d6c708b832f3 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 2 Sep 2021 12:43:43 +0200 Subject: [PATCH 24/47] prototype perf history graph ugly and y scaling is a problem ATM --- core/include/mmcore/Call.h | 13 +++++++++++- core/include/mmcore/PerformanceHistory.h | 9 +++++++++ frontend/services/gui/src/graph/Call.cpp | 20 +++++++++++++++++-- frontend/services/gui/src/graph/Call.h | 5 +++++ .../gui/src/graph/GraphCollection.cpp | 6 ++++++ 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 6c04da2149..75da75f8f0 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -125,6 +125,12 @@ namespace core { else return 0; } + inline std::array GetCPUHistory(uint32_t func) const { + if (func < callback_names.size()) + return cpu_history[func].copyHistory(); + else + return std::array{}; + } inline double GetLastGPUTime(uint32_t func) const { if (func < callback_names.size()) return gpu_history[func].last_value(); @@ -143,7 +149,12 @@ namespace core { else return 0; } - + inline std::array GetGPUHistory(uint32_t func) const { + if (func < callback_names.size()) + return gpu_history[func].copyHistory(); + else + return std::array{}; + } inline uint32_t GetFuncCount() const { /// XXX assert(last_cpu_time.size() == avg_cpu_time.size() == num_cpu_time_samples.size() == last_gpu_time.size() == /// avg_gpu_time.size() == num_gpu_time_samples.size()); diff --git a/core/include/mmcore/PerformanceHistory.h b/core/include/mmcore/PerformanceHistory.h index bc0422c2b0..f96019542a 100644 --- a/core/include/mmcore/PerformanceHistory.h +++ b/core/include/mmcore/PerformanceHistory.h @@ -45,6 +45,15 @@ class PerformanceHistory { return num_samples; } + std::array copyHistory() const { + std::array ret{}; + std::copy(time_buffer.begin() + next_index, time_buffer.end(), ret.begin()); + if (next_index > 0) { + std::copy_n(time_buffer.begin(), next_index, ret.begin() + (buffer_length - next_index)); + } + return ret; + } + private: static int offset(const int index, const int offset); diff --git a/frontend/services/gui/src/graph/Call.cpp b/frontend/services/gui/src/graph/Call.cpp index b9413aea87..9e253edfcb 100644 --- a/frontend/services/gui/src/graph/Call.cpp +++ b/frontend/services/gui/src/graph/Call.cpp @@ -11,8 +11,8 @@ #include "Module.h" #ifdef PROFILING -#define PROFILING_CHILD_WIDTH (12.0f) -#define PROFILING_CHILD_HEIGHT (8.5f) +#define PROFILING_CHILD_WIDTH (18.0f) +#define PROFILING_CHILD_HEIGHT (14.8f) #endif using namespace megamol; @@ -439,6 +439,14 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::Text("%i", this->profiling[i].ncpus); ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::TextUnformatted("CPU History"); + ImGui::TableNextColumn(); + ImGui::PlotLines("###cpuplot", this->profiling[i].hcpu.data(), + static_cast(this->profiling[i].hcpu.size()), 0, nullptr, 0.0f, 16.0f, + ImVec2(core::PerformanceHistory::buffer_length * 2 * megamol::gui::gui_scaling.Get(), + (3.0f * ImGui::GetFrameHeight()))); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); ImGui::TextUnformatted("LastGPUTime"); ImGui::TableNextColumn(); ImGui::Text("%.12f", this->profiling[i].lgput); @@ -452,6 +460,14 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::TextUnformatted("NumGPUSamples"); ImGui::TableNextColumn(); ImGui::Text("%.12i", this->profiling[i].ngpus); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("GPU History"); + ImGui::TableNextColumn(); + ImGui::PlotLines("###gpuplot", this->profiling[i].hgpu.data(), + static_cast(this->profiling[i].hgpu.size()), 0, nullptr, 0.0f, 16.0f, + ImVec2(core::PerformanceHistory::buffer_length * 2 * megamol::gui::gui_scaling.Get(), + ((3.0f * ImGui::GetFrameHeight())))); ImGui::EndTable(); } ImGui::EndTabItem(); diff --git a/frontend/services/gui/src/graph/Call.h b/frontend/services/gui/src/graph/Call.h index 8467e3bc4f..db25a444b5 100644 --- a/frontend/services/gui/src/graph/Call.h +++ b/frontend/services/gui/src/graph/Call.h @@ -10,6 +10,9 @@ #pragma once +#ifdef PROFILING +#include "mmcore/PerformanceHistory.h" +#endif #include "widgets/HoverToolTip.h" @@ -74,9 +77,11 @@ namespace gui { double lcput; double acput; uint32_t ncpus; + std::array hcpu; double lgput; double agput; uint32_t ngpus; + std::array hgpu; std::string name; }; diff --git a/frontend/services/gui/src/graph/GraphCollection.cpp b/frontend/services/gui/src/graph/GraphCollection.cpp index 11cef15c7a..148c226959 100644 --- a/frontend/services/gui/src/graph/GraphCollection.cpp +++ b/frontend/services/gui/src/graph/GraphCollection.cpp @@ -652,9 +652,15 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( prof[i].lcput = ccall.callPtr->GetLastCPUTime(i); prof[i].acput = ccall.callPtr->GetAverageCPUTime(i); prof[i].ncpus = ccall.callPtr->GetNumCPUSamples(i); + const auto ch = ccall.callPtr->GetCPUHistory(i); + std::transform(ch.begin(), ch.end(), prof[i].hcpu.begin(), + [](double d) -> float { return static_cast(d); }); prof[i].lgput = ccall.callPtr->GetLastGPUTime(i); prof[i].agput = ccall.callPtr->GetAverageGPUTime(i); prof[i].ngpus = ccall.callPtr->GetNumGPUSamples(i); + const auto gh = ccall.callPtr->GetGPUHistory(i); + std::transform(gh.begin(), gh.end(), prof[i].hgpu.begin(), + [](double d) -> float { return static_cast(d); }); prof[i].name = ccall.callPtr->GetFuncName(i); } gcall.ptr.lock()->SetProfilingValues(prof); From 0167667bebbfcdbc990ee5e8ac2c7fa42cbe2c55 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 2 Sep 2021 15:01:30 +0200 Subject: [PATCH 25/47] even smaller footprint in code --- core/include/mmcore/Call.h | 105 ++-------------- core/include/mmcore/CallProfiling.h | 55 ++++++++ core/src/Call.cpp | 15 +-- core/src/CallProfiling.cpp | 117 ++++++++++++++++++ core/src/MegaMolGraph.cpp | 10 +- core/src/PerformanceQueryManager.cpp | 4 +- .../gui/src/graph/GraphCollection.cpp | 21 ++-- .../opengl_glfw/OpenGL_GLFW_Service.cpp | 2 +- 8 files changed, 202 insertions(+), 127 deletions(-) create mode 100644 core/include/mmcore/CallProfiling.h create mode 100644 core/src/CallProfiling.cpp diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 75da75f8f0..ecc3779a2c 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -12,13 +12,9 @@ #endif /* (defined(_MSC_VER) && (_MSC_VER > 1000)) */ #include +#include #ifdef PROFILING -#include -#include -#include -#include -#include "PerformanceQueryManager.h" -#include "PerformanceHistory.h" +#include "CallProfiling.h" #endif #include "mmcore/api/MegaMolCore.std.h" @@ -104,79 +100,8 @@ namespace core { } #ifdef PROFILING - static uint32_t GetSampleHistoryLength() { - return PerformanceHistory::buffer_length; - } - inline double GetLastCPUTime(uint32_t func) const { - if (func < callback_names.size()) - return cpu_history[func].last_value(); - else - return -1.0; - } - inline double GetAverageCPUTime(uint32_t func) const { - if (func < callback_names.size()) - return cpu_history[func].average(); - else - return -1.0; - } - inline uint32_t GetNumCPUSamples(uint32_t func) const { - if (func < callback_names.size()) - return cpu_history[func].samples(); - else - return 0; - } - inline std::array GetCPUHistory(uint32_t func) const { - if (func < callback_names.size()) - return cpu_history[func].copyHistory(); - else - return std::array{}; - } - inline double GetLastGPUTime(uint32_t func) const { - if (func < callback_names.size()) - return gpu_history[func].last_value(); - else - return -1.0; - } - inline double GetAverageGPUTime(uint32_t func) const { - if (func < callback_names.size()) - return gpu_history[func].average(); - else - return -1.0; - } - inline uint32_t GetNumGPUSamples(uint32_t func) const { - if (func < callback_names.size()) - return gpu_history[func].samples(); - else - return 0; - } - inline std::array GetGPUHistory(uint32_t func) const { - if (func < callback_names.size()) - return gpu_history[func].copyHistory(); - else - return std::array{}; - } - inline uint32_t GetFuncCount() const { - /// XXX assert(last_cpu_time.size() == avg_cpu_time.size() == num_cpu_time_samples.size() == last_gpu_time.size() == - /// avg_gpu_time.size() == num_gpu_time_samples.size()); - return static_cast(callback_names.size()); - } - inline std::string GetFuncName(uint32_t i) const { - if (i < callback_names.size()) { - return callback_names[i]; - } else { - return "out of bounds"; - } - } - static void InitializeQueryManager() { - if (qm == nullptr) { - qm = new PerformanceQueryManager(); - } - } - static void CollectGPUPerformance() { - if (qm != nullptr) { - qm->Collect(); - } - } + bool UsesGL() { return uses_gl; } + const CallProfiling& GetProfiling() const { return profiling; } #endif private: @@ -196,29 +121,15 @@ namespace core { friend class MegaMolGraph; friend class PerformanceQueryManager; + CallProfiling profiling; + void setProfilingInfo(std::vector names, bool usesGL) { - callback_names = std::move(names); - cpu_history.resize(callback_names.size()); - gpu_history.resize(callback_names.size()); uses_gl = usesGL; - if (usesGL) { - qm->AddCall(this); - } + profiling.setProfilingInfo(std::move(names), this); } - std::vector cpu_history; - std::vector gpu_history; - - std::vector callback_names; bool uses_gl = false; - - // todo these are so slow, we need double buffering all the same. best wrap starting_call and func inside the query and vary across the current frame - - // there is only one query. it needs to be fetched and the result assigned - // to starting_call at the end of the frame. - static PerformanceQueryManager *qm; - // who can use the query this frame? -#endif PROFILING +#endif //PROFILING }; diff --git a/core/include/mmcore/CallProfiling.h b/core/include/mmcore/CallProfiling.h new file mode 100644 index 0000000000..0b0b2b5390 --- /dev/null +++ b/core/include/mmcore/CallProfiling.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +#include "PerformanceQueryManager.h" +#include "PerformanceHistory.h" + +namespace megamol { +namespace core { + + class Call; + + class CallProfiling { + public: + + CallProfiling(); + ~CallProfiling(); + + static uint32_t GetSampleHistoryLength(); + + double GetLastCPUTime(uint32_t func) const; + double GetAverageCPUTime(uint32_t func) const; + uint32_t GetNumCPUSamples(uint32_t func) const; + std::array GetCPUHistory(uint32_t func) const; + + double GetLastGPUTime(uint32_t func) const; + double GetAverageGPUTime(uint32_t func) const; + uint32_t GetNumGPUSamples(uint32_t func) const; + std::array GetGPUHistory(uint32_t func) const; + + uint32_t GetFuncCount() const; + const std::string& GetFuncName(uint32_t i) const; + + static void InitializeQueryManager(); + static void CollectGPUPerformance(); + + private: + friend class Call; + friend class PerformanceQueryManager; + + void setProfilingInfo(std::vector names, Call *parent); + + std::vector cpu_history; + std::vector gpu_history; + std::vector callback_names; + Call *parent_call = nullptr; + static PerformanceQueryManager *qm; + static std::string err_oob; + }; + +} +} diff --git a/core/src/Call.cpp b/core/src/Call.cpp index b99f0781bb..9f99c743d7 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -26,10 +26,6 @@ using namespace megamol::core; -#ifdef PROFILING -PerformanceQueryManager *Call::qm = nullptr; -#endif - /* * Call::Call */ @@ -42,11 +38,6 @@ Call::Call(void) : callee(nullptr), caller(nullptr), className(nullptr), funcMap * Call::~Call */ Call::~Call(void) { -#ifdef PROFILING - if (uses_gl) { - qm->RemoveCall(this); - } -#endif if (this->caller != nullptr) { CallerSlot* cr = this->caller; this->caller = nullptr; // DO NOT DELETE @@ -85,17 +76,17 @@ bool Call::operator()(unsigned int func) { const auto startTime = std::chrono::high_resolution_clock::now(); bool gl_started = false; if (uses_gl) { - gl_started = qm->Start(this, this->callee->GetCoreInstance()->GetFrameID(), func); + gl_started = CallProfiling::qm->Start(this, this->callee->GetCoreInstance()->GetFrameID(), func); } #endif res = this->callee->InCall(this->funcMap[func], *this); #ifdef PROFILING if (gl_started) { - qm->Stop(this->callee->GetCoreInstance()->GetFrameID()); + CallProfiling::qm->Stop(this->callee->GetCoreInstance()->GetFrameID()); } const auto endTime = std::chrono::high_resolution_clock::now(); const std::chrono::duration diffMillis = endTime - startTime; - cpu_history[func].push_value(diffMillis.count()); + profiling.cpu_history[func].push_value(diffMillis.count()); #endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS diff --git a/core/src/CallProfiling.cpp b/core/src/CallProfiling.cpp new file mode 100644 index 0000000000..234c3132b3 --- /dev/null +++ b/core/src/CallProfiling.cpp @@ -0,0 +1,117 @@ +#include "mmcore/CallProfiling.h" +#include "mmcore/Call.h" + +using namespace megamol; +using namespace core; + +std::string CallProfiling::err_oob = "out of bounds"; +PerformanceQueryManager* CallProfiling::qm = nullptr; + +CallProfiling::CallProfiling() { + +} + +CallProfiling::~CallProfiling() { + if (parent_call->UsesGL()) { + qm->RemoveCall(parent_call); + } +} + +uint32_t CallProfiling::GetSampleHistoryLength() { + return PerformanceHistory::buffer_length; +} + +double CallProfiling::GetLastCPUTime(uint32_t func) const { + if (func < callback_names.size()) + return cpu_history[func].last_value(); + else + return -1.0; +} + +double CallProfiling::GetAverageCPUTime(uint32_t func) const { + if (func < callback_names.size()) + return cpu_history[func].average(); + else + return -1.0; +} + +uint32_t CallProfiling::GetNumCPUSamples(uint32_t func) const { + if (func < callback_names.size()) + return cpu_history[func].samples(); + else + return 0; +} + +std::array CallProfiling::GetCPUHistory( + uint32_t func) const { + if (func < callback_names.size()) + return cpu_history[func].copyHistory(); + else + return std::array{}; +} + +double CallProfiling::GetLastGPUTime(uint32_t func) const { + if (func < callback_names.size()) + return gpu_history[func].last_value(); + else + return -1.0; +} + +double CallProfiling::GetAverageGPUTime(uint32_t func) const { + if (func < callback_names.size()) + return gpu_history[func].average(); + else + return -1.0; +} + +uint32_t CallProfiling::GetNumGPUSamples(uint32_t func) const { + if (func < callback_names.size()) + return gpu_history[func].samples(); + else + return 0; +} + +std::array CallProfiling::GetGPUHistory( + uint32_t func) const { + if (func < callback_names.size()) + return gpu_history[func].copyHistory(); + else + return std::array{}; +} + +uint32_t CallProfiling::GetFuncCount() const { + /// XXX assert(last_cpu_time.size() == avg_cpu_time.size() == num_cpu_time_samples.size() == last_gpu_time.size() == + /// avg_gpu_time.size() == num_gpu_time_samples.size()); + return static_cast(callback_names.size()); +} + +const std::string& CallProfiling::GetFuncName(uint32_t i) const { + if (i < callback_names.size()) { + return callback_names[i]; + } else { + return err_oob; + } +} + +void CallProfiling::InitializeQueryManager() { + if (qm == nullptr) { + qm = new PerformanceQueryManager(); + } +} + +void CallProfiling::CollectGPUPerformance() { + if (qm != nullptr) { + qm->Collect(); + } +} + +void CallProfiling::setProfilingInfo(std::vector names, Call* parent) { + callback_names = std::move(names); + cpu_history.resize(callback_names.size()); + gpu_history.resize(callback_names.size()); + parent_call = parent; + if (parent_call->UsesGL()) { + InitializeQueryManager(); + qm->AddCall(parent_call); + } +} diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index 553079474b..76d212cfdc 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -15,6 +15,7 @@ // TODO if GL enabled #include "mmcore/view/Renderer2DModule.h" #include "mmcore/view/Renderer3DModuleGL.h" +#include "mmcore/view/RendererModule.h" // splits a string of the form "::one::two::three::" into an array of strings {"one", "two", "three"} static std::vector splitPathName(std::string const& path) { @@ -366,11 +367,10 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req callbacks[x] = call_description->FunctionName(x); } // TODO if gl enabled, else both vars = false - const auto gl_1 = dynamic_cast(to_slot.second.get()); - const auto gl_2 = dynamic_cast(to_slot.second.get()); - if ((gl_1 || gl_2)) { - core::Call::InitializeQueryManager(); - } + const auto gl_1 = dynamic_cast(to_slot.second.get()); + const auto gl_2 = dynamic_cast(to_slot.second.get()); + // something like that would be nice but does not work + //const auto gl_3 = dynamic_cast>(to_slot.second.get()); call->setProfilingInfo(callbacks, gl_1 || gl_2); #endif diff --git a/core/src/PerformanceQueryManager.cpp b/core/src/PerformanceQueryManager.cpp index ce84efe831..bc02567007 100644 --- a/core/src/PerformanceQueryManager.cpp +++ b/core/src/PerformanceQueryManager.cpp @@ -42,7 +42,7 @@ void PerformanceQueryManager::ResetGLProfiling() { } void PerformanceQueryManager::AdvanceGLProfiling() { - starting_func = (starting_func + 1) % all_calls[starting_call]->GetFuncCount(); + starting_func = (starting_func + 1) % all_calls[starting_call]->profiling.GetFuncCount(); if (starting_func == 0) { // we wrapped, advance to next call! starting_call = (starting_call + 1) % all_calls.size(); @@ -94,7 +94,7 @@ void PerformanceQueryManager::Collect() { const auto the_call = qi.call_idx; qi.started = false; auto c = all_calls[the_call]; - c->gpu_history[the_func].push_value(static_cast(time / 1000000.0)); + c->profiling.gpu_history[the_func].push_value(static_cast(time) / 1000000.0); } AdvanceGLProfiling(); // important! regardless of whether the last call was actually profiled! we need to advance // through the graph though diff --git a/frontend/services/gui/src/graph/GraphCollection.cpp b/frontend/services/gui/src/graph/GraphCollection.cpp index 148c226959..2d04883e3e 100644 --- a/frontend/services/gui/src/graph/GraphCollection.cpp +++ b/frontend/services/gui/src/graph/GraphCollection.cpp @@ -645,23 +645,24 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( if (gcall.class_name == ccall.request.className && gui_utils::CaseInsensitiveStringCompare(gcall.from, ccall.request.from) && gui_utils::CaseInsensitiveStringCompare(gcall.to, ccall.request.to)) { - auto func_count = ccall.callPtr->GetFuncCount(); + const auto& profiling = ccall.callPtr->GetProfiling(); + auto func_count = profiling.GetFuncCount(); std::vector prof; prof.resize(func_count); for (uint32_t i = 0; i < func_count; i++) { - prof[i].lcput = ccall.callPtr->GetLastCPUTime(i); - prof[i].acput = ccall.callPtr->GetAverageCPUTime(i); - prof[i].ncpus = ccall.callPtr->GetNumCPUSamples(i); - const auto ch = ccall.callPtr->GetCPUHistory(i); + prof[i].lcput = profiling.GetLastCPUTime(i); + prof[i].acput = profiling.GetAverageCPUTime(i); + prof[i].ncpus = profiling.GetNumCPUSamples(i); + const auto ch = profiling.GetCPUHistory(i); std::transform(ch.begin(), ch.end(), prof[i].hcpu.begin(), [](double d) -> float { return static_cast(d); }); - prof[i].lgput = ccall.callPtr->GetLastGPUTime(i); - prof[i].agput = ccall.callPtr->GetAverageGPUTime(i); - prof[i].ngpus = ccall.callPtr->GetNumGPUSamples(i); - const auto gh = ccall.callPtr->GetGPUHistory(i); + prof[i].lgput = profiling.GetLastGPUTime(i); + prof[i].agput = profiling.GetAverageGPUTime(i); + prof[i].ngpus = profiling.GetNumGPUSamples(i); + const auto gh = profiling.GetGPUHistory(i); std::transform(gh.begin(), gh.end(), prof[i].hgpu.begin(), [](double d) -> float { return static_cast(d); }); - prof[i].name = ccall.callPtr->GetFuncName(i); + prof[i].name = profiling.GetFuncName(i); } gcall.ptr.lock()->SetProfilingValues(prof); } diff --git a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp index 9e2259e86e..4bd5add7db 100644 --- a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp +++ b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp @@ -787,7 +787,7 @@ void OpenGL_GLFW_Service::postGraphRender() { ::glfwSwapBuffers(m_pimpl->glfwContextWindowPtr); #ifdef PROFILING - core::Call::CollectGPUPerformance(); + core::CallProfiling::CollectGPUPerformance(); #endif //::glfwMakeContextCurrent(window_ptr); From c88e7ca5632b057de3a3c48d5a79144b464ab261 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 2 Sep 2021 15:50:11 +0200 Subject: [PATCH 26/47] added implot as external dep --- externals/CMakeExternals.cmake | 42 ++++++++++++++++++++++++ externals/implot/CMakeLists.txt | 20 +++++++++++ frontend/services/CMakeLists.txt | 3 +- frontend/services/gui/src/GUIManager.cpp | 41 +++++++++++++---------- frontend/services/gui/src/GUIManager.h | 6 +++- frontend/services/gui/src/graph/Call.cpp | 18 ++++++++-- 6 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 externals/implot/CMakeLists.txt diff --git a/externals/CMakeExternals.cmake b/externals/CMakeExternals.cmake index 234ebad3d8..09e240e0d8 100644 --- a/externals/CMakeExternals.cmake +++ b/externals/CMakeExternals.cmake @@ -458,6 +458,48 @@ function(require_external NAME) add_external_library(imguizmoquat LIBRARY ${IMGUIZMOQUAT_LIB}) + # implot + elseif(NAME STREQUAL "implot") + if(TARGET implot) + return() + endif() + + require_external(imgui) + + if(WIN32) + set(IMPLOT_LIB "lib/implot.lib") + else() + set(IMPLOT_LIB "lib/libimplot.a") + endif() + + if(WIN32) + set(IMGUI_LIB "lib/imgui.lib") + else() + set(IMGUI_LIB "lib/libimgui.a") + endif() + + external_get_property(imgui INSTALL_DIR) + + add_external_project(implot STATIC + GIT_REPOSITORY https://github.com/epezent/implot.git + GIT_TAG "v0.8" + BUILD_BYPRODUCTS "/${IMPLOT_LIB}" + DEPENDS imgui + CMAKE_ARGS + -DIMGUI_LIBRARY:PATH=${INSTALL_DIR}/${IMGUI_LIB} + -DIMGUI_INCLUDE_DIR:PATH=${INSTALL_DIR}/include + -DCMAKE_C_FLAGS=-fPIC + -DCMAKE_CXX_FLAGS=-fPIC + PATCH_COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_SOURCE_DIR}/externals/implot/CMakeLists.txt" + "/CMakeLists.txt") + + add_external_library(implot + LIBRARY ${IMPLOT_LIB}) + + external_get_property(implot SOURCE_DIR) + target_include_directories(implot INTERFACE "${SOURCE_DIR}") + # libpng elseif(NAME STREQUAL "libpng") if(TARGET libpng) diff --git a/externals/implot/CMakeLists.txt b/externals/implot/CMakeLists.txt new file mode 100644 index 0000000000..3cf773fdaf --- /dev/null +++ b/externals/implot/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0) + +project(implot CXX) + +set(IMPLOT_PUBLIC_HDRS + implot.h) +set(IMPLOT_PRIVATE_HDRS + implot_internal.h) +set(IMPLOT_SRCS + implot.cpp + implot_items.cpp) + +add_library(implot STATIC ${IMPLOT_SRCS} ${IMPLOT_PUBLIC_HDRS} ${IMPLOT_PRIVATE_HDRS}) + +target_compile_definitions(implot PRIVATE IMGUI_IMPL_OPENGL_LOADER_GLAD) +target_link_libraries(implot PRIVATE ${IMGUI_LIBRARY}) +target_include_directories(implot PRIVATE ${IMGUI_INCLUDE_DIR}) + +install(TARGETS implot DESTINATION "lib") +install(FILES ${IMPLOT_PUBLIC_HDRS} DESTINATION "include") diff --git a/frontend/services/CMakeLists.txt b/frontend/services/CMakeLists.txt index f3c09ee22f..67e0e2571e 100644 --- a/frontend/services/CMakeLists.txt +++ b/frontend/services/CMakeLists.txt @@ -12,6 +12,7 @@ if(BUILD_FRONTEND_SERVICES) require_external(glm) require_external(glad) require_external(imgui) + require_external(implot) require_external(imguizmoquat) file(GLOB_RECURSE header_files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" @@ -87,7 +88,7 @@ if(BUILD_FRONTEND_SERVICES) target_link_libraries(${PROJECT_NAME} PRIVATE glfw) endif() - target_link_libraries(${PROJECT_NAME} PRIVATE ${VERSION_LIBRARY} ${CMAKE_DL_LIBS} PUBLIC abstract_frontend_service vislib core glad glm imgui imguizmoquat) + target_link_libraries(${PROJECT_NAME} PRIVATE ${VERSION_LIBRARY} ${CMAKE_DL_LIBS} PUBLIC abstract_frontend_service vislib core glad glm imgui implot imguizmoquat) # Install gui resources if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gui/resources") diff --git a/frontend/services/gui/src/GUIManager.cpp b/frontend/services/gui/src/GUIManager.cpp index 87c6167504..47b9a025d2 100644 --- a/frontend/services/gui/src/GUIManager.cpp +++ b/frontend/services/gui/src/GUIManager.cpp @@ -22,7 +22,8 @@ using namespace megamol::gui; GUIManager::GUIManager() : hotkeys() - , context(nullptr) + , imgui_context(nullptr) + , implot_context(nullptr) , initialized_api(megamol::gui::GUIImGuiAPI::NONE) , gui_state() , win_collection() @@ -179,7 +180,7 @@ bool GUIManager::CreateContext(GUIImGuiAPI imgui_api) { this->initialized_api = imgui_api; megamol::gui::gui_context_count++; - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); return true; } return false; @@ -204,13 +205,13 @@ bool GUIManager::PreDraw(glm::vec2 framebuffer_size, glm::vec2 window_size, doub return false; } // Check for existing imgui context - if (this->context == nullptr) { + if (this->imgui_context == nullptr) { megamol::core::utility::log::Log::DefaultLog.WriteError( "[GUI] No valid ImGui context available. [%s, %s, line %d]\n", __FILE__, __FUNCTION__, __LINE__); return false; } // Set ImGui context - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); // Process hotkeys if (this->hotkeys[HOTKEY_GUI_SHOW_HIDE_GUI].is_pressed) { @@ -367,14 +368,14 @@ bool GUIManager::PostDraw() { return false; } // Check for existing imgui context - if (this->context == nullptr) { + if (this->imgui_context == nullptr) { megamol::core::utility::log::Log::DefaultLog.WriteError( "[GUI] No valid ImGui context available. [%s, %s, line %d]\n", __FILE__, __FUNCTION__, __LINE__); return false; } // Set ImGui context - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); ImGuiIO& io = ImGui::GetIO(); ImGuiStyle& style = ImGui::GetStyle(); @@ -509,7 +510,7 @@ bool GUIManager::PostDraw() { bool GUIManager::OnKey(core::view::Key key, core::view::KeyAction action, core::view::Modifiers mods) { - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); ImGuiIO& io = ImGui::GetIO(); @@ -635,7 +636,7 @@ bool GUIManager::OnKey(core::view::Key key, core::view::KeyAction action, core:: bool GUIManager::OnChar(unsigned int codePoint) { - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); ImGuiIO& io = ImGui::GetIO(); io.ClearInputCharacters(); @@ -649,7 +650,7 @@ bool GUIManager::OnChar(unsigned int codePoint) { bool GUIManager::OnMouseMove(double x, double y) { - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); ImGuiIO& io = ImGui::GetIO(); io.MousePos = ImVec2(static_cast(x), static_cast(y)); @@ -670,7 +671,7 @@ bool GUIManager::OnMouseMove(double x, double y) { bool GUIManager::OnMouseButton( core::view::MouseButton button, core::view::MouseButtonAction action, core::view::Modifiers mods) { - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); bool down = (action == core::view::MouseButtonAction::PRESS); auto buttonIndex = static_cast(button); @@ -693,7 +694,7 @@ bool GUIManager::OnMouseButton( bool GUIManager::OnMouseScroll(double dx, double dy) { - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); ImGuiIO& io = ImGui::GetIO(); io.MouseWheelH += (float) dx; @@ -737,7 +738,7 @@ void megamol::gui::GUIManager::SetScale(float scale) { void megamol::gui::GUIManager::SetClipboardFunc(const char* (*get_clipboard_func)(void* user_data), void (*set_clipboard_func)(void* user_data, const char* string), void* user_data) { - if (this->context != nullptr) { + if (this->imgui_context != nullptr) { ImGuiIO& io = ImGui::GetIO(); io.SetClipboardTextFn = set_clipboard_func; io.GetClipboardTextFn = get_clipboard_func; @@ -952,12 +953,13 @@ bool GUIManager::create_context() { // Create ImGui context --------------------------------------------------- IMGUI_CHECKVERSION(); - this->context = ImGui::CreateContext(font_atlas); - if (this->context == nullptr) { + this->imgui_context = ImGui::CreateContext(font_atlas); + if (this->imgui_context == nullptr) { megamol::core::utility::log::Log::DefaultLog.WriteError( "[GUI] Unable to create ImGui context. [%s, %s, line %d]\n", __FILE__, __FUNCTION__, __LINE__); return false; } + this->implot_context = ImPlot::CreateContext(); // Style settings --------------------------------------------------------- ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | @@ -1061,11 +1063,11 @@ bool GUIManager::create_context() { bool GUIManager::destroy_context() { if (this->initialized_api != GUIImGuiAPI::NONE) { - if (this->context != nullptr) { + if (this->imgui_context != nullptr) { // Handle multiple ImGui contexts. if (megamol::gui::gui_context_count < 2) { - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); // Shutdown API only if only one context is left switch (this->initialized_api) { case (GUIImGuiAPI::OPEN_GL): @@ -1078,11 +1080,14 @@ bool GUIManager::destroy_context() { ImGui::GetCurrentContext()->FontAtlasOwnedByContext = true; } - ImGui::DestroyContext(this->context); + if (this->implot_context != nullptr) { + ImPlot::DestroyContext(this->implot_context); + } + ImGui::DestroyContext(this->imgui_context); megamol::gui::gui_context_count--; megamol::core::utility::log::Log::DefaultLog.WriteInfo("[GUI] Destroyed ImGui context."); } - this->context = nullptr; + this->imgui_context = nullptr; this->initialized_api = GUIImGuiAPI::NONE; } diff --git a/frontend/services/gui/src/GUIManager.h b/frontend/services/gui/src/GUIManager.h index 1e1b7b626b..226fb4335b 100644 --- a/frontend/services/gui/src/GUIManager.h +++ b/frontend/services/gui/src/GUIManager.h @@ -10,6 +10,7 @@ #pragma once +#include "implot.h" #include "mmcore/CoreInstance.h" #include "mmcore/MegaMolGraph.h" #include "mmcore/utility/Picking_gl.h" @@ -293,7 +294,10 @@ namespace gui { megamol::gui::HotkeyMap_t hotkeys; /** The ImGui context created and used by this GUIManager */ - ImGuiContext* context; + ImGuiContext* imgui_context; + + /** The ImGui context created and used by this GUIManager */ + ImPlotContext* implot_context; GUIImGuiAPI initialized_api; diff --git a/frontend/services/gui/src/graph/Call.cpp b/frontend/services/gui/src/graph/Call.cpp index 9e253edfcb..3d0c43ae3b 100644 --- a/frontend/services/gui/src/graph/Call.cpp +++ b/frontend/services/gui/src/graph/Call.cpp @@ -11,8 +11,11 @@ #include "Module.h" #ifdef PROFILING + #define PROFILING_CHILD_WIDTH (18.0f) #define PROFILING_CHILD_HEIGHT (14.8f) +#include "implot.h" + #endif using namespace megamol; @@ -441,10 +444,21 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::TableNextColumn(); ImGui::TextUnformatted("CPU History"); ImGui::TableNextColumn(); + + /* ImGui::PlotLines("###cpuplot", this->profiling[i].hcpu.data(), static_cast(this->profiling[i].hcpu.size()), 0, nullptr, 0.0f, 16.0f, - ImVec2(core::PerformanceHistory::buffer_length * 2 * megamol::gui::gui_scaling.Get(), - (3.0f * ImGui::GetFrameHeight()))); + )); + */ + + if (ImPlot::BeginPlot("CPU", nullptr, nullptr, + ImVec2(core::PerformanceHistory::buffer_length * 2 * megamol::gui::gui_scaling.Get(), + (3.0f * ImGui::GetFrameHeight())))) { + ImPlot::PlotLine( + "###cpuplot", this->profiling[i].hcpu.data(), static_cast(this->profiling[i].hcpu.size())); + ImPlot::EndPlot(); + } + ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted("LastGPUTime"); From 20ce8773ec6d47279843d65cf6362dd453578c4a Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 2 Sep 2021 19:38:36 +0200 Subject: [PATCH 27/47] using implot fancyness --- frontend/services/gui/src/graph/Call.cpp | 62 +++++++++++-------- frontend/services/gui/src/graph/Call.h | 4 +- .../gui/src/graph/GraphCollection.cpp | 8 +-- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/frontend/services/gui/src/graph/Call.cpp b/frontend/services/gui/src/graph/Call.cpp index 3d0c43ae3b..f07eb4c3a6 100644 --- a/frontend/services/gui/src/graph/Call.cpp +++ b/frontend/services/gui/src/graph/Call.cpp @@ -12,8 +12,9 @@ #ifdef PROFILING -#define PROFILING_CHILD_WIDTH (18.0f) -#define PROFILING_CHILD_HEIGHT (14.8f) +#define PROFILING_PLOT_HEIGHT (7.0f) +#define PROFILING_CHILD_WIDTH (15.0f) +#define PROFILING_CHILD_HEIGHT (9.0f + 2.0f * PROFILING_PLOT_HEIGHT) #include "implot.h" #endif @@ -440,25 +441,28 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::TextUnformatted("NumCPUSamples"); ImGui::TableNextColumn(); ImGui::Text("%i", this->profiling[i].ncpus); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("CPU History"); - ImGui::TableNextColumn(); - /* - ImGui::PlotLines("###cpuplot", this->profiling[i].hcpu.data(), - static_cast(this->profiling[i].hcpu.size()), 0, nullptr, 0.0f, 16.0f, - )); - */ - - if (ImPlot::BeginPlot("CPU", nullptr, nullptr, - ImVec2(core::PerformanceHistory::buffer_length * 2 * megamol::gui::gui_scaling.Get(), - (3.0f * ImGui::GetFrameHeight())))) { - ImPlot::PlotLine( - "###cpuplot", this->profiling[i].hcpu.data(), static_cast(this->profiling[i].hcpu.size())); - ImPlot::EndPlot(); - } + ImGui::EndTable(); + } + + std::array xbuf; + std::iota(xbuf.begin(), xbuf.end(), 0.0f); + std::array ybuf; + const auto ch = this->profiling[i].hcpu; + std::transform(ch.begin(), ch.end(), ybuf.begin(), [](double d) -> float { return static_cast(d); }); + auto Xhist_count = static_cast(ybuf.size()); + + ImPlot::FitNextPlotAxes(); // no ImPlotAxisFlags_Lock + if (ImPlot::BeginPlot("CPU History", nullptr, nullptr, + ImVec2(ImGui::GetContentRegionAvail().x, (PROFILING_PLOT_HEIGHT * ImGui::GetFrameHeight())))) { + ImPlot::PlotLine("###cpuplot", xbuf.data(), ybuf.data(), Xhist_count); + ImPlot::EndPlot(); + } + if (ImGui::BeginTable(("table_" + tab_label).c_str(), 2, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableColumnFlags_NoResize, + ImVec2(0.0f, 0.0f))) { + ImGui::TableSetupColumn(("column_" + tab_label).c_str(), ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextUnformatted("LastGPUTime"); @@ -474,16 +478,20 @@ void megamol::gui::Call::draw_profiling_data() { ImGui::TextUnformatted("NumGPUSamples"); ImGui::TableNextColumn(); ImGui::Text("%.12i", this->profiling[i].ngpus); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("GPU History"); - ImGui::TableNextColumn(); - ImGui::PlotLines("###gpuplot", this->profiling[i].hgpu.data(), - static_cast(this->profiling[i].hgpu.size()), 0, nullptr, 0.0f, 16.0f, - ImVec2(core::PerformanceHistory::buffer_length * 2 * megamol::gui::gui_scaling.Get(), - ((3.0f * ImGui::GetFrameHeight())))); + ImGui::EndTable(); } + + const auto gh = this->profiling[i].hgpu; + std::transform(gh.begin(), gh.end(), ybuf.begin(), [](double d) -> float { return static_cast(d); }); + + ImPlot::FitNextPlotAxes(); + if (ImPlot::BeginPlot("GPU History", nullptr, nullptr, + ImVec2(ImGui::GetContentRegionAvail().x, (PROFILING_PLOT_HEIGHT * ImGui::GetFrameHeight())))) { + ImPlot::PlotLine("###gpuplot", xbuf.data(), ybuf.data(), Xhist_count); + ImPlot::EndPlot(); + } + ImGui::EndTabItem(); } } diff --git a/frontend/services/gui/src/graph/Call.h b/frontend/services/gui/src/graph/Call.h index db25a444b5..98a47e2913 100644 --- a/frontend/services/gui/src/graph/Call.h +++ b/frontend/services/gui/src/graph/Call.h @@ -77,11 +77,11 @@ namespace gui { double lcput; double acput; uint32_t ncpus; - std::array hcpu; + std::array hcpu; double lgput; double agput; uint32_t ngpus; - std::array hgpu; + std::array hgpu; std::string name; }; diff --git a/frontend/services/gui/src/graph/GraphCollection.cpp b/frontend/services/gui/src/graph/GraphCollection.cpp index 2d04883e3e..e5f3cbedba 100644 --- a/frontend/services/gui/src/graph/GraphCollection.cpp +++ b/frontend/services/gui/src/graph/GraphCollection.cpp @@ -653,15 +653,11 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( prof[i].lcput = profiling.GetLastCPUTime(i); prof[i].acput = profiling.GetAverageCPUTime(i); prof[i].ncpus = profiling.GetNumCPUSamples(i); - const auto ch = profiling.GetCPUHistory(i); - std::transform(ch.begin(), ch.end(), prof[i].hcpu.begin(), - [](double d) -> float { return static_cast(d); }); + prof[i].hcpu = profiling.GetCPUHistory(i); prof[i].lgput = profiling.GetLastGPUTime(i); prof[i].agput = profiling.GetAverageGPUTime(i); prof[i].ngpus = profiling.GetNumGPUSamples(i); - const auto gh = profiling.GetGPUHistory(i); - std::transform(gh.begin(), gh.end(), prof[i].hgpu.begin(), - [](double d) -> float { return static_cast(d); }); + prof[i].hgpu = profiling.GetGPUHistory(i); prof[i].name = profiling.GetFuncName(i); } gcall.ptr.lock()->SetProfilingValues(prof); From c6af5876e1f9070a30622ff31b5267b75f5bca7b Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 3 Sep 2021 09:54:13 +0200 Subject: [PATCH 28/47] use current version (v0.11) of implot to have some bugs fixed --- externals/CMakeExternals.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/CMakeExternals.cmake b/externals/CMakeExternals.cmake index 09e240e0d8..51bb3ba9aa 100644 --- a/externals/CMakeExternals.cmake +++ b/externals/CMakeExternals.cmake @@ -482,7 +482,7 @@ function(require_external NAME) add_external_project(implot STATIC GIT_REPOSITORY https://github.com/epezent/implot.git - GIT_TAG "v0.8" + GIT_TAG "v0.11" BUILD_BYPRODUCTS "/${IMPLOT_LIB}" DEPENDS imgui CMAKE_ARGS From 9e1613707f44411563a302a293a4c0c2997235f2 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 3 Sep 2021 10:44:27 +0200 Subject: [PATCH 29/47] implot tweaking --- frontend/services/gui/src/graph/Call.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/services/gui/src/graph/Call.cpp b/frontend/services/gui/src/graph/Call.cpp index f07eb4c3a6..daf4a71d88 100644 --- a/frontend/services/gui/src/graph/Call.cpp +++ b/frontend/services/gui/src/graph/Call.cpp @@ -452,9 +452,9 @@ void megamol::gui::Call::draw_profiling_data() { std::transform(ch.begin(), ch.end(), ybuf.begin(), [](double d) -> float { return static_cast(d); }); auto Xhist_count = static_cast(ybuf.size()); - ImPlot::FitNextPlotAxes(); // no ImPlotAxisFlags_Lock - if (ImPlot::BeginPlot("CPU History", nullptr, nullptr, - ImVec2(ImGui::GetContentRegionAvail().x, (PROFILING_PLOT_HEIGHT * ImGui::GetFrameHeight())))) { + if (ImPlot::BeginPlot("CPU History", nullptr, "ms", + ImVec2(ImGui::GetContentRegionAvail().x, (PROFILING_PLOT_HEIGHT * ImGui::GetFrameHeight())), + ImPlotFlags_None, ImPlotAxisFlags_AutoFit)) { ImPlot::PlotLine("###cpuplot", xbuf.data(), ybuf.data(), Xhist_count); ImPlot::EndPlot(); } @@ -485,9 +485,9 @@ void megamol::gui::Call::draw_profiling_data() { const auto gh = this->profiling[i].hgpu; std::transform(gh.begin(), gh.end(), ybuf.begin(), [](double d) -> float { return static_cast(d); }); - ImPlot::FitNextPlotAxes(); - if (ImPlot::BeginPlot("GPU History", nullptr, nullptr, - ImVec2(ImGui::GetContentRegionAvail().x, (PROFILING_PLOT_HEIGHT * ImGui::GetFrameHeight())))) { + if (ImPlot::BeginPlot("GPU History", nullptr, "ms", + ImVec2(ImGui::GetContentRegionAvail().x, (PROFILING_PLOT_HEIGHT * ImGui::GetFrameHeight())), + ImPlotFlags_None, ImPlotAxisFlags_AutoFit)) { ImPlot::PlotLine("###gpuplot", xbuf.data(), ybuf.data(), Xhist_count); ImPlot::EndPlot(); } From 872d6339d1647c6934a3e46af56409f897e76a47 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 8 Sep 2021 17:33:24 +0200 Subject: [PATCH 30/47] ContextToGL event callback fix for context outslot --- core/include/mmcore/view/ContextToGL.h | 86 ++++++++++++++++++++------ 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/core/include/mmcore/view/ContextToGL.h b/core/include/mmcore/view/ContextToGL.h index 95dec5c714..c6152ed2f9 100644 --- a/core/include/mmcore/view/ContextToGL.h +++ b/core/include/mmcore/view/ContextToGL.h @@ -113,6 +113,72 @@ class ContextToGL : public Renderer3DModuleGL { */ virtual bool Render(CallRender3DGL& call); + bool OnChar(unsigned codePoint) override { + auto* ci = this->_getContextSlot.template CallAs(); + if (ci != nullptr) { + view::InputEvent evt; + evt.tag = view::InputEvent::Tag::Char; + evt.charData.codePoint = codePoint; + ci->SetInputEvent(evt); + return (*ci)(InputCall::FnOnChar); + } + return false; + } + + bool OnKey(Key key, KeyAction action, Modifiers mods) override { + auto* ci = this->_getContextSlot.template CallAs(); + if (ci != nullptr) { + view::InputEvent evt; + evt.tag = view::InputEvent::Tag::Key; + evt.keyData.key = key; + evt.keyData.action = action; + evt.keyData.mods = mods; + ci->SetInputEvent(evt); + return (*ci)(InputCall::FnOnKey); + } + return false; + } + + bool OnMouseButton(MouseButton button, MouseButtonAction action, Modifiers mods) override { + auto* ci = this->chainRenderSlot.template CallAs(); + if (ci != nullptr) { + view::InputEvent evt; + evt.tag = view::InputEvent::Tag::MouseButton; + evt.mouseButtonData.button = button; + evt.mouseButtonData.action = action; + evt.mouseButtonData.mods = mods; + ci->SetInputEvent(evt); + return (*ci)(InputCall::FnOnMouseButton); + } + return false; + } + + bool OnMouseMove(double x, double y) override { + auto* ci = this->chainRenderSlot.template CallAs(); + if (ci != nullptr) { + view::InputEvent evt; + evt.tag = view::InputEvent::Tag::MouseMove; + evt.mouseMoveData.x = x; + evt.mouseMoveData.y = y; + ci->SetInputEvent(evt); + return (*ci)(InputCall::FnOnMouseMove); + } + return false; + } + + bool OnMouseScroll(double dx, double dy) override { + auto* ci = this->chainRenderSlot.template CallAs(); + if (ci != nullptr) { + view::InputEvent evt; + evt.tag = view::InputEvent::Tag::MouseScroll; + evt.mouseScrollData.dx = dx; + evt.mouseScrollData.dy = dy; + ci->SetInputEvent(evt); + return (*ci)(InputCall::FnOnMouseScroll); + } + return false; + } + private: core::CallerSlot _getContextSlot; @@ -168,26 +234,6 @@ bool ContextToGL::Render(CallRender3DGL& ca viewport = {width, height}; } cr->SetFramebuffer(_framebuffer); - cr->SetInputEvent(call.GetInputEvent()); - - auto const& ie = cr->GetInputEvent(); - switch (ie.tag) { - case InputEvent::Tag::Char: { - (*cr)(CALL::FnOnChar); - } break; - case InputEvent::Tag::Key: { - (*cr)(CALL::FnOnKey); - } break; - case InputEvent::Tag::MouseButton: { - (*cr)(CALL::FnOnMouseButton); - } break; - case InputEvent::Tag::MouseMove: { - (*cr)(CALL::FnOnMouseMove); - } break; - case InputEvent::Tag::MouseScroll: { - (*cr)(CALL::FnOnMouseScroll); - } break; - } (*cr)(CALL::FnRender); From b542e7c1b84c6365358843cd5f7cc9d4e6b33a9e Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 8 Sep 2021 18:12:01 +0200 Subject: [PATCH 31/47] cleanup --- core/include/mmcore/PerformanceHistory.h | 11 ----------- core/src/Call.cpp | 2 +- core/src/CallProfiling.cpp | 2 -- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/core/include/mmcore/PerformanceHistory.h b/core/include/mmcore/PerformanceHistory.h index f96019542a..fce387dff8 100644 --- a/core/include/mmcore/PerformanceHistory.h +++ b/core/include/mmcore/PerformanceHistory.h @@ -19,17 +19,6 @@ class PerformanceHistory { double operator[](int index) const; double last_value() const { - // do we want to treat the special case? - //if (num_samples > 0) { - // return time_buffer[last_index]; - //} else { - // return std::numeric_limits::infinity(); - //} - - // or just like this... - //return time_buffer[last_index]; - - // or even better return time_buffer[offset(next_index, buffer_length - 1)]; } diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 9f99c743d7..c2cfc90ad9 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -19,7 +19,7 @@ #ifdef PROFILING # include "mmcore/view/Renderer3DModuleGL.h" # include "mmcore/view/Renderer2DModule.h" -#include "mmcore/CoreInstance.h" +# include "mmcore/CoreInstance.h" # include #endif #include "mmcore/utility/log/Log.h" diff --git a/core/src/CallProfiling.cpp b/core/src/CallProfiling.cpp index 234c3132b3..e5bb8763e3 100644 --- a/core/src/CallProfiling.cpp +++ b/core/src/CallProfiling.cpp @@ -80,8 +80,6 @@ std::array CallProfiling::GetGPUHisto } uint32_t CallProfiling::GetFuncCount() const { - /// XXX assert(last_cpu_time.size() == avg_cpu_time.size() == num_cpu_time_samples.size() == last_gpu_time.size() == - /// avg_gpu_time.size() == num_gpu_time_samples.size()); return static_cast(callback_names.size()); } From 06e2718b2513dc593fce48689e174de2e38ebd4d Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 9 Sep 2021 13:04:33 +0200 Subject: [PATCH 32/47] Profiling can be compiled out actually --- core/include/mmcore/Call.h | 14 +++++++++++--- core/include/mmcore/PerformanceQueryManager.h | 3 +-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index ecc3779a2c..345529284b 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -99,8 +99,16 @@ namespace core { return this->className; } + // TODO needs to be replaced by some CallAPICapabilities or something + bool UsesGL() { +#ifdef PROFILING + return uses_gl; +#else + return false; +#endif + } + #ifdef PROFILING - bool UsesGL() { return uses_gl; } const CallProfiling& GetProfiling() const { return profiling; } #endif @@ -127,9 +135,9 @@ namespace core { uses_gl = usesGL; profiling.setProfilingInfo(std::move(names), this); } - bool uses_gl = false; -#endif //PROFILING +#endif // PROFILING + }; diff --git a/core/include/mmcore/PerformanceQueryManager.h b/core/include/mmcore/PerformanceQueryManager.h index b83421818f..e5dbe4fd96 100644 --- a/core/include/mmcore/PerformanceQueryManager.h +++ b/core/include/mmcore/PerformanceQueryManager.h @@ -1,6 +1,5 @@ #pragma once -#ifdef PROFILING #include #include @@ -40,7 +39,7 @@ class PerformanceQueryManager { int32_t running_query = -1; }; -#endif } // namespace core } // namespace megamol + From 2198a987c76e5ec7637634e45ccad3d9a5a6f5e7 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 9 Sep 2021 13:42:14 +0200 Subject: [PATCH 33/47] I propose CallCapabilities --- core/include/mmcore/Call.h | 18 +++----- core/include/mmcore/CallCapabilities.h | 44 +++++++++++++++++++ core/include/mmcore/view/CallRender2DGL.h | 2 +- core/include/mmcore/view/CallRender3DGL.h | 2 +- core/src/Call.cpp | 9 ++-- core/src/CallCapabilities.cpp | 51 +++++++++++++++++++++++ core/src/CallProfiling.cpp | 4 +- core/src/MegaMolGraph.cpp | 7 +--- 8 files changed, 109 insertions(+), 28 deletions(-) create mode 100644 core/include/mmcore/CallCapabilities.h create mode 100644 core/src/CallCapabilities.cpp diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 345529284b..d600e5b269 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -13,6 +13,7 @@ #include #include +#include "CallCapabilities.h" #ifdef PROFILING #include "CallProfiling.h" #endif @@ -99,13 +100,8 @@ namespace core { return this->className; } - // TODO needs to be replaced by some CallAPICapabilities or something - bool UsesGL() { -#ifdef PROFILING - return uses_gl; -#else - return false; -#endif + const CallCapabilities& GetCapabilities() const { + return caps; } #ifdef PROFILING @@ -131,14 +127,12 @@ namespace core { CallProfiling profiling; - void setProfilingInfo(std::vector names, bool usesGL) { - uses_gl = usesGL; + void setProfilingInfo(std::vector names) { profiling.setProfilingInfo(std::move(names), this); } - bool uses_gl = false; #endif // PROFILING - - + protected: + CallCapabilities caps; }; diff --git a/core/include/mmcore/CallCapabilities.h b/core/include/mmcore/CallCapabilities.h new file mode 100644 index 0000000000..9994f12f69 --- /dev/null +++ b/core/include/mmcore/CallCapabilities.h @@ -0,0 +1,44 @@ +/* + * Call.h + * + * Copyright (C) 2021 by Universitaet Stuttgart (VIS). + * Alle Rechte vorbehalten. + */ + +#pragma once +#include + +namespace megamol { +namespace core { + + class CallCapabilities { + public: + enum caps { + REQUIRES_OPENGL = 1 << 0, + REQUIRES_CUDA = 1 << 1, + REQUIRES_OPENCL = 1 << 2, + REQUIRES_OPTIX = 1 << 3, + REQUIRES_OSPRAY = 1 << 4, + REQUIRES_VULKAN = 1 << 5 + }; + + void RequireOpenGL(); + void RequireCUDA(); + void RequireOpenCL(); + void RequireOptiX(); + void RequireOSPRay(); + void RequireVulkan(); + + bool OpenGLRequired() const; + bool CUDARequired() const; + bool OpenCLRequired() const; + bool OptiXRequired() const; + bool OSPRayRequired() const; + bool VulkanRequired() const; + + private: + uint64_t cap_bits = 0; + }; + +} +} diff --git a/core/include/mmcore/view/CallRender2DGL.h b/core/include/mmcore/view/CallRender2DGL.h index 22a8ef907b..9fa7ef0189 100644 --- a/core/include/mmcore/view/CallRender2DGL.h +++ b/core/include/mmcore/view/CallRender2DGL.h @@ -75,7 +75,7 @@ class CallRender2DGL : public CallRenderGL { } /** Ctor. */ - CallRender2DGL(void) = default; + CallRender2DGL(void) : CallRenderGL() { caps.RequireOpenGL(); } /** Dtor. */ virtual ~CallRender2DGL(void) = default; diff --git a/core/include/mmcore/view/CallRender3DGL.h b/core/include/mmcore/view/CallRender3DGL.h index 1d411021e9..797ce23c4b 100644 --- a/core/include/mmcore/view/CallRender3DGL.h +++ b/core/include/mmcore/view/CallRender3DGL.h @@ -58,7 +58,7 @@ class CallRender3DGL : public CallRenderGL { static const char* FunctionName(unsigned int idx) { return AbstractCallRender::FunctionName(idx); } /** Ctor. */ - CallRender3DGL(void) : CallRenderGL() { } + CallRender3DGL(void) : CallRenderGL() { caps.RequireOpenGL(); } /** Dtor. */ virtual ~CallRender3DGL(void) = default; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index c2cfc90ad9..5fe69aa109 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -61,10 +61,7 @@ bool Call::operator()(unsigned int func) { #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS auto f = this->callee->GetCallbackFuncName(func); auto parent = callee->Parent().get(); - auto p3 = dynamic_cast(parent); - auto p3_2 = dynamic_cast(parent); - auto p2 = dynamic_cast(parent); - if (p3 || p3_2 || p2) { + if (caps.OpenGLRequired()) { std::string output = dynamic_cast(parent)->ClassName(); output += "::"; output += f; @@ -75,7 +72,7 @@ bool Call::operator()(unsigned int func) { #ifdef PROFILING const auto startTime = std::chrono::high_resolution_clock::now(); bool gl_started = false; - if (uses_gl) { + if (caps.OpenGLRequired()) { gl_started = CallProfiling::qm->Start(this, this->callee->GetCoreInstance()->GetFrameID(), func); } #endif @@ -90,7 +87,7 @@ bool Call::operator()(unsigned int func) { #endif #ifdef RIG_RENDERCALLS_WITH_DEBUGGROUPS - if (p2 || p3 || p3_2) glPopDebugGroup(); + if (caps.OpenGLRequired()) glPopDebugGroup(); #endif } // megamol::core::utility::log::Log::DefaultLog.WriteInfo("calling %s, idx %i, result %s (%s)", this->ClassName(), func, diff --git a/core/src/CallCapabilities.cpp b/core/src/CallCapabilities.cpp new file mode 100644 index 0000000000..ffb67ee64a --- /dev/null +++ b/core/src/CallCapabilities.cpp @@ -0,0 +1,51 @@ +#include "mmcore/CallCapabilities.h" + +using namespace megamol::core; + +void CallCapabilities::RequireOpenGL() { + cap_bits |= REQUIRES_OPENGL; +} + +void CallCapabilities::RequireCUDA() { + cap_bits |= REQUIRES_CUDA; +} + +void CallCapabilities::RequireOpenCL() { + cap_bits |= REQUIRES_OPENCL; +} + +void CallCapabilities::RequireOptiX() { + cap_bits |= REQUIRES_OPTIX; +} + +void CallCapabilities::RequireOSPRay() { + cap_bits |= REQUIRES_OSPRAY; +} + +void CallCapabilities::RequireVulkan() { + cap_bits |= REQUIRES_VULKAN; +} + +bool CallCapabilities::OpenGLRequired() const { + return (cap_bits & REQUIRES_OPENGL) > 0; +} + +bool CallCapabilities::CUDARequired() const { + return (cap_bits & REQUIRES_CUDA) > 0; +} + +bool CallCapabilities::OpenCLRequired() const { + return (cap_bits & REQUIRES_OPENCL) > 0; +} + +bool CallCapabilities::OptiXRequired() const { + return (cap_bits & REQUIRES_OPTIX) > 0; +} + +bool CallCapabilities::OSPRayRequired() const { + return (cap_bits & REQUIRES_OSPRAY) > 0; +} + +bool CallCapabilities::VulkanRequired() const { + return (cap_bits & REQUIRES_VULKAN) > 0; +} diff --git a/core/src/CallProfiling.cpp b/core/src/CallProfiling.cpp index e5bb8763e3..382b002112 100644 --- a/core/src/CallProfiling.cpp +++ b/core/src/CallProfiling.cpp @@ -12,7 +12,7 @@ CallProfiling::CallProfiling() { } CallProfiling::~CallProfiling() { - if (parent_call->UsesGL()) { + if (parent_call->GetCapabilities().OpenGLRequired()) { qm->RemoveCall(parent_call); } } @@ -108,7 +108,7 @@ void CallProfiling::setProfilingInfo(std::vector names, Call* paren cpu_history.resize(callback_names.size()); gpu_history.resize(callback_names.size()); parent_call = parent; - if (parent_call->UsesGL()) { + if (parent_call->GetCapabilities().OpenGLRequired()) { InitializeQueryManager(); qm->AddCall(parent_call); } diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index 76d212cfdc..dab3ae91ad 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -366,12 +366,7 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req for (uint32_t x = 0; x < call_description->FunctionCount(); ++x) { callbacks[x] = call_description->FunctionName(x); } - // TODO if gl enabled, else both vars = false - const auto gl_1 = dynamic_cast(to_slot.second.get()); - const auto gl_2 = dynamic_cast(to_slot.second.get()); - // something like that would be nice but does not work - //const auto gl_3 = dynamic_cast>(to_slot.second.get()); - call->setProfilingInfo(callbacks, gl_1 || gl_2); + call->setProfilingInfo(callbacks); #endif log("create call: " + request.from + " -> " + request.to + " (" + std::string(call_description->ClassName()) + ")"); From b75874d3ecaab9ba29656ddae30672b325bf5623 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 9 Sep 2021 14:08:51 +0200 Subject: [PATCH 34/47] bug fixes --- core/include/mmcore/CallProfiling.h | 8 ++++++++ core/include/mmcore/view/CallRender2DGL.h | 2 +- core/include/mmcore/view/CallRender3DGL.h | 2 +- core/src/Call.cpp | 5 +++++ core/src/CallProfiling.cpp | 4 +--- core/src/PerformanceQueryManager.cpp | 1 + core/src/view/CallRenderGL.cpp | 2 +- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/core/include/mmcore/CallProfiling.h b/core/include/mmcore/CallProfiling.h index 0b0b2b5390..844fd11155 100644 --- a/core/include/mmcore/CallProfiling.h +++ b/core/include/mmcore/CallProfiling.h @@ -34,6 +34,8 @@ namespace core { uint32_t GetFuncCount() const; const std::string& GetFuncName(uint32_t i) const; + void ShutdownProfiling() const; + static void InitializeQueryManager(); static void CollectGPUPerformance(); @@ -51,5 +53,11 @@ namespace core { static std::string err_oob; }; + inline void CallProfiling::ShutdownProfiling() const { + if (qm != nullptr) { + qm->RemoveCall(parent_call); + } + } + } } diff --git a/core/include/mmcore/view/CallRender2DGL.h b/core/include/mmcore/view/CallRender2DGL.h index 9fa7ef0189..22a8ef907b 100644 --- a/core/include/mmcore/view/CallRender2DGL.h +++ b/core/include/mmcore/view/CallRender2DGL.h @@ -75,7 +75,7 @@ class CallRender2DGL : public CallRenderGL { } /** Ctor. */ - CallRender2DGL(void) : CallRenderGL() { caps.RequireOpenGL(); } + CallRender2DGL(void) = default; /** Dtor. */ virtual ~CallRender2DGL(void) = default; diff --git a/core/include/mmcore/view/CallRender3DGL.h b/core/include/mmcore/view/CallRender3DGL.h index 797ce23c4b..476e1995aa 100644 --- a/core/include/mmcore/view/CallRender3DGL.h +++ b/core/include/mmcore/view/CallRender3DGL.h @@ -58,7 +58,7 @@ class CallRender3DGL : public CallRenderGL { static const char* FunctionName(unsigned int idx) { return AbstractCallRender::FunctionName(idx); } /** Ctor. */ - CallRender3DGL(void) : CallRenderGL() { caps.RequireOpenGL(); } + CallRender3DGL(void) = default; /** Dtor. */ virtual ~CallRender3DGL(void) = default; diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 5fe69aa109..8827cd458e 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -38,6 +38,11 @@ Call::Call(void) : callee(nullptr), caller(nullptr), className(nullptr), funcMap * Call::~Call */ Call::~Call(void) { +#ifdef PROFILING + if (caps.OpenGLRequired()) { + profiling.ShutdownProfiling(); + } +#endif if (this->caller != nullptr) { CallerSlot* cr = this->caller; this->caller = nullptr; // DO NOT DELETE diff --git a/core/src/CallProfiling.cpp b/core/src/CallProfiling.cpp index 382b002112..e3d409b3c4 100644 --- a/core/src/CallProfiling.cpp +++ b/core/src/CallProfiling.cpp @@ -12,9 +12,7 @@ CallProfiling::CallProfiling() { } CallProfiling::~CallProfiling() { - if (parent_call->GetCapabilities().OpenGLRequired()) { - qm->RemoveCall(parent_call); - } + } uint32_t CallProfiling::GetSampleHistoryLength() { diff --git a/core/src/PerformanceQueryManager.cpp b/core/src/PerformanceQueryManager.cpp index bc02567007..099e58f9c4 100644 --- a/core/src/PerformanceQueryManager.cpp +++ b/core/src/PerformanceQueryManager.cpp @@ -42,6 +42,7 @@ void PerformanceQueryManager::ResetGLProfiling() { } void PerformanceQueryManager::AdvanceGLProfiling() { + if (all_calls.empty()) return; starting_func = (starting_func + 1) % all_calls[starting_call]->profiling.GetFuncCount(); if (starting_func == 0) { // we wrapped, advance to next call! diff --git a/core/src/view/CallRenderGL.cpp b/core/src/view/CallRenderGL.cpp index 77d6382a14..11462574bd 100644 --- a/core/src/view/CallRenderGL.cpp +++ b/core/src/view/CallRenderGL.cpp @@ -14,7 +14,7 @@ using namespace megamol::core; * view::CallRender3DGL::CallRender3DGL */ view::CallRenderGL::CallRenderGL(void) : AbstractCallRender() { - // intentionally empty + caps.RequireOpenGL(); } From cea528fa213d5b41ac23484f209d8e2a479737e7 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 9 Sep 2021 16:44:22 +0200 Subject: [PATCH 35/47] downgrade --- core/include/mmcore/PerformanceHistory.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/include/mmcore/PerformanceHistory.h b/core/include/mmcore/PerformanceHistory.h index fce387dff8..2a5a52b30f 100644 --- a/core/include/mmcore/PerformanceHistory.h +++ b/core/include/mmcore/PerformanceHistory.h @@ -1,14 +1,14 @@ #pragma once #include -#include +#include namespace megamol { namespace core { class PerformanceHistory { public: - static constexpr uint32_t buffer_length = 100; + static const uint32_t buffer_length = 100; PerformanceHistory(); From 4a84100442ac8ef7bad16e190d88e27841bef0bf Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 9 Sep 2021 17:17:53 +0200 Subject: [PATCH 36/47] cleanup --- core/include/mmcore/CallProfiling.h | 11 +++-------- core/src/CallProfiling.cpp | 9 ++++++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/core/include/mmcore/CallProfiling.h b/core/include/mmcore/CallProfiling.h index 844fd11155..128d474482 100644 --- a/core/include/mmcore/CallProfiling.h +++ b/core/include/mmcore/CallProfiling.h @@ -49,15 +49,10 @@ namespace core { std::vector gpu_history; std::vector callback_names; Call *parent_call = nullptr; - static PerformanceQueryManager *qm; - static std::string err_oob; + // this only works since the MegaMol build is static, otherwise a global round-robin could be a problem... + inline static PerformanceQueryManager *qm = nullptr; + inline const static std::string err_oob = "out of bounds"; }; - inline void CallProfiling::ShutdownProfiling() const { - if (qm != nullptr) { - qm->RemoveCall(parent_call); - } - } - } } diff --git a/core/src/CallProfiling.cpp b/core/src/CallProfiling.cpp index e3d409b3c4..ef7fe4ad91 100644 --- a/core/src/CallProfiling.cpp +++ b/core/src/CallProfiling.cpp @@ -4,9 +4,6 @@ using namespace megamol; using namespace core; -std::string CallProfiling::err_oob = "out of bounds"; -PerformanceQueryManager* CallProfiling::qm = nullptr; - CallProfiling::CallProfiling() { } @@ -111,3 +108,9 @@ void CallProfiling::setProfilingInfo(std::vector names, Call* paren qm->AddCall(parent_call); } } + +void CallProfiling::ShutdownProfiling() const { + if (qm != nullptr) { + qm->RemoveCall(parent_call); + } +} From f77c22ab24ba58af45921b249c52922ba79ce71c Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 9 Sep 2021 17:23:47 +0200 Subject: [PATCH 37/47] another cleanup --- core/src/MegaMolGraph.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index dab3ae91ad..5386355c3f 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -12,11 +12,6 @@ #include #include // std::accumulate -// TODO if GL enabled -#include "mmcore/view/Renderer2DModule.h" -#include "mmcore/view/Renderer3DModuleGL.h" -#include "mmcore/view/RendererModule.h" - // splits a string of the form "::one::two::three::" into an array of strings {"one", "two", "three"} static std::vector splitPathName(std::string const& path) { std::vector result; From 112af8f5eeb8eeda43c6d089863ea37da6327161 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 17 Sep 2021 17:55:18 +0200 Subject: [PATCH 38/47] fix merge --- frontend/services/gui/src/GUIManager.cpp | 4 ++-- frontend/services/gui/src/GUIManager.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/services/gui/src/GUIManager.cpp b/frontend/services/gui/src/GUIManager.cpp index f449e95f86..e9114b9528 100644 --- a/frontend/services/gui/src/GUIManager.cpp +++ b/frontend/services/gui/src/GUIManager.cpp @@ -331,14 +331,14 @@ bool GUIManager::PostDraw() { return false; } // Check for existing imgui context - if (this->context == nullptr) { + if (this->imgui_context == nullptr) { megamol::core::utility::log::Log::DefaultLog.WriteError( "[GUI] No valid ImGui context available. [%s, %s, line %d]\n", __FILE__, __FUNCTION__, __LINE__); return false; } // Set ImGui context - ImGui::SetCurrentContext(this->context); + ImGui::SetCurrentContext(this->imgui_context); ImGuiIO& io = ImGui::GetIO(); ImGuiStyle& style = ImGui::GetStyle(); diff --git a/frontend/services/gui/src/GUIManager.h b/frontend/services/gui/src/GUIManager.h index 974756b752..fef5cdf1ab 100644 --- a/frontend/services/gui/src/GUIManager.h +++ b/frontend/services/gui/src/GUIManager.h @@ -10,8 +10,8 @@ #pragma once -#include "implot.h" #include "CommandRegistry.h" +#include "implot.h" #include "mmcore/CoreInstance.h" #include "mmcore/MegaMolGraph.h" #include "mmcore/utility/Picking_gl.h" From 0e51270a958a4a9a82f7df93eb51aea4246a04a0 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 17 Sep 2021 18:16:46 +0200 Subject: [PATCH 39/47] callrenderviewgl caps --- core/src/view/CallRenderViewGL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/view/CallRenderViewGL.cpp b/core/src/view/CallRenderViewGL.cpp index 72eccb2f5f..108a1240b7 100644 --- a/core/src/view/CallRenderViewGL.cpp +++ b/core/src/view/CallRenderViewGL.cpp @@ -15,7 +15,7 @@ using namespace megamol::core; * view::CallRenderViewGL::CallRenderViewGL */ view::CallRenderViewGL::CallRenderViewGL(void) : AbstractCallRenderView() { - // intentionally empty + caps.RequireOpenGL(); } From 4f9b23db9a94c0546ce1aaed3e5d96e5e8604146 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 23 Sep 2021 14:39:58 +0200 Subject: [PATCH 40/47] move GPU performance collection to its own service. --- frontend/main/src/main.cpp | 7 ++++ frontend/services/CMakeLists.txt | 2 + .../opengl_glfw/OpenGL_GLFW_Service.cpp | 3 -- .../profiling_service/Profiling_Service.hpp | 39 +++++++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 frontend/services/profiling_service/Profiling_Service.hpp diff --git a/frontend/main/src/main.cpp b/frontend/main/src/main.cpp index 7ac969f086..e3832bee7b 100644 --- a/frontend/main/src/main.cpp +++ b/frontend/main/src/main.cpp @@ -21,6 +21,7 @@ #include "ProjectLoader_Service.hpp" #include "ImagePresentation_Service.hpp" #include "Remote_Service.hpp" +#include "Profiling_Service.hpp" #include /// XXX see temporary fix below @@ -129,6 +130,9 @@ int main(const int argc, const char** argv) { megamol::frontend::ImagePresentation_Service imagepresentation_service; megamol::frontend::ImagePresentation_Service::Config imagepresentationConfig; +#ifdef PROFILING + megamol::frontend::Profiling_Service profiling_service; +#endif imagepresentation_service.setPriority(3); // before render: do things after GL; post render: do things before GL megamol::frontend::Command_Service command_service; #ifdef MM_CUDA_ENABLED @@ -159,6 +163,9 @@ int main(const int argc, const char** argv) { services.add(projectloader_service, &projectloaderConfig); services.add(imagepresentation_service, &imagepresentationConfig); services.add(command_service, nullptr); +#ifdef PROFILING + services.add(profiling_service, nullptr); +#endif #ifdef MM_CUDA_ENABLED services.add(cuda_service, nullptr); #endif diff --git a/frontend/services/CMakeLists.txt b/frontend/services/CMakeLists.txt index ab13fea32b..7fa97b8fb8 100644 --- a/frontend/services/CMakeLists.txt +++ b/frontend/services/CMakeLists.txt @@ -31,6 +31,7 @@ if(BUILD_FRONTEND_SERVICES) "project_loader/*.hpp" "image_presentation/*.hpp" "remote_service/*.hpp" + "profiling_service/*.hpp" # "service_template/*.hpp" ) file(GLOB_RECURSE gui_header_files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "gui/*.h" "gui/*.hpp") @@ -65,6 +66,7 @@ if(BUILD_FRONTEND_SERVICES) "project_loader" "image_presentation" "remote_service" + "profiling_service" "gui/src" # "service_template" ) diff --git a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp index 397809f9ec..7869150c72 100644 --- a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp +++ b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp @@ -341,9 +341,6 @@ void megamol::frontend_resources::WindowManipulation::set_swap_interval(const un void megamol::frontend_resources::WindowManipulation::swap_buffers() const { glfwSwapBuffers(reinterpret_cast(window_ptr)); -#ifdef PROFILING - core::CallProfiling::CollectGPUPerformance(); -#endif PROFILING glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT); } diff --git a/frontend/services/profiling_service/Profiling_Service.hpp b/frontend/services/profiling_service/Profiling_Service.hpp new file mode 100644 index 0000000000..ccb5f04eec --- /dev/null +++ b/frontend/services/profiling_service/Profiling_Service.hpp @@ -0,0 +1,39 @@ +/* + * Screenshot_Service.hpp + * + * Copyright (C) 2020 by MegaMol Team + * Alle Rechte vorbehalten. + */ + +#pragma once + +#include "AbstractFrontendService.hpp" +#include "mmcore/CallProfiling.h" + +namespace megamol { +namespace frontend { + +class Profiling_Service final : public AbstractFrontendService { +public: + std::string serviceName() const override { return "Profiling_Service"; } + bool init(void* configPtr) override { return true;} + void close() override {} + void updateProvidedResources() override {} + void digestChangedRequestedResources() override {} + + void resetProvidedResources() override { + core::CallProfiling::CollectGPUPerformance(); + } + + void preGraphRender() override {} + void postGraphRender() override {} + std::vector& getProvidedResources() override { return m_providedResourceReferences; } + const std::vector getRequestedResourceNames() const override { return m_requestedResourcesNames; } + void setRequestedResources(std::vector resources) override {} + + std::vector m_providedResourceReferences; + std::vector m_requestedResourcesNames; +}; + +} // namespace frontend +} // namespace megamol From 4a55d0841b3025432ee3150d429df733d9b6c994 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 23 Sep 2021 18:00:37 +0200 Subject: [PATCH 41/47] cleanup --- core/include/mmcore/Call.h | 18 +++++--- core/include/mmcore/CallProfiling.h | 6 +-- .../mmcore/factories/CallAutoDescription.h | 8 ++++ core/src/Call.cpp | 16 ++++++- core/src/CallProfiling.cpp | 44 +++++++------------ core/src/MegaMolGraph.cpp | 9 ---- core/src/PerformanceQueryManager.cpp | 2 +- .../gui/src/graph/GraphCollection.cpp | 4 +- 8 files changed, 54 insertions(+), 53 deletions(-) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index d600e5b269..0bbcc90dde 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -104,12 +104,19 @@ namespace core { return caps; } + void SetCallbackNames(std::vector names); + + const std::string& GetCallbackName(uint32_t idx) const; + + uint32_t GetCallbackCount() const { + return static_cast(callback_names.size()); + } + #ifdef PROFILING const CallProfiling& GetProfiling() const { return profiling; } #endif private: - /** The callee connected by this call */ CalleeSlot *callee; @@ -121,15 +128,14 @@ namespace core { /** The function id mapping */ unsigned int *funcMap; + std::vector callback_names; + + inline static std::string err_out_of_bounds = "index out of bounds"; + #ifdef PROFILING - friend class MegaMolGraph; friend class PerformanceQueryManager; CallProfiling profiling; - - void setProfilingInfo(std::vector names) { - profiling.setProfilingInfo(std::move(names), this); - } #endif // PROFILING protected: CallCapabilities caps; diff --git a/core/include/mmcore/CallProfiling.h b/core/include/mmcore/CallProfiling.h index 128d474482..0e594f554b 100644 --- a/core/include/mmcore/CallProfiling.h +++ b/core/include/mmcore/CallProfiling.h @@ -31,8 +31,7 @@ namespace core { uint32_t GetNumGPUSamples(uint32_t func) const; std::array GetGPUHistory(uint32_t func) const; - uint32_t GetFuncCount() const; - const std::string& GetFuncName(uint32_t i) const; + void SetParent(Call *parent); void ShutdownProfiling() const; @@ -43,11 +42,8 @@ namespace core { friend class Call; friend class PerformanceQueryManager; - void setProfilingInfo(std::vector names, Call *parent); - std::vector cpu_history; std::vector gpu_history; - std::vector callback_names; Call *parent_call = nullptr; // this only works since the MegaMol build is static, otherwise a global round-robin could be a problem... inline static PerformanceQueryManager *qm = nullptr; diff --git a/core/include/mmcore/factories/CallAutoDescription.h b/core/include/mmcore/factories/CallAutoDescription.h index 2e5e8129a0..d5bc0f03d6 100644 --- a/core/include/mmcore/factories/CallAutoDescription.h +++ b/core/include/mmcore/factories/CallAutoDescription.h @@ -10,6 +10,9 @@ #include "CallDescription.h" +#include +#include + namespace megamol::core::factories { /** @@ -50,6 +53,11 @@ namespace megamol::core::factories { Call* CreateCall() const override { T* c = new T(); c->SetClassName(this->ClassName()); + std::vector callbacks(this->FunctionCount()); + for (uint32_t x = 0; x < this->FunctionCount(); ++x) { + callbacks[x] = this->FunctionName(x); + } + c->SetCallbackNames(callbacks); return this->describeCall(c); } diff --git a/core/src/Call.cpp b/core/src/Call.cpp index 80b8319b98..97a7f018c7 100644 --- a/core/src/Call.cpp +++ b/core/src/Call.cpp @@ -24,7 +24,6 @@ using namespace megamol::core; * Call::Call */ Call::Call(void) : callee(nullptr), caller(nullptr), className(nullptr), funcMap(nullptr) { - // intentionally empty } @@ -93,3 +92,18 @@ bool Call::operator()(unsigned int func) { // res ? "true" : "false", this->callee == nullptr ? "no callee" : "from callee"); return res; } + +void Call::SetCallbackNames(std::vector names) { + callback_names = std::move(names); +#ifdef PROFILING + profiling.SetParent(this); +#endif +} + +const std::string& Call::GetCallbackName(uint32_t idx) const { + if (idx < callback_names.size()) { + return callback_names[idx]; + } else { + return err_out_of_bounds; + } +} diff --git a/core/src/CallProfiling.cpp b/core/src/CallProfiling.cpp index ef7fe4ad91..8c07094473 100644 --- a/core/src/CallProfiling.cpp +++ b/core/src/CallProfiling.cpp @@ -5,7 +5,6 @@ using namespace megamol; using namespace core; CallProfiling::CallProfiling() { - } CallProfiling::~CallProfiling() { @@ -17,21 +16,21 @@ uint32_t CallProfiling::GetSampleHistoryLength() { } double CallProfiling::GetLastCPUTime(uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return cpu_history[func].last_value(); else return -1.0; } double CallProfiling::GetAverageCPUTime(uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return cpu_history[func].average(); else return -1.0; } uint32_t CallProfiling::GetNumCPUSamples(uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return cpu_history[func].samples(); else return 0; @@ -39,28 +38,28 @@ uint32_t CallProfiling::GetNumCPUSamples(uint32_t func) const { std::array CallProfiling::GetCPUHistory( uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return cpu_history[func].copyHistory(); else return std::array{}; } double CallProfiling::GetLastGPUTime(uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return gpu_history[func].last_value(); else return -1.0; } double CallProfiling::GetAverageGPUTime(uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return gpu_history[func].average(); else return -1.0; } uint32_t CallProfiling::GetNumGPUSamples(uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return gpu_history[func].samples(); else return 0; @@ -68,21 +67,19 @@ uint32_t CallProfiling::GetNumGPUSamples(uint32_t func) const { std::array CallProfiling::GetGPUHistory( uint32_t func) const { - if (func < callback_names.size()) + if (func < parent_call->GetCallbackCount()) return gpu_history[func].copyHistory(); else return std::array{}; } -uint32_t CallProfiling::GetFuncCount() const { - return static_cast(callback_names.size()); -} - -const std::string& CallProfiling::GetFuncName(uint32_t i) const { - if (i < callback_names.size()) { - return callback_names[i]; - } else { - return err_oob; +void CallProfiling::SetParent(Call* parent) { + cpu_history.resize(parent->GetCallbackCount()); + gpu_history.resize(parent->GetCallbackCount()); + parent_call = parent; + if (parent_call->GetCapabilities().OpenGLRequired()) { + InitializeQueryManager(); + qm->AddCall(parent_call); } } @@ -98,17 +95,6 @@ void CallProfiling::CollectGPUPerformance() { } } -void CallProfiling::setProfilingInfo(std::vector names, Call* parent) { - callback_names = std::move(names); - cpu_history.resize(callback_names.size()); - gpu_history.resize(callback_names.size()); - parent_call = parent; - if (parent_call->GetCapabilities().OpenGLRequired()) { - InitializeQueryManager(); - qm->AddCall(parent_call); - } -} - void CallProfiling::ShutdownProfiling() const { if (qm != nullptr) { qm->RemoveCall(parent_call); diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index d8d7e76265..2d86ff173d 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -633,15 +633,6 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req return false; } -#ifdef PROFILING - // TODO: move to CallAutoDescription::CreateCall() if possible - std::vector callbacks(call_description->FunctionCount()); - for (uint32_t x = 0; x < call_description->FunctionCount(); ++x) { - callbacks[x] = call_description->FunctionName(x); - } - call->setProfilingInfo(callbacks); -#endif - log("create call: " + request.from + " -> " + request.to + " (" + std::string(call_description->ClassName()) + ")"); this->call_list_.emplace_front(CallInstance_t{call, request}); diff --git a/core/src/PerformanceQueryManager.cpp b/core/src/PerformanceQueryManager.cpp index 099e58f9c4..1b9a3624e3 100644 --- a/core/src/PerformanceQueryManager.cpp +++ b/core/src/PerformanceQueryManager.cpp @@ -43,7 +43,7 @@ void PerformanceQueryManager::ResetGLProfiling() { void PerformanceQueryManager::AdvanceGLProfiling() { if (all_calls.empty()) return; - starting_func = (starting_func + 1) % all_calls[starting_call]->profiling.GetFuncCount(); + starting_func = (starting_func + 1) % all_calls[starting_call]->GetCallbackCount(); if (starting_func == 0) { // we wrapped, advance to next call! starting_call = (starting_call + 1) % all_calls.size(); diff --git a/frontend/services/gui/src/graph/GraphCollection.cpp b/frontend/services/gui/src/graph/GraphCollection.cpp index cfa06f75ed..85290d9458 100644 --- a/frontend/services/gui/src/graph/GraphCollection.cpp +++ b/frontend/services/gui/src/graph/GraphCollection.cpp @@ -647,7 +647,7 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( gui_utils::CaseInsensitiveStringCompare(gcall.from, ccall.request.from) && gui_utils::CaseInsensitiveStringCompare(gcall.to, ccall.request.to)) { const auto& profiling = ccall.callPtr->GetProfiling(); - auto func_count = profiling.GetFuncCount(); + auto func_count = ccall.callPtr->GetCallbackCount(); std::vector prof; prof.resize(func_count); for (uint32_t i = 0; i < func_count; i++) { @@ -659,7 +659,7 @@ bool megamol::gui::GraphCollection::add_update_project_from_core( prof[i].agput = profiling.GetAverageGPUTime(i); prof[i].ngpus = profiling.GetNumGPUSamples(i); prof[i].hgpu = profiling.GetGPUHistory(i); - prof[i].name = profiling.GetFuncName(i); + prof[i].name = ccall.callPtr->GetCallbackName(i); } gcall.ptr.lock()->SetProfilingValues(prof); } From 7640f09018611ae4a68fa04970c4502dd824e8f5 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 23 Sep 2021 18:34:48 +0200 Subject: [PATCH 42/47] GL caps restored --- core/include/mmcore/view/CallRender2DGL.h | 4 +++- core/include/mmcore/view/CallRender3DGL.h | 4 +++- core/include/mmcore/view/CallRenderViewGL.h | 18 ++++++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/core/include/mmcore/view/CallRender2DGL.h b/core/include/mmcore/view/CallRender2DGL.h index c78cb6deae..304ee2ba9d 100644 --- a/core/include/mmcore/view/CallRender2DGL.h +++ b/core/include/mmcore/view/CallRender2DGL.h @@ -42,7 +42,9 @@ namespace view { class CallRender2DGL : public BaseCallRender { public: /** Ctor. */ - CallRender2DGL(void) = default; + CallRender2DGL(void) : BaseCallRender() { + this->caps.RequireOpenGL(); + } /** Dtor. */ virtual ~CallRender2DGL(void) = default; diff --git a/core/include/mmcore/view/CallRender3DGL.h b/core/include/mmcore/view/CallRender3DGL.h index 7704c25d7e..15c6efed6f 100644 --- a/core/include/mmcore/view/CallRender3DGL.h +++ b/core/include/mmcore/view/CallRender3DGL.h @@ -35,7 +35,9 @@ namespace view { : public BaseCallRender { public: /** Ctor. */ - CallRender3DGL(void) = default; + CallRender3DGL(void) : BaseCallRender() { + this->caps.RequireOpenGL(); + } /** Dtor. */ virtual ~CallRender3DGL(void) = default; diff --git a/core/include/mmcore/view/CallRenderViewGL.h b/core/include/mmcore/view/CallRenderViewGL.h index b87bad5af3..ef7155973e 100644 --- a/core/include/mmcore/view/CallRenderViewGL.h +++ b/core/include/mmcore/view/CallRenderViewGL.h @@ -24,13 +24,23 @@ namespace view { /** * Call for rendering visual elements (from separate sources) into a single target, i.e., - * FBO-based compositing and cluster display. + * FBO-based compositing and cluster display. */ - using CallRenderViewGL = AbstractCallRenderView; + class CallRenderViewGL + : public AbstractCallRenderView { + public: + /** Ctor. */ + CallRenderViewGL(void) + : AbstractCallRenderView() { + this->caps.RequireOpenGL(); + } + + /** Dtor. */ + virtual ~CallRenderViewGL(void) = default; + }; /** Description class typedef */ - typedef factories::CallAutoDescription - CallRenderViewGLDescription; + typedef factories::CallAutoDescription CallRenderViewGLDescription; } /* end namespace view */ From 16a73a1d7523a8c4497109a115749caae9693a01 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 24 Sep 2021 09:27:10 +0200 Subject: [PATCH 43/47] includes and ifdefs--- --- core/include/mmcore/Call.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/include/mmcore/Call.h b/core/include/mmcore/Call.h index 0bbcc90dde..1d679a09db 100644 --- a/core/include/mmcore/Call.h +++ b/core/include/mmcore/Call.h @@ -12,7 +12,9 @@ #endif /* (defined(_MSC_VER) && (_MSC_VER > 1000)) */ #include +#include #include +#include #include "CallCapabilities.h" #ifdef PROFILING #include "CallProfiling.h" From c2b5cb2b1e36d1ed80a02cc57d11c1e27c4077ef Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 29 Sep 2021 18:39:39 +0200 Subject: [PATCH 44/47] cleanup --- frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp index 7869150c72..a95e28dbac 100644 --- a/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp +++ b/frontend/services/opengl_glfw/OpenGL_GLFW_Service.cpp @@ -41,10 +41,6 @@ #include #include -#ifdef PROFILING -#include -#include "mmcore/Call.h" -#endif #include "mmcore/utility/log/Log.h" static const std::string service_name = "OpenGL_GLFW_Service: "; From eac3795f478667303487bce61f2990dc87725991 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 30 Sep 2021 18:54:17 +0200 Subject: [PATCH 45/47] sneak in smaller screenies...? --- frontend/services/screenshot_service/Screenshot_Service.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/services/screenshot_service/Screenshot_Service.cpp b/frontend/services/screenshot_service/Screenshot_Service.cpp index ff960c9b05..881cd69f34 100644 --- a/frontend/services/screenshot_service/Screenshot_Service.cpp +++ b/frontend/services/screenshot_service/Screenshot_Service.cpp @@ -14,6 +14,7 @@ // to write png files #include "png.h" +#include "zlib.h" #include "mmcore/utility/graphics/ScreenShotComments.h" #include "vislib/sys/FastFile.h" @@ -93,7 +94,7 @@ static bool write_png_to_file(megamol::frontend_resources::ImageData const& imag png_set_write_fn(pngPtr, static_cast(&file), &pngWriteFileFunc, &pngFlushFileFunc); - png_set_compression_level(pngPtr, 0); + png_set_compression_level(pngPtr, Z_BEST_SPEED); // todo: camera settings are not stored without magic knowledge about the view std::string project = megamolgraph_ptr->Convenience().SerializeGraph(); From e2a3e93e3b3d4c398ea0d16cf98cc884404af8b6 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 1 Oct 2021 19:20:19 +0200 Subject: [PATCH 46/47] dangling deps tripping ninja --- externals/CMakeExternals.cmake | 3 +-- remoteconsole/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/externals/CMakeExternals.cmake b/externals/CMakeExternals.cmake index da9402ab4f..d0239a25f3 100644 --- a/externals/CMakeExternals.cmake +++ b/externals/CMakeExternals.cmake @@ -116,7 +116,6 @@ function(require_external NAME) endif() add_external_headeronly_project(libcxxopts - DEPENDS libzmq GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git # we are waiting for v3 which brings allowing unrecognized options #GIT_TAG "v2.1.1" @@ -575,7 +574,7 @@ function(require_external NAME) # libzmq / libcppzmq elseif(NAME STREQUAL "libzmq" OR NAME STREQUAL "libcppzmq") - if(TARGET libzmq) + if(TARGET libzmq OR TARGET libcppzmq) return() endif() diff --git a/remoteconsole/CMakeLists.txt b/remoteconsole/CMakeLists.txt index 598b8d3449..d80588c391 100644 --- a/remoteconsole/CMakeLists.txt +++ b/remoteconsole/CMakeLists.txt @@ -22,7 +22,7 @@ if(BUILD_REMOTECONSOLE) target_include_directories(${PROJECT_NAME} PUBLIC $ PUBLIC "include" "src") - target_link_libraries(${PROJECT_NAME} PRIVATE lua libzmq libcppzmq libcxxopts) + target_link_libraries(${PROJECT_NAME} PRIVATE libzmq libcppzmq libcxxopts) set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER base) source_group("Header Files" FILES ${header_files}) From ca80e1a56942716f89bd6d808433f6f016cd8dbb Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Mon, 4 Oct 2021 13:18:57 +0200 Subject: [PATCH 47/47] adapted ospray plugin readme to reflect TBB changes --- plugins/OSPRay_plugin/Readme.md | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/plugins/OSPRay_plugin/Readme.md b/plugins/OSPRay_plugin/Readme.md index ac3066df36..4c6bd9aa6e 100644 --- a/plugins/OSPRay_plugin/Readme.md +++ b/plugins/OSPRay_plugin/Readme.md @@ -13,26 +13,34 @@ The figure below shows a common OSPRay module call graph in MegaMol. ## Building [OSPRay](http://ospray.org) is not included in this package, however it is required for this plugin to be build. -The currently supported OSPRay versions are **2.4** and **2.5**. +The currently supported OSPRay versions are **2.4** through **2.7**. In order to get all dependencies installed at once, we strongly recommend to build [OSPRay](https://www.ospray.org/downloads.html) following the **CMake Superbuild** instructions. -The current dependencies are: [rekcommon](https://github.com/ospray/rkcommon), [openvkl](https://www.openvkl.org/), [ISPC](https://ispc.github.io/), [TBB](https://www.threadingbuildingblocks.org/) ([oneTBB](https://github.com/oneapi-src/oneTBB)), and [Embree](https://embree.github.io/). +The current dependencies are: [rkcommon](https://github.com/ospray/rkcommon), [openvkl](https://www.openvkl.org/), [ISPC](https://ispc.github.io/), [TBB](https://www.threadingbuildingblocks.org/) ([oneTBB](https://github.com/oneapi-src/oneTBB)), and [Embree](https://embree.github.io/). These need not be installed manually though (see below). *Installing the precompiled binaries is not sufficient!* -- Step 1: **OSPRay:** - - Download the source code to a new folder `git clone https://github.com/ospray/ospray.git ospray` and configure OSPRay with CMake using the CMake file located in `../scripts/superbuild`. - - In order to speed up the build process, uncheck the option `BUILD_EMBREE_FROM_SOURCE` since the binary version of Embree is sufficient. - - Build OSPRay following further instructions for the CMake Superbuild. - -- Step 2: **MegaMol:** +- Step 1: **MegaMol:** + - Build a vanilla MegaMol to provide its internal TBB for Step 2 +- Step 2: **OSPRay:** + - Download the source code to a new folder `git clone https://github.com/ospray/ospray.git ospray` and configure OSPRay with CMake using the CMake file located in `scripts/superbuild`. This automatically fetches the required dependencies. + - In order to speed up the build process, uncheck the option `BUILD_EMBREE_FROM_SOURCE` since the binary version of Embree is sufficient. + - Since MegaMol also uses TBB, you need to point OSPRay to the TBB inside the MegaMol build to avoid conflicts (in ```/_deps/tbb-install```) + - Build OSPRay following further instructions for the CMake Superbuild + - We have found the following to work quickest (on Windows, for Linux adapt the environment setting and slashes to ```export``` etc.): +```bash + set TBB_ROOT=\_deps\tbb-install + cmake -S scripts/superbuild -B build/super -D DOWNLOAD_TBB=false -D BUILD_EMBREE_FROM_SOURCE=false -D CMAKE_INSTALL_PREFIX=build/super/install -G Ninja + cmake --build build/super --config Release +``` + +- Step 3: **MegaMol:** - Make sure you enable the plugin in CMake by checking the option `BUILD_OSPRAY_PLUGIN_PLUGIN`. Either use `-DBUILD_OSPRAY_PLUGIN_PLUGIN` as configuration argument or use the graphical user interface `ccmake`. - If OSPRay is not automatically found during configuration of MegaMol, set the appropriate `ospray_DIR`. - *Hint:* The CMake configuration files of OSPRay are usually found in a subdirectory of the install directory: `../build/install/ospray/lib/cmake/...` + *Hint:* The CMake configuration files of OSPRay are usually found in a subdirectory of the install directory: `/install/ospray/lib/cmake/...` - CMake subsequently asks for the build files of the following dependencies: - - rkcommon: `../build/install/rkcommon/lib/cmake/...` - - TBB root directory: `../build/install/tbb` + - rkcommon: `/install/rkcommon/lib/cmake/...` - Build and install MegaMol. - - In order to test OSPRay, start MegaMol using the example project file `..build/install/examples/testspheres_ospray_megamol.lua`. + - In order to test OSPRay, start MegaMol using the example project file `/install/examples/testspheres_ospray_megamol.lua`. *Note:* On Linux, you have to run MegaMol using the `megamol.sh` script in order to additionally set the required path to the shared libraries of OSPRay. ## Modules