Profiler skeleton.
This commit is contained in:
parent
f3f9d93017
commit
6486e0a48e
|
@ -18,6 +18,7 @@
|
|||
#include <xenia/malloc.h>
|
||||
#include <xenia/platform.h>
|
||||
#include <xenia/platform_includes.h>
|
||||
#include <xenia/profiling.h>
|
||||
#include <xenia/string.h>
|
||||
#include <xenia/types.h>
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#define XE_OPTION_LOG_KERNEL 1
|
||||
#define XE_OPTION_LOG_FS 1
|
||||
|
||||
// Enable profiling.
|
||||
#define XE_OPTION_PROFILING 1
|
||||
|
||||
// TODO(benvanik): make this a runtime option
|
||||
#define XE_OPTION_OPTIMIZED 0
|
||||
|
|
|
@ -79,7 +79,9 @@ static uint32_t __stdcall xe_thread_callback_win32(void* param) {
|
|||
}
|
||||
}
|
||||
|
||||
xe::Profiler::ThreadEnter(thread->name);
|
||||
thread->callback(thread->callback_param);
|
||||
xe::Profiler::ThreadExit();
|
||||
return 0;
|
||||
}
|
||||
#pragma warning(default : 6320; default : 6322)
|
||||
|
@ -118,7 +120,9 @@ static void* xe_thread_callback_pthreads(void* param) {
|
|||
#else
|
||||
pthread_setname_np(pthread_self(), thread->name);
|
||||
#endif // OSX
|
||||
xe::Profiler::ThreadEnter(thread->name);
|
||||
thread->callback(thread->callback_param);
|
||||
xe::Profiler::ThreadExit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -253,10 +253,12 @@ X_STATUS XThread::Exit(int exit_code) {
|
|||
|
||||
static uint32_t __stdcall XThreadStartCallbackWin32(void* param) {
|
||||
XThread* thread = reinterpret_cast<XThread*>(param);
|
||||
xe::Profiler::ThreadEnter(thread->name());
|
||||
xeKeTlsSetValue(current_thread_tls, (uint64_t)thread);
|
||||
thread->Execute();
|
||||
xeKeTlsSetValue(current_thread_tls, NULL);
|
||||
thread->Release();
|
||||
xe::Profiler::ThreadExit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -293,10 +295,12 @@ X_STATUS XThread::PlatformExit(int exit_code) {
|
|||
|
||||
static void* XThreadStartCallbackPthreads(void* param) {
|
||||
XThread* thread = reinterpret_cast<XThread*>(param);
|
||||
xe::Profiler::ThreadEnter(thread->name());
|
||||
xeKeTlsSetValue(current_thread_tls, (uint64_t)thread);
|
||||
thread->Execute();
|
||||
xeKeTlsSetValue(current_thread_tls, NULL);
|
||||
thread->Release();
|
||||
xe::Profiler::ThreadExit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_
|
|
@ -18,6 +18,8 @@
|
|||
'platform.cc',
|
||||
'platform.h',
|
||||
'platform_includes.h',
|
||||
'profiling.cc',
|
||||
'profiling.h',
|
||||
'string.cc',
|
||||
'string.h',
|
||||
'types.h',
|
||||
|
|
|
@ -24,6 +24,8 @@ using namespace xe::cpu;
|
|||
|
||||
|
||||
int alloy_sandbox(int argc, xechar_t** argv) {
|
||||
xe::Profiler::ThreadEnter("main");
|
||||
|
||||
XenonMemory* memory = new XenonMemory();
|
||||
|
||||
ExportResolver* export_resolver = new ExportResolver();
|
||||
|
@ -57,6 +59,9 @@ int alloy_sandbox(int argc, xechar_t** argv) {
|
|||
delete runtime;
|
||||
delete memory;
|
||||
|
||||
xe::Profiler::Dump();
|
||||
xe::Profiler::ThreadExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
// ehhh
|
||||
|
|
|
@ -22,6 +22,8 @@ DEFINE_string(target, "",
|
|||
int xenia_run(int argc, xechar_t** argv) {
|
||||
int result_code = 1;
|
||||
|
||||
Profiler::ThreadEnter("main");
|
||||
|
||||
Emulator* emulator = NULL;
|
||||
|
||||
// Grab path from the flag or unnamed argument.
|
||||
|
@ -89,6 +91,8 @@ XECLEANUP:
|
|||
if (result_code) {
|
||||
XEFATAL("Failed to launch emulator: %d", result_code);
|
||||
}
|
||||
Profiler::Dump();
|
||||
Profiler::Shutdown();
|
||||
return result_code;
|
||||
}
|
||||
XE_MAIN_WINDOW_THUNK(xenia_run, XETEXT("xenia-run"), "xenia-run some.xex");
|
||||
|
|
Loading…
Reference in New Issue