Profiler skeleton.

This commit is contained in:
Ben Vanik 2014-05-27 22:54:40 -07:00
parent f3f9d93017
commit 6486e0a48e
10 changed files with 249 additions and 0 deletions

View File

@ -18,6 +18,7 @@
#include <xenia/malloc.h> #include <xenia/malloc.h>
#include <xenia/platform.h> #include <xenia/platform.h>
#include <xenia/platform_includes.h> #include <xenia/platform_includes.h>
#include <xenia/profiling.h>
#include <xenia/string.h> #include <xenia/string.h>
#include <xenia/types.h> #include <xenia/types.h>

View File

@ -27,6 +27,8 @@
#define XE_OPTION_LOG_KERNEL 1 #define XE_OPTION_LOG_KERNEL 1
#define XE_OPTION_LOG_FS 1 #define XE_OPTION_LOG_FS 1
// Enable profiling.
#define XE_OPTION_PROFILING 1
// TODO(benvanik): make this a runtime option // TODO(benvanik): make this a runtime option
#define XE_OPTION_OPTIMIZED 0 #define XE_OPTION_OPTIMIZED 0

View File

@ -79,7 +79,9 @@ static uint32_t __stdcall xe_thread_callback_win32(void* param) {
} }
} }
xe::Profiler::ThreadEnter(thread->name);
thread->callback(thread->callback_param); thread->callback(thread->callback_param);
xe::Profiler::ThreadExit();
return 0; return 0;
} }
#pragma warning(default : 6320; default : 6322) #pragma warning(default : 6320; default : 6322)
@ -118,7 +120,9 @@ static void* xe_thread_callback_pthreads(void* param) {
#else #else
pthread_setname_np(pthread_self(), thread->name); pthread_setname_np(pthread_self(), thread->name);
#endif // OSX #endif // OSX
xe::Profiler::ThreadEnter(thread->name);
thread->callback(thread->callback_param); thread->callback(thread->callback_param);
xe::Profiler::ThreadExit();
return 0; return 0;
} }

View File

@ -253,10 +253,12 @@ X_STATUS XThread::Exit(int exit_code) {
static uint32_t __stdcall XThreadStartCallbackWin32(void* param) { static uint32_t __stdcall XThreadStartCallbackWin32(void* param) {
XThread* thread = reinterpret_cast<XThread*>(param); XThread* thread = reinterpret_cast<XThread*>(param);
xe::Profiler::ThreadEnter(thread->name());
xeKeTlsSetValue(current_thread_tls, (uint64_t)thread); xeKeTlsSetValue(current_thread_tls, (uint64_t)thread);
thread->Execute(); thread->Execute();
xeKeTlsSetValue(current_thread_tls, NULL); xeKeTlsSetValue(current_thread_tls, NULL);
thread->Release(); thread->Release();
xe::Profiler::ThreadExit();
return 0; return 0;
} }
@ -293,10 +295,12 @@ X_STATUS XThread::PlatformExit(int exit_code) {
static void* XThreadStartCallbackPthreads(void* param) { static void* XThreadStartCallbackPthreads(void* param) {
XThread* thread = reinterpret_cast<XThread*>(param); XThread* thread = reinterpret_cast<XThread*>(param);
xe::Profiler::ThreadEnter(thread->name());
xeKeTlsSetValue(current_thread_tls, (uint64_t)thread); xeKeTlsSetValue(current_thread_tls, (uint64_t)thread);
thread->Execute(); thread->Execute();
xeKeTlsSetValue(current_thread_tls, NULL); xeKeTlsSetValue(current_thread_tls, NULL);
thread->Release(); thread->Release();
xe::Profiler::ThreadExit();
return 0; return 0;
} }

88
src/xenia/profiling.cc Normal file
View File

@ -0,0 +1,88 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#define MICRO_PROFILE_IMPL
#include <xenia/profiling.h>
namespace xe {
std::unique_ptr<ProfilerDisplay> Profiler::display_ = nullptr;
void Profiler::Dump() {
MicroProfileDumpTimers();
}
void Profiler::Shutdown() {
display_.reset();
MicroProfileShutdown();
}
void Profiler::ThreadEnter(const char* name) {
MicroProfileOnThreadCreate(name);
}
void Profiler::ThreadExit() {
MicroProfileOnThreadExit();
}
void Profiler::set_display(std::unique_ptr<ProfilerDisplay> display) {
display_ = std::move(display);
}
void Profiler::Present() {
MicroProfileFlip();
if (!display_) {
return;
}
display_->Begin();
MicroProfileDraw(display_->width(), display_->height());
display_->End();
}
} // namespace xe
uint32_t MicroProfileGpuInsertTimeStamp() {
return 0;
}
uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey) {
return 0;
}
uint64_t MicroProfileTicksPerSecondGpu() {
return 0;
}
void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType type) {
auto display = xe::Profiler::display();
if (!display) {
return;
}
display->DrawBox(
nX, nY, nX1, nY1,
nColor,
static_cast<xe::ProfilerDisplay::BoxType>(type));
}
void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor) {
auto display = xe::Profiler::display();
if (!display) {
return;
}
display->DrawLine2D(nVertices, pVertices, nColor);
}
void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nLen) {
auto display = xe::Profiler::display();
if (!display) {
return;
}
display->DrawText(nX, nY, nColor, pText, nLen);
}

135
src/xenia/profiling.h Normal file
View File

@ -0,0 +1,135 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_PROFILING_H_
#define XENIA_PROFILING_H_
#include <memory>
#include <xenia/config.h>
#include <xenia/platform.h>
#include <xenia/platform_includes.h>
#include <xenia/string.h>
#include <xenia/types.h>
#if XE_OPTION_PROFILING
// Pollutes the global namespace. Yuck.
#include <microprofile/microprofile.h>
#endif // XE_OPTION_PROFILING
namespace xe {
#if XE_OPTION_PROFILING
// Defines a profiling scope for CPU tasks.
// Use `SCOPE_profile_cpu(name)` to activate the scope.
#define DEFINE_profile_cpu(name, group_name, scope_name, color) \
MICROPROFILE_DEFINE(name, group_name, scope_name, color)
// Declares a previously defined profile scope. Use in a translation unit.
#define DECLARE_profile_cpu(name) MICROPROFILE_DECLARE(name)
// Defines a profiling scope for GPU tasks.
// Use `COUNT_profile_gpu(name)` to activate the scope.
#define DEFINE_profile_gpu(name, group_name, scope_name, color) \
MICROPROFILE_DEFINE_GPU(name, group_name, scope_name, color)
// Declares a previously defined profile scope. Use in a translation unit.
#define DECLARE_profile_gpu(name) MICROPROFILE_DECLARE_GPU(name)
// Enters a previously defined CPU profiling scope, active for the duration
// of the containing block.
#define SCOPE_profile_cpu(name) \
MICROPROFILE_SCOPE(name)
// Enters a CPU profiling scope, active for the duration of the containing
// block. No previous definition required.
#define SCOPE_profile_cpu_i(group_name, scope_name, color) \
MICROPROFILE_SCOPEI(group_name, scope_name, color)
// Enters a previously defined GPU profiling scope, active for the duration
// of the containing block.
#define SCOPE_profile_gpu(name) \
MICROPROFILE_SCOPEGPU(name)
// Enters a GPU profiling scope, active for the duration of the containing
// block. No previous definition required.
#define SCOPE_profile_gpu_i(group_name, scope_name, color) \
MICROPROFILE_SCOPEGPUI(group_name, scope_name, color)
// Tracks a CPU value counter.
#define COUNT_profile_cpu(name, count) MICROPROFILE_META_CPU(name, count)
// Tracks a GPU value counter.
#define COUNT_profile_gpu(name, count) MICROPROFILE_META_GPU(name, count)
#else
#define DEFINE_profile_cpu(name, group_name, scope_name, color)
#define DEFINE_profile_gpu(name, group_name, scope_name, color)
#define DECLARE_profile_cpu(name)
#define DECLARE_profile_gpu(name)
#define SCOPE_profile_cpu(name) do {} while (false)
#define SCOPE_profile_cpu_i(group_name, scope_name, color) do {} while (false)
#define SCOPE_profile_gpu(name) do {} while (false)
#define SCOPE_profile_gpu_i(group_name, scope_name, color) do {} while (false)
#define COUNT_profile_cpu(name, count) do {} while (false)
#define COUNT_profile_gpu(name, count) do {} while (false)
#endif // XE_OPTION_PROFILING
class ProfilerDisplay {
public:
enum BoxType {
BOX_TYPE_BAR = MicroProfileBoxTypeBar,
BOX_TYPE_FLAT = MicroProfileBoxTypeFlat,
};
virtual uint32_t width() const = 0;
virtual uint32_t height() const = 0;
// TODO(benvanik): GPU timestamping.
virtual void Begin() = 0;
virtual void End() = 0;
virtual void DrawBox(int x, int y, int x1, int y1, uint32_t color, BoxType type) = 0;
virtual void DrawLine2D(uint32_t count, float* vertices, uint32_t color) = 0;
virtual void DrawText(int x, int y, uint32_t color, const char* text, size_t text_length) = 0;
};
class Profiler {
public:
// Dumps data to stdout.
static void Dump();
// Cleans up profiling, releasing all memory.
static void Shutdown();
// Activates the calling thread for profiling.
// This must be called immediately after launching a thread.
static void ThreadEnter(const char* name = nullptr);
// Deactivates the calling thread for profiling.
static void ThreadExit();
// Gets the current display, if any.
static ProfilerDisplay* display() { return display_.get(); }
// Initializes drawing with the given display.
static void set_display(std::unique_ptr<ProfilerDisplay> display);
// Presents the profiler to the bound display, if any.
static void Present();
// TODO(benvanik): display mode/pause/etc?
// TODO(benvanik): mouse, keys
private:
static std::unique_ptr<ProfilerDisplay> display_;
};
} // namespace xe
#endif // XENIA_PROFILING_H_

View File

@ -18,6 +18,8 @@
'platform.cc', 'platform.cc',
'platform.h', 'platform.h',
'platform_includes.h', 'platform_includes.h',
'profiling.cc',
'profiling.h',
'string.cc', 'string.cc',
'string.h', 'string.h',
'types.h', 'types.h',

View File

@ -24,6 +24,8 @@ using namespace xe::cpu;
int alloy_sandbox(int argc, xechar_t** argv) { int alloy_sandbox(int argc, xechar_t** argv) {
xe::Profiler::ThreadEnter("main");
XenonMemory* memory = new XenonMemory(); XenonMemory* memory = new XenonMemory();
ExportResolver* export_resolver = new ExportResolver(); ExportResolver* export_resolver = new ExportResolver();
@ -57,6 +59,9 @@ int alloy_sandbox(int argc, xechar_t** argv) {
delete runtime; delete runtime;
delete memory; delete memory;
xe::Profiler::Dump();
xe::Profiler::ThreadExit();
return 0; return 0;
} }
// ehhh // ehhh

View File

@ -22,6 +22,8 @@ DEFINE_string(target, "",
int xenia_run(int argc, xechar_t** argv) { int xenia_run(int argc, xechar_t** argv) {
int result_code = 1; int result_code = 1;
Profiler::ThreadEnter("main");
Emulator* emulator = NULL; Emulator* emulator = NULL;
// Grab path from the flag or unnamed argument. // Grab path from the flag or unnamed argument.
@ -89,6 +91,8 @@ XECLEANUP:
if (result_code) { if (result_code) {
XEFATAL("Failed to launch emulator: %d", result_code); XEFATAL("Failed to launch emulator: %d", result_code);
} }
Profiler::Dump();
Profiler::Shutdown();
return result_code; return result_code;
} }
XE_MAIN_WINDOW_THUNK(xenia_run, XETEXT("xenia-run"), "xenia-run some.xex"); XE_MAIN_WINDOW_THUNK(xenia_run, XETEXT("xenia-run"), "xenia-run some.xex");

View File

@ -39,6 +39,8 @@
'target_defaults': { 'target_defaults': {
'include_dirs': [ 'include_dirs': [
'include/', 'include/',
'third_party/',
'.',
], ],
'defines': [ 'defines': [
@ -242,6 +244,7 @@
'user32', 'user32',
'ole32', 'ole32',
'ntdll', 'ntdll',
'advapi32',
], ],
}], }],
['OS == "mac"', { ['OS == "mac"', {
@ -318,6 +321,7 @@
'xinput', 'xinput',
'xaudio2', 'xaudio2',
'Shell32', 'Shell32',
'advapi32',
], ],
}], }],
['OS == "mac"', { ['OS == "mac"', {