From 24a27b48bdd55d7c0bba0ef266c59ff6a241b3c0 Mon Sep 17 00:00:00 2001 From: Igor Korsukov Date: Fri, 27 Oct 2023 20:18:01 +0300 Subject: [PATCH] updated profiler --- SetupConfigure.cmake | 2 +- .../view/system/profilerviewmodel.cpp | 4 +- src/framework/global/CMakeLists.txt | 5 +- src/framework/global/globalmodule.cpp | 11 +- src/framework/global/log.h | 2 +- src/framework/global/logger.h | 4 + src/framework/global/profiler.h | 31 ++ .../global/thirdparty/haw_profiler/.gitignore | 2 - .../global/thirdparty/haw_profiler/README.md | 22 -- .../haw_profiler/src/profiler.cmake | 13 - .../haw_profiler/tests/CMakeLists.txt | 21 -- .../{haw_profiler => kors_profiler}/LICENSE | 0 .../global/thirdparty/kors_profiler/README.md | 35 ++ .../kors_profiler/example/CMakeLists.txt | 22 ++ .../tests => kors_profiler/example}/main.cpp | 23 +- .../thirdparty/kors_profiler/profiler.cmake | 9 + .../thirdparty/kors_profiler/src/funcinfo.h | 339 ++++++++++++++++++ .../src/profiler.cpp | 161 ++++----- .../src/profiler.h | 95 +++-- 19 files changed, 604 insertions(+), 197 deletions(-) create mode 100644 src/framework/global/profiler.h delete mode 100644 src/framework/global/thirdparty/haw_profiler/.gitignore delete mode 100644 src/framework/global/thirdparty/haw_profiler/README.md delete mode 100644 src/framework/global/thirdparty/haw_profiler/src/profiler.cmake delete mode 100644 src/framework/global/thirdparty/haw_profiler/tests/CMakeLists.txt rename src/framework/global/thirdparty/{haw_profiler => kors_profiler}/LICENSE (100%) create mode 100644 src/framework/global/thirdparty/kors_profiler/README.md create mode 100644 src/framework/global/thirdparty/kors_profiler/example/CMakeLists.txt rename src/framework/global/thirdparty/{haw_profiler/tests => kors_profiler/example}/main.cpp (72%) create mode 100644 src/framework/global/thirdparty/kors_profiler/profiler.cmake create mode 100644 src/framework/global/thirdparty/kors_profiler/src/funcinfo.h rename src/framework/global/thirdparty/{haw_profiler => kors_profiler}/src/profiler.cpp (82%) rename src/framework/global/thirdparty/{haw_profiler => kors_profiler}/src/profiler.h (64%) diff --git a/SetupConfigure.cmake b/SetupConfigure.cmake index 86608c7008..976f3d171c 100644 --- a/SetupConfigure.cmake +++ b/SetupConfigure.cmake @@ -293,7 +293,7 @@ if (WIN_PORTABLE) add_definitions(-DWIN_PORTABLE) endif() -add_definitions(-DHAW_PROFILER_ENABLED) +add_definitions(-DKORS_PROFILER_ENABLED) if (MUE_ENABLE_LOAD_QML_FROM_SOURCE) add_definitions(-DMUE_ENABLE_LOAD_QML_FROM_SOURCE) diff --git a/src/diagnostics/view/system/profilerviewmodel.cpp b/src/diagnostics/view/system/profilerviewmodel.cpp index 3e1166c85a..e79d5ac724 100644 --- a/src/diagnostics/view/system/profilerviewmodel.cpp +++ b/src/diagnostics/view/system/profilerviewmodel.cpp @@ -21,10 +21,12 @@ */ #include "profilerviewmodel.h" +#include "global/profiler.h" + #include "log.h" using namespace mu::diagnostics; -using namespace haw::profiler; +using namespace mu::profiler; ProfilerViewModel::ProfilerViewModel(QObject* parent) : QAbstractListModel(parent) diff --git a/src/framework/global/CMakeLists.txt b/src/framework/global/CMakeLists.txt index 11cd030373..30c7301b0c 100644 --- a/src/framework/global/CMakeLists.txt +++ b/src/framework/global/CMakeLists.txt @@ -23,13 +23,13 @@ set(MODULE global) include(${CMAKE_CURRENT_LIST_DIR}/modularity/modularity.cmake) include(${CMAKE_CURRENT_LIST_DIR}/async/async.cmake) include(${CMAKE_CURRENT_LIST_DIR}/thirdparty/kors_logger/logger.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/thirdparty/haw_profiler/src/profiler.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/thirdparty/kors_profiler/profiler.cmake) set(MODULE_SRC ${MODULARITY_SRC} ${ASYNC_SRC} ${KORS_LOGGER_SRC} - ${HAW_PROFILER_SRC} + ${KORS_PROFILER_SRC} ${CMAKE_CURRENT_LIST_DIR}/globaltypes.h ${CMAKE_CURRENT_LIST_DIR}/iapplication.h ${CMAKE_CURRENT_LIST_DIR}/iinteractive.h @@ -39,6 +39,7 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/logger.h ${CMAKE_CURRENT_LIST_DIR}/logremover.cpp ${CMAKE_CURRENT_LIST_DIR}/logremover.h + ${CMAKE_CURRENT_LIST_DIR}/profiler.h ${CMAKE_CURRENT_LIST_DIR}/dataformatter.cpp ${CMAKE_CURRENT_LIST_DIR}/dataformatter.h ${CMAKE_CURRENT_LIST_DIR}/muversion.cpp diff --git a/src/framework/global/globalmodule.cpp b/src/framework/global/globalmodule.cpp index 6d732b27c1..4d1ecbd690 100644 --- a/src/framework/global/globalmodule.cpp +++ b/src/framework/global/globalmodule.cpp @@ -24,9 +24,10 @@ #include "modularity/ioc.h" #include "internal/globalconfiguration.h" -#include "log.h" +#include "logger.h" #include "logremover.h" #include "thirdparty/kors_logger/src/logdefdest.h" +#include "profiler.h" #include "muversion.h" #include "internal/application.h" @@ -44,6 +45,8 @@ #include "diagnostics/idiagnosticspathsregister.h" +#include "log.h" + using namespace mu::framework; using namespace mu::modularity; using namespace mu::io; @@ -78,7 +81,7 @@ void GlobalModule::onPreInit(const IApplication::RunMode& mode) settings()->load(); //! --- Setup logger --- - using namespace kors::logger; + using namespace mu::logger; Logger* logger = Logger::instance(); logger->clearDests(); @@ -131,7 +134,7 @@ void GlobalModule::onPreInit(const IApplication::RunMode& mode) LOGI() << "=== Started MuseScore " << framework::MUVersion::fullVersion() << ", build number " << MUSESCORE_BUILD_NUMBER << " ==="; //! --- Setup profiler --- - using namespace haw::profiler; + using namespace mu::profiler; struct MyPrinter : public Profiler::Printer { void printDebug(const std::string& str) override { LOG_STREAM(Logger::DEBG, "Profiler", Color::Magenta)() << str; } @@ -143,7 +146,7 @@ void GlobalModule::onPreInit(const IApplication::RunMode& mode) profOpt.funcsTimeEnabled = true; profOpt.funcsTraceEnabled = false; profOpt.funcsMaxThreadCount = 100; - profOpt.dataTopCount = 150; + profOpt.statTopCount = 150; Profiler* profiler = Profiler::instance(); profiler->setup(profOpt, new MyPrinter()); diff --git a/src/framework/global/log.h b/src/framework/global/log.h index 7e478c82d8..91e3339312 100644 --- a/src/framework/global/log.h +++ b/src/framework/global/log.h @@ -26,7 +26,7 @@ #include #include -#include "thirdparty/haw_profiler/src/profiler.h" +#include "profiler.h" #include "logger.h" #undef FALLTHROUGH diff --git a/src/framework/global/logger.h b/src/framework/global/logger.h index 005b164bfd..22047e3022 100644 --- a/src/framework/global/logger.h +++ b/src/framework/global/logger.h @@ -23,6 +23,7 @@ #define MU_LOGGER_H #include "thirdparty/kors_logger/src/logger.h" +#include "thirdparty/kors_logger/src/logdefdest.h" #include "thirdparty/kors_logger/src/log_base.h" namespace mu::logger { @@ -30,6 +31,9 @@ using Logger = kors::logger::Logger; using Type = kors::logger::Type; using Level = kors::logger::Level; using Color = kors::logger::Color; +using LogLayout = kors::logger::LogLayout; +using ConsoleLogDest = kors::logger::ConsoleLogDest; +using FileLogDest = kors::logger::FileLogDest; } #endif // MU_LOGGER_H diff --git a/src/framework/global/profiler.h b/src/framework/global/profiler.h new file mode 100644 index 0000000000..1bc3edb09c --- /dev/null +++ b/src/framework/global/profiler.h @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef MU_PROFILER_H +#define MU_PROFILER_H + +#include "thirdparty/kors_profiler/src/profiler.h" + +namespace mu::profiler { +using Profiler = kors::profiler::Profiler; +} + +#endif // MU_PROFILER_H diff --git a/src/framework/global/thirdparty/haw_profiler/.gitignore b/src/framework/global/thirdparty/haw_profiler/.gitignore deleted file mode 100644 index c751e92f2a..0000000000 --- a/src/framework/global/thirdparty/haw_profiler/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.user -build-* \ No newline at end of file diff --git a/src/framework/global/thirdparty/haw_profiler/README.md b/src/framework/global/thirdparty/haw_profiler/README.md deleted file mode 100644 index bfa3813fbf..0000000000 --- a/src/framework/global/thirdparty/haw_profiler/README.md +++ /dev/null @@ -1,22 +0,0 @@ -Simple profiler ---------------- -Simple, embedded profiler with very small overhead -(ported from https://github.com/igorkorsukov/qzebradev) - -Features: -* Embedded profiler (can run anywhere and anytime) -* Function duration measure -* Steps duration measure -* Very small overhead -* Enabled / disabled on compile time and run time -* Thread safe (without use mutex) -* Custom data printer - -[Example](tests/main.cpp) - -To use Profiler within your software project include the Profiler source into your project - -Source: -* profiler.h/cpp - profiler and macros - -or see and include `src/profiler.cmake` in the cmake project diff --git a/src/framework/global/thirdparty/haw_profiler/src/profiler.cmake b/src/framework/global/thirdparty/haw_profiler/src/profiler.cmake deleted file mode 100644 index f01335b2ea..0000000000 --- a/src/framework/global/thirdparty/haw_profiler/src/profiler.cmake +++ /dev/null @@ -1,13 +0,0 @@ - -set(HAW_PROFILER_SRC - ${CMAKE_CURRENT_LIST_DIR}/profiler.cpp - ${CMAKE_CURRENT_LIST_DIR}/profiler.h -) - -set(HAW_PROFILER_INC - ${CMAKE_CURRENT_LIST_DIR} -) - -if (MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4456") -endif (MSVC) \ No newline at end of file diff --git a/src/framework/global/thirdparty/haw_profiler/tests/CMakeLists.txt b/src/framework/global/thirdparty/haw_profiler/tests/CMakeLists.txt deleted file mode 100644 index c6b6e874ba..0000000000 --- a/src/framework/global/thirdparty/haw_profiler/tests/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 3.14) - -project(haw_profiler LANGUAGES CXX) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -include(${CMAKE_CURRENT_LIST_DIR}/../src/profiler.cmake) - -include_directories(${HAW_PROFILER_INC}) - -add_executable(haw_profiler - main.cpp - ${HAW_PROFILER_SRC} -) - -target_link_libraries(haw_profiler - pthread -) diff --git a/src/framework/global/thirdparty/haw_profiler/LICENSE b/src/framework/global/thirdparty/kors_profiler/LICENSE similarity index 100% rename from src/framework/global/thirdparty/haw_profiler/LICENSE rename to src/framework/global/thirdparty/kors_profiler/LICENSE diff --git a/src/framework/global/thirdparty/kors_profiler/README.md b/src/framework/global/thirdparty/kors_profiler/README.md new file mode 100644 index 0000000000..9ce4e7e618 --- /dev/null +++ b/src/framework/global/thirdparty/kors_profiler/README.md @@ -0,0 +1,35 @@ +# profiler + +Simple, embedded profiler with very small overhead +Requires C++17 and higher. + +Features: +* Embedded profiler (can run anywhere and anytime) +* Function duration measure +* Steps duration measure +* Very small overhead +* Enabled / disabled on compile time and run time +* Thread safe (without use mutex) +* Custom data printer + +[Example](example/main.cpp) + +Used in at least two private commercial projects and one [open source](https://github.com/musescore/MuseScore). + +## Integration +To use Profiler within your software project include the Profiler source into your project + +Source: +* profiler.h/cpp - profiler and macros +* funcinfo.h - macros for parsing signatures + +or see and include `profiler.cmake` in the cmake project + +## ChangeLog + +### v1.1 +* Improved parsing of function signatures +* Fixed get threads data + +### v1.0 +* Ported from [https://github.com/igorkorsukov/qzebradev](https://github.com/igorkorsukov/qzebradev) diff --git a/src/framework/global/thirdparty/kors_profiler/example/CMakeLists.txt b/src/framework/global/thirdparty/kors_profiler/example/CMakeLists.txt new file mode 100644 index 0000000000..77b4853223 --- /dev/null +++ b/src/framework/global/thirdparty/kors_profiler/example/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.14) + +project(profiler_example LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include(${CMAKE_CURRENT_LIST_DIR}/../profiler.cmake) + +include_directories(${KORS_PROFILER_INC}) +add_definitions(-DKORS_PROFILER_ENABLED) + +add_executable(${PROJECT_NAME} + main.cpp + ${KORS_PROFILER_SRC} +) + +target_link_libraries(${PROJECT_NAME} + pthread +) diff --git a/src/framework/global/thirdparty/haw_profiler/tests/main.cpp b/src/framework/global/thirdparty/kors_profiler/example/main.cpp similarity index 72% rename from src/framework/global/thirdparty/haw_profiler/tests/main.cpp rename to src/framework/global/thirdparty/kors_profiler/example/main.cpp index b1442a4965..dd4218a55e 100644 --- a/src/framework/global/thirdparty/haw_profiler/tests/main.cpp +++ b/src/framework/global/thirdparty/kors_profiler/example/main.cpp @@ -72,7 +72,7 @@ public: int main(int argc, char* argv[]) { - std::clog << "Hello World, I am Profiler\n"; + std::cout << "Hello World, I am Profiler" << std::endl; Example t; t.example(); @@ -101,4 +101,25 @@ int main(int argc, char* argv[]) Example::th_func 2.212 ms 1 2.212 ms */ + + //! NOTE Custom setup + + // custom printer + using namespace kors::profiler; + struct MyPrinter : public Profiler::Printer + { + void printDebug(const std::string& str) override { std::clog << str << std::endl; } + void printInfo(const std::string& str) override { std::clog << str << std::endl; } + }; + + // options + Profiler::Options profOpt; + profOpt.stepTimeEnabled = true; // enable measure of steps, macros: BEGIN_STEP_TIME, STEP_TIME + profOpt.funcsTimeEnabled = true; // enable measure of functions, macros: TRACEFUNC, TRACEFUNC_C + profOpt.funcsTraceEnabled = false; // enable trace (output by func call), macros: TRACEFUNC, TRACEFUNC_C + profOpt.funcsMaxThreadCount = 100; // max treads count + profOpt.statTopCount = 150; // statistic top count + + Profiler* profiler = Profiler::instance(); + profiler->setup(profOpt, new MyPrinter()); } diff --git a/src/framework/global/thirdparty/kors_profiler/profiler.cmake b/src/framework/global/thirdparty/kors_profiler/profiler.cmake new file mode 100644 index 0000000000..66e46dcd4a --- /dev/null +++ b/src/framework/global/thirdparty/kors_profiler/profiler.cmake @@ -0,0 +1,9 @@ + +set(KORS_PROFILER_SRC + ${CMAKE_CURRENT_LIST_DIR}/src/profiler.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/profiler.h +) + +set(KORS_PROFILER_INC + ${CMAKE_CURRENT_LIST_DIR}/src +) diff --git a/src/framework/global/thirdparty/kors_profiler/src/funcinfo.h b/src/framework/global/thirdparty/kors_profiler/src/funcinfo.h new file mode 100644 index 0000000000..82049ae08f --- /dev/null +++ b/src/framework/global/thirdparty/kors_profiler/src/funcinfo.h @@ -0,0 +1,339 @@ +/* +MIT License + +Copyright (c) 2023 Igor Korsukov + +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 KORS__FI_H +#define KORS__FI_H + +#include +#include + +#ifndef KORS_FUNC_SIG +#if defined(_MSC_VER) +#define FUNC_SIG __FUNCSIG__ +#else +#define FUNC_SIG __PRETTY_FUNCTION__ +#endif +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#if (__GNUC__ < 11) +#define _KORS_NO_STRINGVIEW_CONSTEXPR_METHODS +#endif +#endif + +#define FUNCNAME kors::funcinfo::funcNameBySig(FUNC_SIG) +#define CLASSNAME kors::funcinfo::classNameBySig(FUNC_SIG) +#define CLASSFUNC kors::funcinfo::classFuncBySig(FUNC_SIG) +#define MODULENAME kors::funcinfo::moduleNameBySig(FUNC_SIG) + +namespace kors::funcinfo { +#ifndef _KORS_NO_STRINGVIEW_CONSTEXPR_METHODS + +//! NOTE Signature maybe like: +//! * ReturnType funcName(...) +//! * ReturnType some_ns::maybesub::funcName(...) +//! * ReturnType Class::funcName(...) +//! * ReturnType some_ns::maybesub::Class::funcName(...) +constexpr std::string_view funcNameBySig(const std::string_view& sig) +{ + constexpr std::string_view Colon("::"); + constexpr std::string_view ArgBegin("("); + constexpr std::string_view Space(" "); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Colon, endFunc); + if (beginFunc == std::string_view::npos) { + beginFunc = sig.find_last_of(Space, endFunc); + } + + if (beginFunc == std::string_view::npos) { + beginFunc = 0; + } else { + beginFunc += 1; + } + + return sig.substr(beginFunc, (endFunc - beginFunc)); +} + +//! NOTE Signature maybe like: +//! * ReturnType Class::funcName(...) +//! * ReturnType some_ns::maybesub::Class::funcName(...) +constexpr std::string_view classNameBySig(const std::string_view& sig) +{ + constexpr std::string_view Colon("::"); + constexpr std::string_view ArgBegin("("); + constexpr std::string_view Space(" "); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Colon, endFunc); + if (beginFunc == std::string_view::npos) { + return std::string_view(); + } + + std::size_t beginClassColon = sig.find_last_of(Colon, beginFunc - 2); + std::size_t beginClassSpace = sig.find_last_of(Space, beginFunc - 2); + + std::size_t beginClass = std::string_view::npos; + if (beginClassColon == std::string_view::npos) { + beginClass = beginClassSpace; + } else if (beginClassSpace == std::string_view::npos) { + beginClass = beginClassColon; + } else { + beginClass = std::max(beginClassColon, beginClassSpace); + } + + if (beginClass == std::string_view::npos) { + beginClass = 0; + } else { + beginClass += 1; + } + + return sig.substr(beginClass, (beginFunc - 1 - beginClass)); +} + +//! NOTE Signature maybe like: +//! * ReturnType Class::funcName(...) +//! * ReturnType some_ns::maybesub::Class::funcName(...) +constexpr std::string_view classFuncBySig(const std::string_view& sig) +{ + constexpr std::string_view Colon("::"); + constexpr std::string_view ArgBegin("("); + constexpr std::string_view Space(" "); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Colon, endFunc); + if (beginFunc == std::string_view::npos) { + return funcNameBySig(sig); + } + + std::size_t beginClassColon = sig.find_last_of(Colon, beginFunc - 2); + std::size_t beginClassSpace = sig.find_last_of(Space, beginFunc - 2); + + std::size_t beginClass = std::string_view::npos; + if (beginClassColon == std::string_view::npos) { + beginClass = beginClassSpace; + } else if (beginClassSpace == std::string_view::npos) { + beginClass = beginClassColon; + } else { + beginClass = std::max(beginClassColon, beginClassSpace); + } + + if (beginClass == std::string_view::npos) { + beginClass = 0; + } else { + beginClass += 1; + } + + return sig.substr(beginClass, (endFunc - beginClass)); +} + +//! NOTE Signature should be like +//! ReturnType xxx::modulename::maybesub::ClassName::methodName() +constexpr std::string_view moduleNameBySig(const std::string_view& sig) +{ + constexpr std::string_view ArgBegin("("); + constexpr std::string_view Space(" "); + constexpr std::string_view Colon("::"); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Space, endFunc); + if (beginFunc == std::string_view::npos) { + return std::string_view(); + } + + size_t beginModule = sig.find_first_of(Colon, beginFunc) + 2; + if (beginModule == std::string_view::npos) { + return std::string_view(); + } + + size_t endModule = sig.find_first_of(Colon, beginModule); + if (endModule == std::string_view::npos) { + return std::string_view(); + } + + return sig.substr(beginModule, (endModule - beginModule)); +} + +#else +//! NOTE Signature maybe like: +//! * ReturnType funcName(...) +//! * ReturnType some_ns::maybesub::funcName(...) +//! * ReturnType Class::funcName(...) +//! * ReturnType some_ns::maybesub::Class::funcName(...) +inline std::string_view funcNameBySig(const std::string_view& sig) +{ + static const std::string_view Colon("::"); + static const std::string_view ArgBegin("("); + static const std::string_view Space(" "); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Colon, endFunc); + if (beginFunc == std::string_view::npos) { + beginFunc = sig.find_last_of(Space, endFunc); + } + + if (beginFunc == std::string_view::npos) { + beginFunc = 0; + } else { + beginFunc += 1; + } + + return sig.substr(beginFunc, (endFunc - beginFunc)); +} + +//! NOTE Signature maybe like: +//! * ReturnType Class::funcName(...) +//! * ReturnType some_ns::maybesub::Class::funcName(...) +inline std::string_view classNameBySig(const std::string_view& sig) +{ + static const std::string_view Colon("::"); + static const std::string_view ArgBegin("("); + static const std::string_view Space(" "); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Colon, endFunc); + if (beginFunc == std::string_view::npos) { + return std::string_view(); + } + + std::size_t beginClassColon = sig.find_last_of(Colon, beginFunc - 2); + std::size_t beginClassSpace = sig.find_last_of(Space, beginFunc - 2); + + std::size_t beginClass = std::string_view::npos; + if (beginClassColon == std::string_view::npos) { + beginClass = beginClassSpace; + } else if (beginClassSpace == std::string_view::npos) { + beginClass = beginClassColon; + } else { + beginClass = std::max(beginClassColon, beginClassSpace); + } + + if (beginClass == std::string_view::npos) { + beginClass = 0; + } else { + beginClass += 1; + } + + return sig.substr(beginClass, (beginFunc - 1 - beginClass)); +} + +//! NOTE Signature maybe like: +//! * ReturnType Class::funcName(...) +//! * ReturnType some_ns::maybesub::Class::funcName(...) +inline std::string_view classFuncBySig(const std::string_view& sig) +{ + static const std::string_view Colon("::"); + static const std::string_view ArgBegin("("); + static const std::string_view Space(" "); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Colon, endFunc); + if (beginFunc == std::string_view::npos) { + return funcNameBySig(sig); + } + + std::size_t beginClassColon = sig.find_last_of(Colon, beginFunc - 2); + std::size_t beginClassSpace = sig.find_last_of(Space, beginFunc - 2); + + std::size_t beginClass = std::string_view::npos; + if (beginClassColon == std::string_view::npos) { + beginClass = beginClassSpace; + } else if (beginClassSpace == std::string_view::npos) { + beginClass = beginClassColon; + } else { + beginClass = std::max(beginClassColon, beginClassSpace); + } + + if (beginClass == std::string_view::npos) { + beginClass = 0; + } else { + beginClass += 1; + } + + return sig.substr(beginClass, (endFunc - beginClass)); +} + +//! NOTE Signature should be like +//! ReturnType xxx::modulename::maybesub::ClassName::methodName() +inline std::string_view moduleNameBySig(const std::string_view& sig) +{ + static const std::string_view ArgBegin("("); + static const std::string_view Space(" "); + static const std::string_view Colon("::"); + + std::size_t endFunc = sig.find_first_of(ArgBegin); + if (endFunc == std::string_view::npos) { + return sig; + } + + std::size_t beginFunc = sig.find_last_of(Space, endFunc); + if (beginFunc == std::string_view::npos) { + return std::string_view(); + } + + size_t beginModule = sig.find_first_of(Colon, beginFunc) + 2; + if (beginModule == std::string_view::npos) { + return std::string_view(); + } + + size_t endModule = sig.find_first_of(Colon, beginModule); + if (endModule == std::string_view::npos) { + return std::string_view(); + } + + return sig.substr(beginModule, (endModule - beginModule)); +} + +#endif // _KORS_NO_STRINGVIEW_CONSTEXPR_METHODS +} + +#endif // KORS__FI_H diff --git a/src/framework/global/thirdparty/haw_profiler/src/profiler.cpp b/src/framework/global/thirdparty/kors_profiler/src/profiler.cpp similarity index 82% rename from src/framework/global/thirdparty/haw_profiler/src/profiler.cpp rename to src/framework/global/thirdparty/kors_profiler/src/profiler.cpp index c90b6c4347..a6a05d2d81 100644 --- a/src/framework/global/thirdparty/haw_profiler/src/profiler.cpp +++ b/src/framework/global/thirdparty/kors_profiler/src/profiler.cpp @@ -1,24 +1,41 @@ +/* +MIT License + +Copyright (c) 2020 Igor Korsukov + +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 "profiler.h" #include -#include #include +#include #include #include -using namespace haw::profiler; +using namespace kors::profiler; Profiler::Options Profiler::m_options; constexpr int MAIN_THREAD_INDEX(0); -Profiler* Profiler::instance() -{ - static Profiler p; - return &p; -} - Profiler::Profiler() { setup(Options(), new Printer()); @@ -29,6 +46,12 @@ Profiler::~Profiler() delete m_printer; } +Profiler* Profiler::instance() +{ + static Profiler p; + return &p; +} + void Profiler::setup(const Options& opt, Printer* printer) { m_options = opt; @@ -165,7 +188,7 @@ void Profiler::clear() } { std::lock_guard lock(m_funcs.mutex); - for (auto st : m_steps.timers) { + for (auto& st : m_steps.timers) { delete st.second; } m_steps.timers.clear(); @@ -187,7 +210,7 @@ Profiler::Data Profiler::threadsData(Data::Mode mode) const std::thread::id empty; for (size_t i = 0; i < funcsThreads.size(); ++i) { - std::thread::id th = funcsThreads[i]; + std::thread::id th = funcsThreads.at(i); if (th == empty) { break; } @@ -205,7 +228,7 @@ Profiler::Data Profiler::threadsData(Data::Mode mode) const Data::Thread thdata; thdata.thread = th; - const FuncTimers& timers = funcsTimers[i]; + const FuncTimers& timers = funcsTimers.at(i); for (auto it : timers) { const FuncTimer* ft = it.second; Data::Func f( @@ -232,13 +255,13 @@ Profiler::Data Profiler::threadsData(Data::Mode mode) const std::string Profiler::threadsDataString(Data::Mode mode) const { Profiler::Data data = threadsData(mode); - return printer()->formatData(data, mode, m_options.dataTopCount); + return printer()->formatData(data, mode, m_options.statTopCount); } void Profiler::printThreadsData(Data::Mode mode) const { Profiler::Data data = threadsData(mode); - printer()->printData(data, mode, m_options.dataTopCount); + printer()->printData(data, mode, m_options.statTopCount); } void Profiler::print(const std::string& str) @@ -266,44 +289,6 @@ bool Profiler::save_file(const std::string& path, const std::string& content) return count > 0; } -std::string FuncMarker::formatSig(const std::string& sig) -{ - static const std::string Coln("::"); - static const std::string Spc(" "); - static const std::string ArgBeg("("); - - std::size_t endFunc = sig.find_first_of(ArgBeg); - if (endFunc == std::string::npos) { - return sig; - } - - std::size_t beginFunc = sig.find_last_of(Coln, endFunc); - if (beginFunc == std::string::npos) { - return sig; - } - - std::size_t beginClassColon = sig.find_last_of(Coln, beginFunc - 2); - std::size_t beginClassSpace = sig.find_last_of(Spc, beginFunc - 2); - - std::size_t beginClass = std::string::npos; - if (beginClassColon == std::string::npos) { - beginClass = beginClassSpace; - } else if (beginClassSpace == std::string::npos) { - beginClass = beginClassColon; - } else { - beginClass = std::max(beginClassColon, beginClassSpace); - } - - if (beginClass == std::string::npos) { - beginClass = beginFunc; - } else { - beginClass += 1; - } - - std::string str = sig.substr(beginClass, (endFunc - beginClass)); - return str; -} - double Profiler::StepTimer::beginMs() const { return beginTime.mlsecsElapsed(); @@ -373,7 +358,7 @@ using mclock = std::chrono::high_resolution_clock; void Profiler::ElapsedTimer::start() { - _start = mclock::now(); + m_start = mclock::now(); } void Profiler::ElapsedTimer::restart() @@ -384,45 +369,42 @@ void Profiler::ElapsedTimer::restart() double Profiler::ElapsedTimer::mlsecsElapsed() const { auto end = mclock::now(); - std::chrono::duration elapsed = end - _start; + std::chrono::duration elapsed = end - m_start; return elapsed.count(); } void Profiler::ElapsedTimer::invalidate() { - _start = mclock::time_point(); + m_start = mclock::time_point(); } bool Profiler::ElapsedTimer::isValid() const { - const mclock::duration since_epoch = _start.time_since_epoch(); + const mclock::duration since_epoch = m_start.time_since_epoch(); return since_epoch.count() > 0; } -Profiler::Printer::~Printer() -{} - void Profiler::Printer::printDebug(const std::string& str) { - std::cout << str << '\n'; + std::cout << str << std::endl; } void Profiler::Printer::printInfo(const std::string& str) { - std::cout << str << '\n'; + std::cout << str << std::endl; } -static std::string formatDouble(double val, size_t prec) +std::string Profiler::Printer::formatDouble(double val, size_t prec) { std::stringstream ss; - ss << std::fixed << std::setprecision(static_cast(prec)) << val; + ss << std::fixed << std::setprecision(prec) << val; return ss.str(); } void Profiler::Printer::printStep(const std::string& tag, double beginMs, double stepMs, const std::string& info) { - static const std::string COLN(" : "); + static const std::string COLON(" : "); static const std::string SEP("/"); static const std::string MS(" ms: "); @@ -431,7 +413,7 @@ void Profiler::Printer::printStep(const std::string& tag, double beginMs, double str .append(tag) - .append(COLN) + .append(COLON) .append(formatDouble(beginMs, 3)) .append(SEP) .append(formatDouble(stepMs, 3)) @@ -480,15 +462,17 @@ void Profiler::Printer::printData(const Data& data, Data::Mode mode, int maxcoun printInfo(formatData(data, mode, maxcount)); } +namespace { +struct IsLessBySum { + bool operator()(const Profiler::Data::Func& f, const Profiler::Data::Func& s) const + { + return f.sumtimeMs > s.sumtimeMs; + } +}; +} + std::string Profiler::Printer::formatData(const Data& data, Data::Mode mode, int maxcount) const { - struct IsLessBySum { - bool operator()(const Profiler::Data::Func& f, const Profiler::Data::Func& s) const - { - return f.sumtimeMs > s.sumtimeMs; - } - }; - std::stringstream stream; stream << "\n\n"; @@ -543,27 +527,25 @@ std::string Profiler::Printer::formatData(const Data& data, Data::Mode mode, int return stream.str(); } +std::string Profiler::Printer::leftJustified(const std::string& in, size_t width) +{ + std::string out = in; + if (width > out.size()) { + out.resize(width, ' '); + } + return out; +} + +#define FORMAT(str, width) leftJustified(str, width) +#define TITLE(str) FORMAT(std::string(str), 18) +#define VALUE(val, unit) FORMAT(std::to_string(val) + unit, 18) +#define VALUE_D(val, unit) FORMAT(formatDouble(val, 3) + unit, 18) + void Profiler::Printer::funcsToStream(std::stringstream& stream, const std::string& title, const std::list& funcs, int count) const { - auto leftJustified = [](const std::string& val, size_t width) -> std::string - { - std::string str; - str.resize(width, ' '); - size_t lenght = width < val.size() ? width : val.size(); - for (size_t i = 0; i < lenght; ++i) { - str[i] = val[i]; - } - return str; - }; - - #define FORMAT(str, width) leftJustified(str, width) - #define TITLE(str) FORMAT(std::string(str), 18) - #define VALUE(val, unit) FORMAT(std::to_string(val) + unit, 18) - #define VALUE_D(val, unit) FORMAT(formatDouble(val, 3) + unit, 18) - stream << title << "\n"; stream << FORMAT("Function", 60) << TITLE("Call time") << TITLE("Call count") << TITLE("Sum time") << "\n"; @@ -580,10 +562,5 @@ void Profiler::Printer::funcsToStream(std::stringstream& stream, } } - #undef FORMAT - #undef TITLE - #undef VALUE - #undef VALUE_D - stream << "\n\n"; } diff --git a/src/framework/global/thirdparty/haw_profiler/src/profiler.h b/src/framework/global/thirdparty/kors_profiler/src/profiler.h similarity index 64% rename from src/framework/global/thirdparty/haw_profiler/src/profiler.h rename to src/framework/global/thirdparty/kors_profiler/src/profiler.h index bf5e639f27..4572e59e7b 100644 --- a/src/framework/global/thirdparty/haw_profiler/src/profiler.h +++ b/src/framework/global/thirdparty/kors_profiler/src/profiler.h @@ -1,7 +1,31 @@ -#ifndef HAW_PROFILER_H -#define HAW_PROFILER_H +/* +MIT License + +Copyright (c) 2020 Igor Korsukov + +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 KORS_PROFILER_H +#define KORS_PROFILER_H #include +#include #include #include #include @@ -11,46 +35,42 @@ #include #include -#ifndef FUNC_INFO -#if defined(_MSC_VER) - #define FUNC_INFO __FUNCSIG__ -#else - #define FUNC_INFO __PRETTY_FUNCTION__ -#endif -#endif +#include "funcinfo.h" -#ifdef HAW_PROFILER_ENABLED +// #define KORS_PROFILER_ENABLED + +#ifdef KORS_PROFILER_ENABLED #ifndef TRACEFUNC #define TRACEFUNC \ - static std::string __func_info(haw::profiler::FuncMarker::formatSig(FUNC_INFO)); \ - haw::profiler::FuncMarker __funcMarker(__func_info); + static std::string __func_info(CLASSFUNC); \ + kors::profiler::FuncMarker __funcMarker(__func_info); #endif #ifndef TRACEFUNC_C #define TRACEFUNC_C(info) \ static std::string __func_info(info); \ - haw::profiler::FuncMarker __funcMarkerInfo(__func_info); + kors::profiler::FuncMarker __funcMarkerInfo(__func_info); #endif #ifndef BEGIN_STEP_TIME #define BEGIN_STEP_TIME(tag) \ - if (haw::profiler::Profiler::options().stepTimeEnabled) \ - { haw::profiler::Profiler::instance()->stepTime(tag, std::string("Begin"), true); } + if (kors::profiler::Profiler::options().stepTimeEnabled) \ + { kors::profiler::Profiler::instance()->stepTime(tag, std::string("Begin"), true); } #endif #ifndef STEP_TIME #define STEP_TIME(tag, info) \ - if (haw::profiler::Profiler::options().stepTimeEnabled) \ - { haw::profiler::Profiler::instance()->stepTime(tag, info); } + if (kors::profiler::Profiler::options().stepTimeEnabled) \ + { kors::profiler::Profiler::instance()->stepTime(tag, info); } #endif #ifndef PROFILER_CLEAR -#define PROFILER_CLEAR haw::profiler::Profiler::instance()->clear(); +#define PROFILER_CLEAR kors::profiler::Profiler::instance()->clear(); #endif #ifndef PROFILER_PRINT -#define PROFILER_PRINT haw::profiler::Profiler::instance()->printThreadsData(); +#define PROFILER_PRINT kors::profiler::Profiler::instance()->printThreadsData(); #endif #else @@ -64,7 +84,7 @@ #endif -namespace haw::profiler { +namespace kors::profiler { class Profiler { public: @@ -72,12 +92,12 @@ public: static Profiler* instance(); struct Options { - bool stepTimeEnabled{ true }; - bool funcsTimeEnabled{ true }; - bool funcsTraceEnabled{ false }; - size_t funcsMaxThreadCount{ 100 }; - int dataTopCount{ 150 }; Options() {} + bool stepTimeEnabled = true; + bool funcsTimeEnabled = true; + bool funcsTraceEnabled = false; + size_t funcsMaxThreadCount = 100; + int statTopCount = 150; }; struct Data { @@ -89,8 +109,8 @@ public: struct Func { std::string func; - long callcount{ 0 }; - double sumtimeMs{ 0. }; + long callcount = 0; + double sumtimeMs = 0.0; Func() {} Func(const std::string& f, long cc, double st) : func(f), callcount(cc), sumtimeMs(st) {} @@ -106,7 +126,7 @@ public: }; struct Printer { - virtual ~Printer(); + virtual ~Printer() = default; virtual void printDebug(const std::string& str); virtual void printInfo(const std::string& str); virtual void printStep(const std::string& tag, double beginMs, double stepMs, const std::string& info); @@ -116,6 +136,9 @@ public: virtual std::string formatData(const Data& data, Data::Mode mode, int maxcount) const; virtual void funcsToStream(std::stringstream& stream, const std::string& title, const std::list& funcs, int count) const; + + static std::string formatDouble(double val, size_t prec); + static std::string leftJustified(const std::string& in, size_t width); }; struct ElapsedTimer { @@ -126,14 +149,14 @@ public: bool isValid() const; private: - std::chrono::high_resolution_clock::time_point _start; + std::chrono::high_resolution_clock::time_point m_start; }; struct FuncTimer { const std::string& func; ElapsedTimer timer; - long callcount; - double sumtimeMs; + long callcount = 0; + double sumtimeMs = 0.0; explicit FuncTimer(const std::string& f) : func(f), callcount(0), sumtimeMs(0) {} }; @@ -199,12 +222,12 @@ private: bool save_file(const std::string& path, const std::string& content); - Printer* m_printer{ nullptr }; + Printer* m_printer = nullptr; StepsData m_steps; mutable FuncsData m_funcs; - size_t m_stackCounter{ 0 }; + size_t m_stackCounter = 0; }; struct FuncMarker @@ -224,11 +247,9 @@ struct FuncMarker } } - static std::string formatSig(const std::string& sig); - - Profiler::FuncTimer* timer{ nullptr }; + Profiler::FuncTimer* timer = nullptr; const std::string& func; }; } -#endif // XTZ_PROFILER_H +#endif // KORS_PROFILER_H