From 31b5290ac90ceb275c88d01291663cf459cbd1f4 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Wed, 14 Apr 2021 01:27:07 +0200 Subject: [PATCH] New profiler API. --- CMakeLists.txt | 5 +++ debugger/debugger.cpp | 9 ++++- main.cpp | 4 +++ utils/CMakeLists.txt | 6 ++++ utils/profiler.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++ utils/profiler.h | 72 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 utils/CMakeLists.txt create mode 100644 utils/profiler.cpp create mode 100644 utils/profiler.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a48cf7f..5e0dd84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ add_subdirectory("${PROJECT_SOURCE_DIR}/debugger/") add_subdirectory("${PROJECT_SOURCE_DIR}/devices/") add_subdirectory("${PROJECT_SOURCE_DIR}/execution") add_subdirectory("${PROJECT_SOURCE_DIR}/machines/") +add_subdirectory("${PROJECT_SOURCE_DIR}/utils/") add_subdirectory("${PROJECT_SOURCE_DIR}/thirdparty/loguru/") #set(BUILD_EXAMPLE_PROGRAMS OFF CACHE BOOL "Build libsoundio example programs") @@ -79,6 +80,7 @@ set(CLI11_ROOT ${PROJECT_SOURCE_DIR}/thirdparty/CLI11) include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}/devices" "${PROJECT_SOURCE_DIR}/cpu/ppc" "${PROJECT_SOURCE_DIR}/debugger" + "${PROJECT_SOURCE_DIR}/utils" "${PROJECT_SOURCE_DIR}/thirdparty/loguru/" "${PROJECT_SOURCE_DIR}/thirdparty/SDL2/") # "${PROJECT_SOURCE_DIR}/thirdparty/cubeb/include") @@ -98,6 +100,7 @@ add_executable(dingusppc ${SOURCES} $ $ $ $ + $ $) if (WIN32) @@ -120,6 +123,7 @@ if (DPPC_BUILD_PPC_TESTS) $ $ $ + $ $) if (WIN32) @@ -145,6 +149,7 @@ if (DPPC_BUILD_BENCHMARKS) $ $ $ + $ $) target_link_libraries(bench1 cubeb ${SDL2_LIBRARIES} ${CMAKE_DL_LIBS} diff --git a/debugger/debugger.cpp b/debugger/debugger.cpp index ed4254e..526b895 100644 --- a/debugger/debugger.cpp +++ b/debugger/debugger.cpp @@ -31,6 +31,7 @@ along with this program. If not, see . #include "../cpu/ppc/ppcdisasm.h" #include "../cpu/ppc/ppcemu.h" #include "../cpu/ppc/ppcmmu.h" +#include "utils/profiler.h" #ifdef ENABLE_68K_DEBUGGER // optionally defined in CMakeLists.txt #include @@ -70,6 +71,7 @@ static void show_help() { cout << " dump NT,X -- dump N memory cells of size T at address X" << endl; cout << " T can be b(byte), w(word), d(double)," << endl; cout << " q(quad) or c(character)." << endl; + cout << " profile N -- print variables for profile N" << endl; #ifdef PROFILER cout << " profiler -- show stats related to the processor" << endl; #endif @@ -365,7 +367,8 @@ static void print_gprs() { } void enter_debugger() { - string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str, inst_string, inst_num_str; + string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str, + inst_string, inst_num_str, profile_name; uint32_t addr, inst_grab; std::stringstream ss; int log_level, context; @@ -396,6 +399,10 @@ void enter_debugger() { show_help(); } else if (cmd == "quit") { break; + } else if (cmd == "profile") { + ss >> profile_name; + + gProfilerObj->print_profile(profile_name); } #ifdef PROFILER else if (cmd == "profiler") { diff --git a/main.cpp b/main.cpp index 7a66297..e6169ad 100644 --- a/main.cpp +++ b/main.cpp @@ -26,6 +26,7 @@ along with this program. If not, see . #include "execution/interpreter_loop.h" #include "machines/machinefactory.h" #include "machines/machineproperties.h" +#include "utils/profiler.h" #include "ppcemu.h" #include #include @@ -153,6 +154,9 @@ int main(int argc, char** argv) { cout << "BootROM path: " << bootrom_path << endl; cout << "Execution mode: " << execution_mode << endl; + // initialize global profiler object + gProfilerObj.reset(new Profiler()); + if (create_machine_for_id(machine_str, bootrom_path) < 0) { goto bail; } diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 0000000..0866e1e --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories("${PROJECT_SOURCE_DIR}") + +file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") + +add_library(utils OBJECT ${SOURCES}) +target_link_libraries(utils PRIVATE cubeb) diff --git a/utils/profiler.cpp b/utils/profiler.cpp new file mode 100644 index 0000000..0289bbf --- /dev/null +++ b/utils/profiler.cpp @@ -0,0 +1,79 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-21 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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 . +*/ + +#include "profiler.h" +#include +#include +#include + +/** global profiler object */ +std::unique_ptr gProfilerObj = 0; + +Profiler::Profiler() +{ + this->profiles_map.clear(); +} + +bool Profiler::register_profile(std::string name, + std::unique_ptr profile_obj) +{ + // bail out if a profile corresponding to 'name' already exists + if (this->profiles_map.find(name) != this->profiles_map.end()) { + return false; + } + + this->profiles_map[name] = std::move(profile_obj); + return true; +} + +void Profiler::print_profile(std::string name) +{ + if (this->profiles_map.find(name) == this->profiles_map.end()) { + std::cout << "Profile " << name << " not found." << std::endl; + return; + } + + std::cout << std::endl; + std::cout << "Summary of the profile '" << name << "':" << std::endl; + std::cout << "------------------------------------------" << std::endl; + + auto prof_it = this->profiles_map.find(name); + + std::vector vars; + + // ask the corresponding profile class to fill its variables for us + prof_it->second->populate_variables(vars); + + for (auto& var : vars) { + switch(var.format) { + case ProfileVarFmt::DEC: + std::cout << var.name << " : " << var.value << std::endl; + break; + case ProfileVarFmt::HEX: + std::cout << var.name << " : " << std::hex << var.value << std::endl; + break; + default: + std::cout << "Unknown value in variable " << var.name << std::endl; + } + } + + std::cout << std::endl; +} diff --git a/utils/profiler.h b/utils/profiler.h new file mode 100644 index 0000000..746888b --- /dev/null +++ b/utils/profiler.h @@ -0,0 +1,72 @@ +/* +DingusPPC - The Experimental PowerPC Macintosh emulator +Copyright (C) 2018-21 divingkatae and maximum + (theweirdo) spatium + +(Contact divingkatae#1017 or powermax#2286 on Discord for more info) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +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 . +*/ + +/** Interface definition for the Profiler. + */ + +#ifndef PROFILER_H +#define PROFILER_H + +#include +#include +#include +#include + +enum class ProfileVarFmt { DEC, HEX }; + +/** Define a special data type for profile variables. */ +typedef struct ProfileVar { + std::string name; + ProfileVarFmt format; + uint32_t value; +} ProfileVar; + +/** Base class for user-defined profiles. */ +class BaseProfile { +public: + BaseProfile(std::string name) { this->name = name; }; + + virtual ~BaseProfile() = default; + + virtual void populate_variables(std::vector& vars) = 0; + +private: + std::string name; +}; + +/** Profiler class for managing of user-defined profiles. */ +class Profiler { +public: + Profiler(); + + virtual ~Profiler() = default; + + bool register_profile(std::string name, std::unique_ptr profile_obj); + + void print_profile(std::string name); + +private: + std::map> profiles_map; +}; + +extern std::unique_ptr gProfilerObj; + +#endif /* PROFILER_H */