diff --git a/common/build/Utilities/utilities.vcxproj b/common/build/Utilities/utilities.vcxproj index 1ee3d0194f..c52ff622bd 100644 --- a/common/build/Utilities/utilities.vcxproj +++ b/common/build/Utilities/utilities.vcxproj @@ -117,6 +117,7 @@ + Create Create diff --git a/common/build/Utilities/utilities.vcxproj.filters b/common/build/Utilities/utilities.vcxproj.filters index 35d467a66d..e28bf1b2fb 100644 --- a/common/build/Utilities/utilities.vcxproj.filters +++ b/common/build/Utilities/utilities.vcxproj.filters @@ -41,6 +41,9 @@ Source Files + + Source Files + Source Files diff --git a/common/include/Utilities/Perf.h b/common/include/Utilities/Perf.h new file mode 100644 index 0000000000..f24e897df2 --- /dev/null +++ b/common/include/Utilities/Perf.h @@ -0,0 +1,57 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2015 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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 PCSX2. + * If not, see . + */ + +#pragma once + +namespace Perf { + + struct Info + { + uptr m_x86; + u32 m_size; + char m_symbol[20]; + // The idea is to keep static zones that are set only + // once. + bool m_dynamic; + + Info(uptr x86, u32 size, const char* symbol); + Info(uptr x86, u32 size, const char* symbol, u32 pc); + void Print(FILE* fp); + }; + + class InfoVector + { + std::vector m_v; + char m_prefix[20]; + + public: + + InfoVector(const char* prefix); + + void print(FILE* fp); + void map(uptr x86, u32 size, const char* symbol); + void map(uptr x86, u32 size, u32 pc); + void reset(); + + }; + + void dump(); + void dump_and_reset(); + + extern InfoVector any; + extern InfoVector ee; + extern InfoVector iop; + extern InfoVector vu; +} diff --git a/common/src/Utilities/CMakeLists.txt b/common/src/Utilities/CMakeLists.txt index dea7c7dcc8..0e125e20c1 100644 --- a/common/src/Utilities/CMakeLists.txt +++ b/common/src/Utilities/CMakeLists.txt @@ -61,6 +61,7 @@ set(UtilitiesSources Mutex.cpp PathUtils.cpp PrecompiledHeader.cpp + Perf.cpp pxCheckBox.cpp pxRadioPanel.cpp pxStaticText.cpp diff --git a/common/src/Utilities/Perf.cpp b/common/src/Utilities/Perf.cpp new file mode 100644 index 0000000000..ce6c284ca6 --- /dev/null +++ b/common/src/Utilities/Perf.cpp @@ -0,0 +1,140 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2015 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 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 PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" + +#include "Perf.h" + +//#define ProfileWithPerf +#define MERGE_BLOCK_RESULT + + +namespace Perf +{ + // Warning object aren't thread safe + InfoVector any(""); + InfoVector ee("EE"); + InfoVector iop("IOP"); + InfoVector vu("VU"); + +// Perf is only supported on linux +#if defined(__linux__) && defined(ProfileWithPerf) + + //////////////////////////////////////////////////////////////////////////////// + // Implementation of the Info object + //////////////////////////////////////////////////////////////////////////////// + + Info::Info(uptr x86, u32 size, const char* symbol) : m_x86(x86), m_size(size), m_dynamic(false) + { + strncpy(m_symbol, symbol, sizeof(m_symbol)); + } + + Info::Info(uptr x86, u32 size, const char* symbol, u32 pc) : m_x86(x86), m_size(size), m_dynamic(true) + { + snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc); + } + + void Info::Print(FILE* fp) + { + fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol); + } + + //////////////////////////////////////////////////////////////////////////////// + // Implementation of the InfoVector object + //////////////////////////////////////////////////////////////////////////////// + + InfoVector::InfoVector(const char* prefix) + { + strncpy(m_prefix, prefix, sizeof(m_prefix)); + } + + void InfoVector::print(FILE* fp) + { + for(auto&& it : m_v) it.Print(fp); + } + + void InfoVector::map(uptr x86, u32 size, const char* symbol) + { + // This function is typically used for dispatcher and recompiler. + // Dispatchers are on a page and must always be kept. + // Recompilers are much bigger (TODO check VIF) and are only + // useful when MERGE_BLOCK_RESULT is defined + +#ifdef MERGE_BLOCK_RESULT + m_v.emplace_back(x86, size, symbol); +#else + if (size < 8 * _1kb) m_v.emplace_back(x86, size, symbol); +#endif + } + + void InfoVector::map(uptr x86, u32 size, u32 pc) + { +#ifndef MERGE_BLOCK_RESULT + m_v.emplace_back(x86, size, m_prefix, pc); +#endif + } + + void InfoVector::reset() + { + auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; }); + m_v.erase(dynamic, m_v.end()); + } + + //////////////////////////////////////////////////////////////////////////////// + // Global function + //////////////////////////////////////////////////////////////////////////////// + + void dump() + { + char file[256]; + snprintf(file, 250, "/tmp/perf-%d.map", getpid()); + FILE* fp = fopen(file, "w"); + + any.print(fp); + ee.print(fp); + iop.print(fp); + vu.print(fp); + + if (fp) + fclose(fp); + } + + void dump_and_reset() + { + dump(); + + any.reset(); + ee.reset(); + iop.reset(); + vu.reset(); + } + +#else + + //////////////////////////////////////////////////////////////////////////////// + // Dummy implementation + //////////////////////////////////////////////////////////////////////////////// + + InfoVector::InfoVector(const char* prefix) {} + void InfoVector::map(uptr x86, u32 size, const char* symbol) {} + void InfoVector::map(uptr x86, u32 size, u32 pc) {} + void InfoVector::reset() {} + + void dump() {} + void dump_and_reset() {} + +#endif + +}