diff --git a/include/openspace/performance/performancelayout.h b/include/openspace/performance/performancelayout.h index 06104144db..2348d765b8 100644 --- a/include/openspace/performance/performancelayout.h +++ b/include/openspace/performance/performancelayout.h @@ -36,9 +36,7 @@ struct PerformanceLayout { static const int NumberValues = 256; static const int MaxValues = 256; - PerformanceLayout(int32_t nEntries); - - int32_t nEntries; + PerformanceLayout(); struct SceneGraphPerformanceLayout { char name[LengthName]; @@ -51,6 +49,7 @@ struct PerformanceLayout { int32_t currentUpdateEphemeris; }; SceneGraphPerformanceLayout sceneGraphEntries[MaxValues]; + int16_t nScaleGraphEntries; struct FunctionPerformanceLayout { char name[LengthName]; @@ -58,6 +57,7 @@ struct PerformanceLayout { int32_t currentTime; }; FunctionPerformanceLayout functionEntries[MaxValues]; + int16_t nFunctionEntries; }; } // namespace performance diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index d8e17aa4c6..c99538358b 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -26,6 +26,7 @@ #define __PERFORMANCEMANAGER_H__ #include +#include #include namespace ghoul { @@ -45,13 +46,18 @@ public: PerformanceManager(); ~PerformanceManager(); + void resetPerformanceMeasurements(); + bool isMeasuringPerformance() const; - void storeIndividualPerformanceMeasurement(std::string identifier, long long us); + void storeIndividualPerformanceMeasurement(std::string identifier, long long nanoseconds); void storeScenePerformanceMeasurements(const std::vector& sceneNodes); private: bool _doPerformanceMeasurements; + + std::map individualPerformanceLocations; + ghoul::SharedMemory* _performanceMemory; }; diff --git a/modules/onscreengui/src/guiperformancecomponent.cpp b/modules/onscreengui/src/guiperformancecomponent.cpp index d1be505f64..8193ec9657 100644 --- a/modules/onscreengui/src/guiperformancecomponent.cpp +++ b/modules/onscreengui/src/guiperformancecomponent.cpp @@ -65,100 +65,140 @@ void GuiPerformanceComponent::render() { ImGui::SliderFloat2("Min values, max Value", _minMaxValues, 0.f, 10000.f); _minMaxValues[1] = fmaxf(_minMaxValues[0], _minMaxValues[1]); - // The indices correspond to the index into the average array further below - ImGui::Text("Sorting"); - ImGui::RadioButton("No Sorting", &_sortingSelection, -1); - ImGui::RadioButton("UpdateEphemeris", &_sortingSelection, 0); - ImGui::RadioButton("UpdateRender", &_sortingSelection, 1); - ImGui::RadioButton("RenderTime", &_sortingSelection, 2); + if (ImGui::CollapsingHeader("SceneGraph")) { + // The indices correspond to the index into the average array further below + ImGui::Text("Sorting"); + ImGui::RadioButton("No Sorting", &_sortingSelection, -1); + ImGui::RadioButton("UpdateEphemeris", &_sortingSelection, 0); + ImGui::RadioButton("UpdateRender", &_sortingSelection, 1); + ImGui::RadioButton("RenderTime", &_sortingSelection, 2); - if (!_performanceMemory) - _performanceMemory = new ghoul::SharedMemory(PerformanceManager::PerformanceMeasurementSharedData); + if (!_performanceMemory) + _performanceMemory = new ghoul::SharedMemory(PerformanceManager::PerformanceMeasurementSharedData); - void* ptr = _performanceMemory->memory(); + void* ptr = _performanceMemory->memory(); - PerformanceLayout* layout = reinterpret_cast(ptr); + PerformanceLayout* layout = reinterpret_cast(ptr); - std::vector indices(layout->nEntries); - std::iota(indices.begin(), indices.end(), 0); + std::vector indices(layout->nScaleGraphEntries); + std::iota(indices.begin(), indices.end(), 0); - // Ordering: - // updateEphemeris - // UpdateRender - // RenderTime - std::vector> averages(layout->nEntries, { 0.f, 0.f, 0.f }); + // Ordering: + // updateEphemeris + // UpdateRender + // RenderTime + std::vector> averages(layout->nScaleGraphEntries, { 0.f, 0.f, 0.f }); - for (int i = 0; i < layout->nEntries; ++i) { - const PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[i]; + for (int i = 0; i < layout->nScaleGraphEntries; ++i) { + const PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[i]; - int v[3] = { 0, 0, 0 }; + int v[3] = { 0, 0, 0 }; - for (int j = 0; j < PerformanceLayout::NumberValues; ++j) { - averages[i][0] += entry.updateEphemeris[j]; - if (entry.updateEphemeris[j] != 0.f) - ++v[0]; - averages[i][1] += entry.updateRenderable[j]; - if (entry.updateRenderable[j] != 0.f) - ++v[1]; - averages[i][2] += entry.renderTime[j]; - if (entry.renderTime[j] != 0.f) - ++v[2]; + for (int j = 0; j < PerformanceLayout::NumberValues; ++j) { + averages[i][0] += entry.updateEphemeris[j]; + if (entry.updateEphemeris[j] != 0.f) + ++v[0]; + averages[i][1] += entry.updateRenderable[j]; + if (entry.updateRenderable[j] != 0.f) + ++v[1]; + averages[i][2] += entry.renderTime[j]; + if (entry.renderTime[j] != 0.f) + ++v[2]; + } + + if (v[0] != 0) + averages[i][0] /= static_cast(v[0]); + if (v[1] != 0) + averages[i][1] /= static_cast(v[1]); + if (v[2] != 0) + averages[i][2] /= static_cast(v[2]); } - if (v[0] != 0) - averages[i][0] /= static_cast(v[0]); - if (v[1] != 0) - averages[i][1] /= static_cast(v[1]); - if (v[2] != 0) - averages[i][2] /= static_cast(v[2]); - } + if (_sortingSelection != -1) { + int sortIndex = _sortingSelection; - if (_sortingSelection != -1) { - int sortIndex = _sortingSelection; + std::sort( + indices.begin(), + indices.end(), + [sortIndex, &averages](size_t a, size_t b) { + return averages[a][sortIndex] > averages[b][sortIndex]; + } + ); - std::sort( - indices.begin(), - indices.end(), - [sortIndex, &averages](size_t a, size_t b) { - return averages[a][sortIndex] > averages[b][sortIndex]; + } + + for (int i = 0; i < layout->nScaleGraphEntries; ++i) { + const PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[indices[i]]; + + if (ImGui::CollapsingHeader(entry.name)) { + std::string updateEphemerisTime = std::to_string(entry.updateEphemeris[entry.currentUpdateEphemeris - 1]) + "us"; + ; + ImGui::PlotLines( + fmt::format("UpdateEphemeris\nAverage: {}us", averages[i][0]).c_str(), + &entry.updateEphemeris[0], + PerformanceLayout::NumberValues, + 0, + updateEphemerisTime.c_str(), + _minMaxValues[0], + _minMaxValues[1], + ImVec2(0, 40) + ); + + std::string updateRenderableTime = std::to_string(entry.updateRenderable[entry.currentUpdateRenderable - 1]) + "us"; + ImGui::PlotLines( + fmt::format("UpdateRender\nAverage: {}us", averages[i][1]).c_str(), + &entry.updateRenderable[0], + PerformanceLayout::NumberValues, + 0, + updateRenderableTime.c_str(), + _minMaxValues[0], + _minMaxValues[1], + ImVec2(0, 40) + ); + + std::string renderTime = std::to_string(entry.renderTime[entry.currentRenderTime - 1]) + "us"; + ImGui::PlotLines( + fmt::format("RenderTime\nAverage: {}us", averages[i][2]).c_str(), + &entry.renderTime[0], + PerformanceLayout::NumberValues, + 0, + renderTime.c_str(), + _minMaxValues[0], + _minMaxValues[1], + ImVec2(0, 40) + ); } - ); - + } } + + if (ImGui::CollapsingHeader("Functions")) { + using namespace performance; + + if (!_performanceMemory) + _performanceMemory = new ghoul::SharedMemory(PerformanceManager::PerformanceMeasurementSharedData); + + void* ptr = _performanceMemory->memory(); + + PerformanceLayout* layout = reinterpret_cast(ptr); - for (int i = 0; i < layout->nEntries; ++i) { - const PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[indices[i]]; - - if (ImGui::CollapsingHeader(entry.name)) { - std::string updateEphemerisTime = std::to_string(entry.updateEphemeris[entry.currentUpdateEphemeris - 1]) + "us"; - ; + for (int i = 0; i < layout->nFunctionEntries; ++i) { + const PerformanceLayout::FunctionPerformanceLayout& entry = layout->functionEntries[i]; + + float avg = 0.f; + int count = 0; + for (int j = 0; j < PerformanceLayout::NumberValues; ++j) { + avg += layout->functionEntries[i].time[j]; + if (layout->functionEntries[i].time[j] != 0.f) + ++count; + } + avg /= count; + + const PerformanceLayout::FunctionPerformanceLayout& f = layout->functionEntries[i]; + + std::string renderTime = std::to_string(entry.time[entry.currentTime - 1]) + "us"; ImGui::PlotLines( - fmt::format("UpdateEphemeris\nAverage: {}us", averages[i][0]).c_str(), - &entry.updateEphemeris[0], - PerformanceLayout::NumberValues, - 0, - updateEphemerisTime.c_str(), - _minMaxValues[0], - _minMaxValues[1], - ImVec2(0, 40) - ); - - std::string updateRenderableTime = std::to_string(entry.updateRenderable[entry.currentUpdateRenderable - 1]) + "us"; - ImGui::PlotLines( - fmt::format("UpdateRender\nAverage: {}us", averages[i][1]).c_str(), - &entry.updateRenderable[0], - PerformanceLayout::NumberValues, - 0, - updateRenderableTime.c_str(), - _minMaxValues[0], - _minMaxValues[1], - ImVec2(0, 40) - ); - - std::string renderTime = std::to_string(entry.renderTime[entry.currentRenderTime - 1]) + "us"; - ImGui::PlotLines( - fmt::format("RenderTime\nAverage: {}us", averages[i][2]).c_str(), - &entry.renderTime[0], + fmt::format("{}\nAverage: {}us", entry.name, avg).c_str(), + &entry.time[0], PerformanceLayout::NumberValues, 0, renderTime.c_str(), @@ -167,6 +207,7 @@ void GuiPerformanceComponent::render() { ImVec2(0, 40) ); } + } } else { diff --git a/src/performance/performancehelper.cpp b/src/performance/performancehelper.cpp index 2858b3a91c..5bf6593912 100644 --- a/src/performance/performancehelper.cpp +++ b/src/performance/performancehelper.cpp @@ -36,9 +36,11 @@ PerformanceHelper::PerformanceHelper(std::string identifier, : _identifier(std::move(identifier)) , _manager(manager) { - glFinish(); + if (_manager) { + glFinish(); - _startTime = std::chrono::high_resolution_clock::now(); + _startTime = std::chrono::high_resolution_clock::now(); + } } PerformanceHelper::~PerformanceHelper() { @@ -46,7 +48,9 @@ PerformanceHelper::~PerformanceHelper() { auto duration = std::chrono::duration_cast( endTime - _startTime).count(); - _manager->storeIndividualPerformanceMeasurement(std::move(_identifier), duration); + if (_manager) { + _manager->storeIndividualPerformanceMeasurement(std::move(_identifier), duration); + } } diff --git a/src/performance/performancelayout.cpp b/src/performance/performancelayout.cpp index 803a577443..5856f9f7e4 100644 --- a/src/performance/performancelayout.cpp +++ b/src/performance/performancelayout.cpp @@ -29,8 +29,9 @@ namespace openspace { namespace performance { -PerformanceLayout::PerformanceLayout(int32_t nEntries) - : nEntries(nEntries) +PerformanceLayout::PerformanceLayout() + : nScaleGraphEntries(0) + , nFunctionEntries(0) { std::memset( sceneGraphEntries, diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index bb27fdc626..c7e7c2645b 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -43,6 +43,23 @@ const std::string PerformanceManager::PerformanceMeasurementSharedData = PerformanceManager::PerformanceManager() : _performanceMemory(nullptr) { + // Compute the total size + const int totalSize = sizeof(PerformanceLayout); + LINFO("Create shared memory of " << totalSize << " bytes"); + + try { + ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); + } + catch (const ghoul::SharedMemory::SharedMemoryError& e) { + LINFOC(e.component, e.what()); + } + + ghoul::SharedMemory::create(PerformanceMeasurementSharedData, totalSize); + _performanceMemory = new ghoul::SharedMemory(PerformanceMeasurementSharedData); + void* ptr = _performanceMemory->memory(); + + // Using the placement-new to create a PerformanceLayout in the shared memory + PerformanceLayout* layout = new (ptr) PerformanceLayout; } PerformanceManager::~PerformanceManager() { @@ -50,12 +67,47 @@ PerformanceManager::~PerformanceManager() { ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); } +void PerformanceManager::resetPerformanceMeasurements() { + // Using the placement-new to create a PerformanceLayout in the shared memory + _performanceMemory->acquireLock(); + void* ptr = _performanceMemory->memory(); + new (ptr) PerformanceLayout; + _performanceMemory->releaseLock(); + + individualPerformanceLocations.clear(); +} + bool PerformanceManager::isMeasuringPerformance() const { return _doPerformanceMeasurements; } -void PerformanceManager::storeIndividualPerformanceMeasurement(std::string identifier, long long us) { +void PerformanceManager::storeIndividualPerformanceMeasurement + (std::string identifier, long long microseconds) +{ + void* ptr = _performanceMemory->memory(); + PerformanceLayout* layout = reinterpret_cast(ptr); + _performanceMemory->acquireLock(); + auto it = individualPerformanceLocations.find(identifier); + PerformanceLayout::FunctionPerformanceLayout* p = nullptr; + if (it == individualPerformanceLocations.end()) { + p = &(layout->functionEntries[layout->nFunctionEntries]); + individualPerformanceLocations[identifier] = layout->nFunctionEntries; + ++(layout->nFunctionEntries); + } + else { + p = &(layout->functionEntries[it->second]); + } +#ifdef _MSC_VER + strcpy_s(p->name, identifier.length() + 1, identifier.c_str()); +#else + strcpy(p->name, identifier.c_str()); +#endif + + p->time[p->currentTime] = static_cast(microseconds); + p->currentTime = (p->currentTime + 1) % PerformanceLayout::NumberValues; + + _performanceMemory->releaseLock(); } void PerformanceManager::storeScenePerformanceMeasurements( @@ -63,47 +115,22 @@ void PerformanceManager::storeScenePerformanceMeasurements( { using namespace performance; - int nNodes = static_cast(sceneNodes.size()); - if (!_performanceMemory) { - // Compute the total size - const int totalSize = sizeof(PerformanceLayout); - LINFO("Create shared memory of " << totalSize << " bytes"); - - try { - ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); - } - catch (const ghoul::SharedMemory::SharedMemoryError& e) { - LINFOC(e.component, e.what()); - } - - ghoul::SharedMemory::create(PerformanceMeasurementSharedData, totalSize); - _performanceMemory = new ghoul::SharedMemory(PerformanceMeasurementSharedData); - void* ptr = _performanceMemory->memory(); - - // Using the placement-new to create a PerformanceLayout in the shared memory - PerformanceLayout* layout = new (ptr) PerformanceLayout(nNodes); - - for (int i = 0; i < nNodes; ++i) { - SceneGraphNode* node = sceneNodes[i]; - - memset(layout->sceneGraphEntries[i].name, 0, PerformanceLayout::LengthName); -#ifdef _MSC_VER - strcpy_s(layout->sceneGraphEntries[i].name, node->name().length() + 1, node->name().c_str()); -#else - strcpy(layout->sceneGraphEntries[i].name, node->name().c_str()); -#endif - - layout->sceneGraphEntries[i].currentRenderTime = 0; - layout->sceneGraphEntries[i].currentUpdateRenderable = 0; - layout->sceneGraphEntries[i].currentUpdateEphemeris = 0; - } - } - void* ptr = _performanceMemory->memory(); PerformanceLayout* layout = reinterpret_cast(ptr); _performanceMemory->acquireLock(); + + int nNodes = static_cast(sceneNodes.size()); + layout->nScaleGraphEntries = nNodes; for (int i = 0; i < nNodes; ++i) { SceneGraphNode* node = sceneNodes[i]; + + memset(layout->sceneGraphEntries[i].name, 0, PerformanceLayout::LengthName); +#ifdef _MSC_VER + strcpy_s(layout->sceneGraphEntries[i].name, node->name().length() + 1, node->name().c_str()); +#else + strcpy(layout->sceneGraphEntries[i].name, node->name().c_str()); +#endif + SceneGraphNode::PerformanceRecord r = node->performanceRecord(); PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[i];