diff --git a/ext/ghoul b/ext/ghoul index 3034cb3d3e..111c53c94c 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 3034cb3d3ebe8474e21fe2bb8e4e6cc275213b63 +Subproject commit 111c53c94cfe514122a71225bb9e903f0a367278 diff --git a/include/openspace/performance/performancelayout.h b/include/openspace/performance/performancelayout.h new file mode 100644 index 0000000000..70568e67e5 --- /dev/null +++ b/include/openspace/performance/performancelayout.h @@ -0,0 +1,61 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __PERFORMANCELAYOUT_H__ +#define __PERFORMANCELAYOUT_H__ + +#include + +namespace openspace { +namespace performance { + +struct PerformanceLayout { + static const int8_t Version = 0; + static const int LengthName = 256; + static const int NumberValues = 256; + static const int MaxValues = 256; + + PerformanceLayout(); + + struct SceneGraphPerformanceLayout { + char name[LengthName]; + float renderTime[NumberValues]; + float updateRenderable[NumberValues]; + float updateEphemeris[NumberValues]; + }; + SceneGraphPerformanceLayout sceneGraphEntries[MaxValues]; + int16_t nScaleGraphEntries; + + struct FunctionPerformanceLayout { + char name[LengthName]; + float time[NumberValues]; + }; + FunctionPerformanceLayout functionEntries[MaxValues]; + int16_t nFunctionEntries; +}; + +} // namespace performance +} // namespace openspace + +#endif // __PERFORMANCELAYOUT_H__ diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h new file mode 100644 index 0000000000..c99538358b --- /dev/null +++ b/include/openspace/performance/performancemanager.h @@ -0,0 +1,67 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __PERFORMANCEMANAGER_H__ +#define __PERFORMANCEMANAGER_H__ + +#include +#include +#include + +namespace ghoul { + class SharedMemory; +} + +namespace openspace { + +class SceneGraphNode; + +namespace performance { + +class PerformanceManager { +public: + static const std::string PerformanceMeasurementSharedData; + + PerformanceManager(); + ~PerformanceManager(); + + void resetPerformanceMeasurements(); + + bool isMeasuringPerformance() const; + + void storeIndividualPerformanceMeasurement(std::string identifier, long long nanoseconds); + void storeScenePerformanceMeasurements(const std::vector& sceneNodes); + +private: + bool _doPerformanceMeasurements; + + std::map individualPerformanceLocations; + + ghoul::SharedMemory* _performanceMemory; +}; + +} // namespace performance +} // namespace openspace + +#endif // __PERFORMANCEMANAGER_H__ diff --git a/include/openspace/performance/performancemeasurement.h b/include/openspace/performance/performancemeasurement.h new file mode 100644 index 0000000000..f08dbb94b2 --- /dev/null +++ b/include/openspace/performance/performancemeasurement.h @@ -0,0 +1,57 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __PERFORMANCEMEASUREMENT_H__ +#define __PERFORMANCEMEASUREMENT_H__ + +#include +#include + +namespace openspace { +namespace performance { + +class PerformanceManager; + +class PerformanceMeasurement { +public: + PerformanceMeasurement(std::string identifier, performance::PerformanceManager* manager); + ~PerformanceMeasurement(); + +private: + std::string _identifier; + performance::PerformanceManager* _manager; + + std::chrono::high_resolution_clock::time_point _startTime; +}; + +#define __MERGE(a,b) a##b +#define __LABEL(a) __MERGE(unique_name_, a) + +/// Declare a new variable for measuring the performance of the current block +#define PerfMeasure(name) auto __LABEL(__LINE__) = openspace::performance::PerformanceMeasurement((name), OsEng.renderEngine().performanceManager()) + +} // namespace performance +} // namespace openspace + +#endif // __PERFORMANCEMEASUREMENTHELPER_H__ diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 913ccd9c82..14c666eda7 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -31,6 +31,7 @@ #include #include +#include namespace ghoul { namespace fontrendering { @@ -67,9 +68,6 @@ public: Post }; - - static const std::string PerformanceMeasurementSharedData; - static const std::string KeyFontMono; static const std::string KeyFontLight; @@ -97,8 +95,10 @@ public: void takeScreenshot(); void toggleInfoText(bool b); + // Performance measurements void setPerformanceMeasurements(bool performanceMeasurements); bool doesPerformanceMeasurements() const; + performance::PerformanceManager* performanceManager(); void serialize(SyncBuffer* syncBuffer); void deserialize(SyncBuffer* syncBuffer); @@ -178,7 +178,7 @@ public: private: void setRenderer(std::unique_ptr renderer); RendererImplementation rendererFromString(const std::string& method); - void storePerformanceMeasurements(); + void renderInformation(); void renderScreenLog(); @@ -186,6 +186,8 @@ private: Scene* _sceneGraph; RaycasterManager* _raycasterManager; + std::unique_ptr _performanceManager; + std::unique_ptr _renderer; RendererImplementation _rendererImplementation; ghoul::Dictionary _rendererData; @@ -196,9 +198,6 @@ private: bool _showLog; bool _takeScreenshot; - bool _doPerformanceMeasurements; - ghoul::SharedMemory* _performanceMemory; - float _globalBlackOutFactor; float _fadeDuration; float _currentFadeTime; diff --git a/include/openspace/util/screenlog.h b/include/openspace/util/screenlog.h index 01c9e9283e..afeaf2ecc2 100644 --- a/include/openspace/util/screenlog.h +++ b/include/openspace/util/screenlog.h @@ -22,6 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#ifndef __SCREENLOG_H__ +#define __SCREENLOG_H__ + #include #include @@ -110,4 +113,6 @@ private: LogLevel _logLevel; }; -} // namespace openspace \ No newline at end of file +} // namespace openspace + +#endif // __SCREENLOG_H__ diff --git a/include/openspace/util/transformationmanager.h b/include/openspace/util/transformationmanager.h index 2443004852..0bbe37c459 100644 --- a/include/openspace/util/transformationmanager.h +++ b/include/openspace/util/transformationmanager.h @@ -33,9 +33,12 @@ #include +namespace ccmc { + class Kameleon; +} // namespace ccmc + namespace openspace { #ifdef OPENSPACE_MODULE_KAMELEON_ENABLED -class ccmc::Kameleon; #endif class TransformationManager : public ghoul::Singleton { friend class ghoul::Singleton; diff --git a/modules/onscreengui/include/guiperformancecomponent.h b/modules/onscreengui/include/guiperformancecomponent.h index f7fde598ac..882c277fe4 100644 --- a/modules/onscreengui/include/guiperformancecomponent.h +++ b/modules/onscreengui/include/guiperformancecomponent.h @@ -43,8 +43,10 @@ public: protected: ghoul::SharedMemory* _performanceMemory = nullptr; - float _minMaxValues[2]; int _sortingSelection; + + bool _sceneGraphIsEnabled; + bool _functionsIsEnabled; }; } // namespace gui diff --git a/modules/onscreengui/src/guiperformancecomponent.cpp b/modules/onscreengui/src/guiperformancecomponent.cpp index 57bc4ab20b..0bd4511ab3 100644 --- a/modules/onscreengui/src/guiperformancecomponent.cpp +++ b/modules/onscreengui/src/guiperformancecomponent.cpp @@ -25,7 +25,10 @@ #include #include +#include +#include #include + #include #include @@ -42,9 +45,10 @@ namespace openspace { namespace gui { void GuiPerformanceComponent::initialize() { - _minMaxValues[0] = 100.f; - _minMaxValues[1] = 250.f; _sortingSelection = -1; + + _sceneGraphIsEnabled = false; + _functionsIsEnabled = false; } void GuiPerformanceComponent::deinitialize() { @@ -53,143 +57,208 @@ void GuiPerformanceComponent::deinitialize() { } void GuiPerformanceComponent::render() { - // Copy and paste from renderengine.cpp::storePerformanceMeasurements method -// const int8_t Version = 0; - const int nValues = 250; - const int lengthName = 256; - const int maxValues = 256; - - struct PerformanceLayout { - int8_t version; - int32_t nValuesPerEntry; - int32_t nEntries; - int32_t maxNameLength; - int32_t maxEntries; - - struct PerformanceLayoutEntry { - char name[lengthName]; - float renderTime[nValues]; - float updateRenderable[nValues]; - float updateEphemeris[nValues]; - - int32_t currentRenderTime; - int32_t currentUpdateRenderable; - int32_t currentUpdateEphemeris; - }; - - PerformanceLayoutEntry entries[maxValues]; - }; + using namespace performance; ImGui::Begin("Performance", &_isEnabled); if (OsEng.renderEngine().doesPerformanceMeasurements() && - ghoul::SharedMemory::exists(RenderEngine::PerformanceMeasurementSharedData)) + ghoul::SharedMemory::exists(PerformanceManager::PerformanceMeasurementSharedData)) { - ImGui::SliderFloat2("Min values, max Value", _minMaxValues, 0.f, 10000.f); - _minMaxValues[1] = fmaxf(_minMaxValues[0], _minMaxValues[1]); + ImGui::Checkbox("SceneGraph", &_sceneGraphIsEnabled); + ImGui::Checkbox("Functions", &_functionsIsEnabled); - // 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); + ImGui::Spacing(); + + if (ImGui::Button("Reset measurements")) { + OsEng.renderEngine().performanceManager()->resetPerformanceMeasurements(); + } + + if (_sceneGraphIsEnabled) { + ImGui::Begin("SceneGraph", &_sceneGraphIsEnabled); + + // 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(RenderEngine::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->nScaleGraphEntries); + std::iota(indices.begin(), indices.end(), 0); - std::vector indices(layout.nEntries); - std::iota(indices.begin(), indices.end(), 0); + // Ordering: + // updateEphemeris + // UpdateRender + // RenderTime + std::vector> averages(layout->nScaleGraphEntries, { 0.f, 0.f, 0.f }); + + std::vector, 3>> minMax( + layout->nScaleGraphEntries + ); + + for (int i = 0; i < layout->nScaleGraphEntries; ++i) { + const PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[i]; - // Ordering: - // updateEphemeris - // UpdateRender - // RenderTime - std::vector> averages(layout.nEntries, { 0.f, 0.f, 0.f }); + int v[3] = { 0, 0, 0 }; - for (int i = 0; i < layout.nEntries; ++i) { - const PerformanceLayout::PerformanceLayoutEntry& entry = layout.entries[i]; + 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]); + } - int v[3] = { 0, 0, 0 }; + 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]); + + auto minmaxEphemeris = std::minmax_element( + std::begin(entry.updateEphemeris), + std::end(entry.updateEphemeris) + ); + minMax[i][0] = std::make_pair( + *(minmaxEphemeris.first), + *(minmaxEphemeris.second) + ); + + + auto minmaxUpdateRenderable = std::minmax_element( + std::begin(entry.updateRenderable), + std::end(entry.updateRenderable) + ); + minMax[i][1] = std::make_pair( + *(minmaxUpdateRenderable.first), + *(minmaxUpdateRenderable.second) + ); + + + auto minmaxRendering = std::minmax_element( + std::begin(entry.renderTime), + std::end(entry.renderTime) + ); + minMax[i][2] = std::make_pair( + *(minmaxRendering.first), + *(minmaxRendering.second) + ); + - for (int j = 0; j < nValues; ++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 (_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[PerformanceLayout::NumberValues - 1]) + "us"; + ; + ImGui::PlotLines( + fmt::format("UpdateEphemeris\nAverage: {}us", averages[indices[i]][0]).c_str(), + &entry.updateEphemeris[0], + PerformanceLayout::NumberValues, + 0, + updateEphemerisTime.c_str(), + minMax[indices[i]][0].first, + minMax[indices[i]][0].second, + ImVec2(0, 40) + ); + + std::string updateRenderableTime = std::to_string(entry.updateRenderable[PerformanceLayout::NumberValues - 1]) + "us"; + ImGui::PlotLines( + fmt::format("UpdateRender\nAverage: {}us", averages[indices[i]][1]).c_str(), + &entry.updateRenderable[0], + PerformanceLayout::NumberValues, + 0, + updateRenderableTime.c_str(), + minMax[indices[i]][1].first, + minMax[indices[i]][1].second, + ImVec2(0, 40) + ); + + std::string renderTime = std::to_string(entry.renderTime[PerformanceLayout::NumberValues - 1]) + "us"; + ImGui::PlotLines( + fmt::format("RenderTime\nAverage: {}us", averages[indices[i]][2]).c_str(), + &entry.renderTime[0], + PerformanceLayout::NumberValues, + 0, + renderTime.c_str(), + minMax[indices[i]][2].first, + minMax[indices[i]][2].second, + ImVec2(0, 40) + ); } - ); - + } + ImGui::End(); } + + if (_functionsIsEnabled) { + ImGui::Begin("Functions", &_functionsIsEnabled); + 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::PerformanceLayoutEntry& entry = layout.entries[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], - layout.nValuesPerEntry, - 0, - updateEphemerisTime.c_str(), - _minMaxValues[0], - _minMaxValues[1], - ImVec2(0, 40) + 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; + + auto minmax = std::minmax_element( + std::begin(layout->functionEntries[i].time), + std::end(layout->functionEntries[i].time) ); - - std::string updateRenderableTime = std::to_string(entry.updateRenderable[entry.currentUpdateRenderable - 1]) + "us"; + + const PerformanceLayout::FunctionPerformanceLayout& f = layout->functionEntries[i]; + + std::string renderTime = std::to_string(entry.time[PerformanceLayout::NumberValues - 1]) + "us"; ImGui::PlotLines( - fmt::format("UpdateRender\nAverage: {}us", averages[i][1]).c_str(), - &entry.updateRenderable[0], - layout.nValuesPerEntry, - 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], - layout.nValuesPerEntry, + fmt::format("{}\nAverage: {}us", entry.name, avg).c_str(), + &entry.time[0], + PerformanceLayout::NumberValues, 0, renderTime.c_str(), - _minMaxValues[0], - _minMaxValues[1], + *(minmax.first), + *(minmax.second), ImVec2(0, 40) ); } + ImGui::End(); } } else { @@ -200,6 +269,5 @@ void GuiPerformanceComponent::render() { ImGui::End(); } - } // namespace gui } // namespace openspace diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f6ad12718..1d7d1a7670 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,9 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/network/networkengine.cpp ${OPENSPACE_BASE_DIR}/src/network/parallelconnection.cpp ${OPENSPACE_BASE_DIR}/src/network/parallelconnection_lua.inl + ${OPENSPACE_BASE_DIR}/src/performance/performancemeasurement.cpp + ${OPENSPACE_BASE_DIR}/src/performance/performancelayout.cpp + ${OPENSPACE_BASE_DIR}/src/performance/performancemanager.cpp ${OPENSPACE_BASE_DIR}/src/properties/matrixproperty.cpp ${OPENSPACE_BASE_DIR}/src/properties/optionproperty.cpp ${OPENSPACE_BASE_DIR}/src/properties/property.cpp @@ -119,6 +122,9 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/network/networkengine.h ${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h ${OPENSPACE_BASE_DIR}/include/openspace/network/messagestructures.h + ${OPENSPACE_BASE_DIR}/include/openspace/performance/performancemeasurement.h + ${OPENSPACE_BASE_DIR}/include/openspace/performance/performancelayout.h + ${OPENSPACE_BASE_DIR}/include/openspace/performance/performancemanager.h ${OPENSPACE_BASE_DIR}/include/openspace/properties/matrixproperty.h ${OPENSPACE_BASE_DIR}/include/openspace/properties/numericalproperty.h ${OPENSPACE_BASE_DIR}/include/openspace/properties/numericalproperty.inl diff --git a/src/performance/performancelayout.cpp b/src/performance/performancelayout.cpp new file mode 100644 index 0000000000..5856f9f7e4 --- /dev/null +++ b/src/performance/performancelayout.cpp @@ -0,0 +1,50 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace openspace { +namespace performance { + +PerformanceLayout::PerformanceLayout() + : nScaleGraphEntries(0) + , nFunctionEntries(0) +{ + std::memset( + sceneGraphEntries, + 0, + MaxValues * sizeof(SceneGraphPerformanceLayout) + ); + + std::memset( + functionEntries, + 0, + MaxValues * sizeof(FunctionPerformanceLayout) + ); +} + +} // namespace performance +} // namespace openspace diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp new file mode 100644 index 0000000000..91731768a0 --- /dev/null +++ b/src/performance/performancemanager.cpp @@ -0,0 +1,167 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include + +#include +#include + +namespace { + const std::string _loggerCat = "PerformanceManager"; +} + +namespace openspace { +namespace performance { + +const std::string PerformanceManager::PerformanceMeasurementSharedData = + "OpenSpacePerformanceMeasurementSharedData"; + +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() { + if (ghoul::SharedMemory::exists(PerformanceMeasurementSharedData)) + 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 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 + + std::rotate( + std::begin(p->time), + std::next(std::begin(p->time)), + std::end(p->time) + ); + p->time[PerformanceLayout::NumberValues - 1] = + static_cast(microseconds); + + _performanceMemory->releaseLock(); +} + +void PerformanceManager::storeScenePerformanceMeasurements( + const std::vector& sceneNodes) +{ + using namespace performance; + + 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]; + + std::rotate( + std::begin(entry.renderTime), + std::next(std::begin(entry.renderTime)), + std::end(entry.renderTime) + ); + entry.renderTime[PerformanceLayout::NumberValues - 1] = r.renderTime / 1000.f; + + std::rotate( + std::begin(entry.updateEphemeris), + std::next(std::begin(entry.updateEphemeris)), + std::end(entry.updateEphemeris) + ); + entry.updateEphemeris[PerformanceLayout::NumberValues - 1] = r.updateTimeEphemeris / 1000.f; + + std::rotate( + std::begin(entry.updateRenderable), + std::next(std::begin(entry.updateRenderable)), + std::end(entry.updateRenderable) + ); + entry.updateRenderable[PerformanceLayout::NumberValues - 1] = r.updateTimeRenderable / 1000.f; + } + _performanceMemory->releaseLock(); +} + +} // namespace performance +} // namespace openspace diff --git a/src/performance/performancemeasurement.cpp b/src/performance/performancemeasurement.cpp new file mode 100644 index 0000000000..a62a6d5d4e --- /dev/null +++ b/src/performance/performancemeasurement.cpp @@ -0,0 +1,60 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +#include + +#include + +namespace openspace { +namespace performance { + +PerformanceMeasurement::PerformanceMeasurement(std::string identifier, + performance::PerformanceManager* manager) + : _identifier(std::move(identifier)) + , _manager(manager) +{ + if (_manager) { + glFinish(); + + _startTime = std::chrono::high_resolution_clock::now(); + } +} + +PerformanceMeasurement::~PerformanceMeasurement() { + auto endTime = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast( + endTime - _startTime).count(); + + if (_manager) { + _manager->storeIndividualPerformanceMeasurement(std::move(_identifier), duration); + } +} + + +} // namespace performance +} // namespace openspace diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 6d407d1646..103aac13a9 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -157,6 +159,8 @@ void FramebufferRenderer::raycastersChanged(VolumeRaycaster& raycaster, bool att } void FramebufferRenderer::update() { + PerfMeasure("FramebufferRenderer::update"); + if (_dirtyResolution) { updateResolution(); } @@ -197,6 +201,8 @@ void FramebufferRenderer::update() { } void FramebufferRenderer::updateResolution() { + PerfMeasure("FramebufferRenderer::updateResolution"); + int nSamples = OsEng.windowWrapper().currentNumberOfAaSamples(); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); @@ -252,6 +258,8 @@ void FramebufferRenderer::updateResolution() { } void FramebufferRenderer::updateRaycastData() { + PerfMeasure("FramebufferRenderer::updateRaycastData"); + _raycastData.clear(); _exitPrograms.clear(); _raycastPrograms.clear(); @@ -296,6 +304,8 @@ void FramebufferRenderer::updateRaycastData() { } void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { + PerfMeasure("FramebufferRenderer::render"); + if (!_scene) return; if (!_camera) @@ -398,6 +408,8 @@ void FramebufferRenderer::setResolution(glm::ivec2 res) { } void FramebufferRenderer::updateRendererData() { + PerfMeasure("FramebufferRenderer::updateRendererData"); + ghoul::Dictionary dict; dict.setValue("fragmentRendererPath", std::string(RenderFragmentShaderPath)); dict.setValue("postFragmentRendererPath", std::string(PostRenderFragmentShaderPath)); diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 5dc84a7710..54b4fcdf04 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -36,6 +36,8 @@ #include #include +#include + #include #include #include @@ -58,7 +60,6 @@ #include #include - #include #include #ifdef GHOUL_USE_DEVIL @@ -102,9 +103,6 @@ namespace { namespace openspace { -const std::string RenderEngine::PerformanceMeasurementSharedData = - "OpenSpacePerformanceMeasurementSharedData"; - const std::string RenderEngine::KeyFontMono = "Mono"; const std::string RenderEngine::KeyFontLight = "Light"; @@ -113,12 +111,11 @@ RenderEngine::RenderEngine() , _sceneGraph(nullptr) , _renderer(nullptr) , _rendererImplementation(RendererImplementation::Invalid) + , _performanceManager(nullptr) , _log(nullptr) , _showInfo(true) , _showLog(true) , _takeScreenshot(false) - , _doPerformanceMeasurements(false) - , _performanceMemory(nullptr) , _globalBlackOutFactor(1.f) , _fadeDuration(2.f) , _currentFadeTime(0.f) @@ -137,11 +134,8 @@ RenderEngine::~RenderEngine() { _sceneGraph = nullptr; delete _mainCamera; - delete _performanceMemory; delete _raycasterManager; - if (ghoul::SharedMemory::exists(PerformanceMeasurementSharedData)) - ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); } bool RenderEngine::deinitialize() { @@ -229,7 +223,6 @@ bool RenderEngine::initializeGL() { // development OsEng.windowWrapper().setNearFarClippingPlane(0.001f, 1000.f); - try { const float fontSizeTime = 15.f; _fontDate = OsEng.fontManager().font(KeyFontMono, fontSizeTime); @@ -365,7 +358,7 @@ void RenderEngine::postSynchronizationPreDraw() { Time::ref().currentTime(), Time::ref().timeJumped(), Time::ref().deltaTime(), - _doPerformanceMeasurements + _performanceManager != nullptr }); _sceneGraph->evaluate(_mainCamera); @@ -399,7 +392,7 @@ void RenderEngine::render(const glm::mat4 &projectionMatrix, const glm::mat4 &vi if (!(OsEng.isMaster() && _disableMasterRendering)) { - _renderer->render(_globalBlackOutFactor, _doPerformanceMeasurements); + _renderer->render(_globalBlackOutFactor, _performanceManager != nullptr); } // Print some useful information on the master viewport @@ -426,8 +419,8 @@ void RenderEngine::postDraw() { _takeScreenshot = false; } - if (_doPerformanceMeasurements) - storePerformanceMeasurements(); + if (_performanceManager) + _performanceManager->storeScenePerformanceMeasurements(scene()->allSceneGraphNodes()); } void RenderEngine::takeScreenshot() { @@ -714,101 +707,20 @@ scripting::ScriptEngine::LuaLibrary RenderEngine::luaLibrary() { } void RenderEngine::setPerformanceMeasurements(bool performanceMeasurements) { - _doPerformanceMeasurements = performanceMeasurements; + if (performanceMeasurements) { + if (!_performanceManager) + _performanceManager = std::make_unique(); + } + else + _performanceManager = nullptr; } bool RenderEngine::doesPerformanceMeasurements() const { - return _doPerformanceMeasurements; + return _performanceManager != nullptr; } -void RenderEngine::storePerformanceMeasurements() { - const int8_t Version = 0; - const int nValues = 250; - const int lengthName = 256; - const int maxValues = 256; - - struct PerformanceLayout { - int8_t version; - int32_t nValuesPerEntry; - int32_t nEntries; - int32_t maxNameLength; - int32_t maxEntries; - - struct PerformanceLayoutEntry { - char name[lengthName]; - float renderTime[nValues]; - float updateRenderable[nValues]; - float updateEphemeris[nValues]; - - int32_t currentRenderTime; - int32_t currentUpdateRenderable; - int32_t currentUpdateEphemeris; - }; - - PerformanceLayoutEntry entries[maxValues]; - }; - - const int nNodes = static_cast(scene()->allSceneGraphNodes().size()); - if (!_performanceMemory) { - - // Compute the total size - const int totalSize = sizeof(int8_t) + 4 * sizeof(int32_t) + - maxValues * sizeof(PerformanceLayout::PerformanceLayoutEntry); - 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(); - PerformanceLayout* layout = reinterpret_cast(ptr); - layout->version = Version; - layout->nValuesPerEntry = nValues; - layout->nEntries = nNodes; - layout->maxNameLength = lengthName; - layout->maxEntries = maxValues; - - memset(layout->entries, 0, maxValues * sizeof(PerformanceLayout::PerformanceLayoutEntry)); - - for (int i = 0; i < nNodes; ++i) { - SceneGraphNode* node = scene()->allSceneGraphNodes()[i]; - - memset(layout->entries[i].name, 0, lengthName); -#ifdef _MSC_VER - strcpy_s(layout->entries[i].name, node->name().length() + 1, node->name().c_str()); -#else - strcpy(layout->entries[i].name, node->name().c_str()); -#endif - - layout->entries[i].currentRenderTime = 0; - layout->entries[i].currentUpdateRenderable = 0; - layout->entries[i].currentUpdateEphemeris = 0; - } - } - - void* ptr = _performanceMemory->memory(); - PerformanceLayout* layout = reinterpret_cast(ptr); - _performanceMemory->acquireLock(); - for (int i = 0; i < nNodes; ++i) { - SceneGraphNode* node = scene()->allSceneGraphNodes()[i]; - SceneGraphNode::PerformanceRecord r = node->performanceRecord(); - PerformanceLayout::PerformanceLayoutEntry& entry = layout->entries[i]; - - entry.renderTime[entry.currentRenderTime] = r.renderTime / 1000.f; - entry.updateEphemeris[entry.currentUpdateEphemeris] = r.updateTimeEphemeris / 1000.f; - entry.updateRenderable[entry.currentUpdateRenderable] = r.updateTimeRenderable / 1000.f; - - entry.currentRenderTime = (entry.currentRenderTime + 1) % nValues; - entry.currentUpdateEphemeris = (entry.currentUpdateEphemeris + 1) % nValues; - entry.currentUpdateRenderable = (entry.currentUpdateRenderable + 1) % nValues; - } - _performanceMemory->releaseLock(); +performance::PerformanceManager* RenderEngine::performanceManager() { + return _performanceManager.get(); } // This method is temporary and will be removed once the scalegraph is in effect ---abock