diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 2a2146b9e7..63d903ddfb 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -6,6 +6,7 @@ set(SRCS BreakPoints.cpp GekkoDisassembler.cpp Hash.cpp IniFile.cpp + JitRegister.cpp MathUtil.cpp MemArena.cpp MemoryUtil.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 301c61524f..dfe91db48b 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -62,6 +62,7 @@ + @@ -98,6 +99,7 @@ + diff --git a/Source/Core/Common/JitRegister.cpp b/Source/Core/Common/JitRegister.cpp new file mode 100644 index 0000000000..69ea7e5bba --- /dev/null +++ b/Source/Core/Common/JitRegister.cpp @@ -0,0 +1,115 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/FileUtil.h" +#include "Common/JitRegister.h" +#include "Common/StringUtil.h" +#include "Core/ConfigManager.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +#if defined USE_OPROFILE && USE_OPROFILE +#include +#endif + +#if defined USE_VTUNE +#include +#pragma comment(lib, "libittnotify.lib") +#pragma comment(lib, "jitprofiling.lib") +#endif + +#if defined USE_OPROFILE && USE_OPROFILE +static op_agent_t s_agent = nullptr; +#endif + +static File::IOFile s_perf_map_file; + +namespace JitRegister +{ + +void Init() +{ +#if defined USE_OPROFILE && USE_OPROFILE + s_agent = op_open_agent(); +#endif + + const std::string& perf_dir = SConfig::GetInstance().m_LocalCoreStartupParameter.m_perfDir; + if (!perf_dir.empty()) + { + std::string filename = StringFromFormat("%s/perf-%d.map", perf_dir.data(), getpid()); + s_perf_map_file.Open(filename, "w"); + // Disable buffering in order to avoid missing some mappings + // if the event of a crash: + std::setvbuf(s_perf_map_file.GetHandle(), NULL, _IONBF, 0); + } +} + +void Shutdown() +{ +#if defined USE_OPROFILE && USE_OPROFILE + op_close_agent(s_agent); + s_agent = nullptr; +#endif + +#ifdef USE_VTUNE + iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, nullptr); +#endif + + if (s_perf_map_file.IsOpen()) + s_perf_map_file.Close(); +} + +void Register(const void* base_address, u32 code_size, + const char* name, u32 original_address) +{ +#if !(defined USE_OPROFILE && USE_OPROFILE) && !defined(USE_VTUNE) + if (!s_perf_map_file.IsOpen()) + return; +#endif + + std::string symbol_name; + if (original_address) + symbol_name = StringFromFormat("%s_%x", name, original_address); + else + symbol_name = name; + +#if defined USE_OPROFILE && USE_OPROFILE + op_write_native_code(s_agent, symbol_name.data(), (u64)base_address, + base_address, code_size); +#endif + +#ifdef USE_VTUNE + iJIT_Method_Load jmethod = {0}; + jmethod.method_id = iJIT_GetNewMethodID(); + jmethod.class_file_name = ""; + jmethod.source_file_name = __FILE__; + jmethod.method_load_address = base_address; + jmethod.method_size = code_size; + jmethod.line_number_size = 0; + jmethod.method_name = symbol_name.data(); + iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod); +#endif + + // Linux perf /tmp/perf-$pid.map: + if (s_perf_map_file.IsOpen()) + { + std::string entry = StringFromFormat( + "%" PRIx64 " %x %s\n", + (u64)base_address, code_size, symbol_name.data()); + s_perf_map_file.WriteBytes(entry.data(), entry.size()); + } +} + +} diff --git a/Source/Core/Common/JitRegister.h b/Source/Core/Common/JitRegister.h new file mode 100644 index 0000000000..68e2687d8b --- /dev/null +++ b/Source/Core/Common/JitRegister.h @@ -0,0 +1,15 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +namespace JitRegister +{ + +void Init(); +void Shutdown(); +void Register(const void* base_address, u32 code_size, + const char* name, u32 original_address=0); + +} diff --git a/Source/Core/Core/CoreParameter.h b/Source/Core/Core/CoreParameter.h index d1f12ef700..b5a386bd65 100644 --- a/Source/Core/Core/CoreParameter.h +++ b/Source/Core/Core/CoreParameter.h @@ -249,6 +249,8 @@ struct SCoreStartupParameter std::string m_strGameIniDefaultRevisionSpecific; std::string m_strGameIniLocal; + std::string m_perfDir; + // Constructor just calls LoadDefaults SCoreStartupParameter(); diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index dcd1df4a33..cbf65bd137 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -12,6 +12,7 @@ #include "disasm.h" #include "Common/CommonTypes.h" +#include "Common/JitRegister.h" #include "Common/MemoryUtil.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitCommon/JitBase.h" @@ -20,18 +21,6 @@ #include #endif -#if defined USE_OPROFILE && USE_OPROFILE -#include - -op_agent_t agent; -#endif - -#if defined USE_VTUNE -#include -#pragma comment(lib, "libittnotify.lib") -#pragma comment(lib, "jitprofiling.lib") -#endif - using namespace Gen; bool JitBaseBlockCache::IsFull() const @@ -47,9 +36,8 @@ using namespace Gen; return; } -#if defined USE_OPROFILE && USE_OPROFILE - agent = op_open_agent(); -#endif + JitRegister::Init(); + iCache.fill(JIT_ICACHE_INVALID_BYTE); iCacheEx.fill(JIT_ICACHE_INVALID_BYTE); iCacheVMEM.fill(JIT_ICACHE_INVALID_BYTE); @@ -62,13 +50,8 @@ using namespace Gen; { num_blocks = 0; m_initialized = false; -#if defined USE_OPROFILE && USE_OPROFILE - op_close_agent(agent); -#endif -#ifdef USE_VTUNE - iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, nullptr); -#endif + JitRegister::Shutdown(); } // This clears the JIT cache. It's called from JitCache.cpp when the JIT cache @@ -164,27 +147,8 @@ using namespace Gen; LinkBlockExits(block_num); } -#if defined USE_OPROFILE && USE_OPROFILE - char buf[100]; - sprintf(buf, "EmuCode%x", b.originalAddress); - const u8* blockStart = blockCodePointers[block_num]; - op_write_native_code(agent, buf, (uint64_t)blockStart, - blockStart, b.codeSize); -#endif - -#ifdef USE_VTUNE - sprintf(b.blockName, "EmuCode_0x%08x", b.originalAddress); - - iJIT_Method_Load jmethod = {0}; - jmethod.method_id = iJIT_GetNewMethodID(); - jmethod.class_file_name = ""; - jmethod.source_file_name = __FILE__; - jmethod.method_load_address = (void*)blockCodePointers[block_num]; - jmethod.method_size = b.codeSize; - jmethod.line_number_size = 0; - jmethod.method_name = b.blockName; - iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod); -#endif + JitRegister::Register(blockCodePointers[block_num], b.codeSize, + "JIT_PPC", b.originalAddress); } const u8 **JitBaseBlockCache::GetCodePointers() diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index 055a82cd66..fe85195745 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -57,10 +57,6 @@ struct JitBlock u64 ticStart; // for profiling - time. u64 ticStop; // for profiling - time. u64 ticCounter; // for profiling - time. - -#ifdef USE_VTUNE - char blockName[32]; -#endif }; typedef void (*CompiledCode)(); diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index 1a1378cb7a..95b30bfa54 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -142,10 +142,12 @@ bool DolphinApp::OnInit() bool UseLogger = false; bool selectVideoBackend = false; bool selectAudioEmulation = false; + bool selectPerfDir = false; wxString videoBackendName; wxString audioEmulationName; wxString userPath; + wxString perfDir; #if wxUSE_CMDLINE_PARSER // Parse command lines wxCmdLineEntryDesc cmdLineDesc[] = @@ -195,6 +197,11 @@ bool DolphinApp::OnInit() "User folder path", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { + wxCMD_LINE_OPTION, "P", "perf_dir", + "Directory for Lionux perf perf-$pid.map file", + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL + }, { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 } @@ -219,6 +226,7 @@ bool DolphinApp::OnInit() BatchMode = parser.Found("batch"); selectVideoBackend = parser.Found("video_backend", &videoBackendName); selectAudioEmulation = parser.Found("audio_emulation", &audioEmulationName); + selectPerfDir = parser.Found("perf_dir", &perfDir); playMovie = parser.Found("movie", &movieFile); if (parser.Found("user", &userPath)) @@ -243,6 +251,12 @@ bool DolphinApp::OnInit() UICommon::CreateDirectories(); UICommon::Init(); + if (selectPerfDir) + { + SConfig::GetInstance().m_LocalCoreStartupParameter.m_perfDir = + WxStrToStr(perfDir); + } + if (selectVideoBackend && videoBackendName != wxEmptyString) SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend = WxStrToStr(videoBackendName);