Moving profiling.h to base - UI could be separated for cleanliness.
This commit is contained in:
@@ -8,6 +8,7 @@ project("xenia-base")
|
||||
defines({
|
||||
})
|
||||
includedirs({
|
||||
project_root.."/third_party/elemental-forms/src",
|
||||
project_root.."/build_tools/third_party/gflags/src",
|
||||
})
|
||||
local_platform_files()
|
||||
|
||||
313
src/xenia/base/profiling.cc
Normal file
313
src/xenia/base/profiling.cc
Normal file
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// NOTE: this must be included before microprofile as macro expansion needs
|
||||
// XELOGI.
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
// NOTE: microprofile must be setup first, before profiling.h is included.
|
||||
#define MICROPROFILE_ENABLED 1
|
||||
#define MICROPROFILEUI_ENABLED 1
|
||||
#define MICROPROFILE_IMPL 1
|
||||
#define MICROPROFILEUI_IMPL 1
|
||||
#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (1024 * 1024 * 10)
|
||||
#define MICROPROFILE_USE_THREAD_NAME_CALLBACK 1
|
||||
#define MICROPROFILE_WEBSERVER_MAXFRAMES 3
|
||||
#define MICROPROFILE_PRINTF XELOGI
|
||||
#define MICROPROFILE_WEBSERVER 0
|
||||
#define MICROPROFILE_DEBUG 0
|
||||
#define MICROPROFILE_MAX_THREADS 128
|
||||
#include "third_party/microprofile/microprofile.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
#if XE_OPTION_PROFILING
|
||||
#include "third_party/microprofile/microprofileui.h"
|
||||
#endif // XE_OPTION_PROFILING
|
||||
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
#undef DrawText
|
||||
#include "xenia/ui/microprofile_drawer.h"
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
|
||||
DEFINE_bool(show_profiler, false, "Show profiling UI by default.");
|
||||
|
||||
namespace xe {
|
||||
|
||||
ui::Window* Profiler::window_ = nullptr;
|
||||
std::unique_ptr<ui::MicroprofileDrawer> Profiler::drawer_ = nullptr;
|
||||
|
||||
#if XE_OPTION_PROFILING
|
||||
|
||||
bool Profiler::is_enabled() { return true; }
|
||||
|
||||
bool Profiler::is_visible() { return is_enabled() && MicroProfileIsDrawing(); }
|
||||
|
||||
void Profiler::Initialize() {
|
||||
// Custom groups.
|
||||
MicroProfileSetEnableAllGroups(false);
|
||||
MicroProfileForceEnableGroup("apu", MicroProfileTokenTypeCpu);
|
||||
MicroProfileForceEnableGroup("cpu", MicroProfileTokenTypeCpu);
|
||||
MicroProfileForceEnableGroup("gpu", MicroProfileTokenTypeCpu);
|
||||
MicroProfileForceEnableGroup("internal", MicroProfileTokenTypeCpu);
|
||||
g_MicroProfile.nGroupMask = g_MicroProfile.nForceGroup;
|
||||
g_MicroProfile.nActiveGroup = g_MicroProfile.nActiveGroupWanted =
|
||||
g_MicroProfile.nGroupMask;
|
||||
|
||||
// Custom timers: time, average.
|
||||
g_MicroProfile.nBars |= 0x1 | 0x2;
|
||||
g_MicroProfile.nActiveBars |= 0x1 | 0x2;
|
||||
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
MicroProfileInitUI();
|
||||
g_MicroProfileUI.bShowSpikes = true;
|
||||
g_MicroProfileUI.nOpacityBackground = 0x40u << 24;
|
||||
g_MicroProfileUI.nOpacityForeground = 0xc0u << 24;
|
||||
if (FLAGS_show_profiler) {
|
||||
MicroProfileSetDisplayMode(1);
|
||||
}
|
||||
#else
|
||||
MicroProfileSetForceEnable(true);
|
||||
MicroProfileSetEnableAllGroups(true);
|
||||
MicroProfileSetForceMetaCounters(false);
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
}
|
||||
|
||||
void Profiler::Dump() {
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
MicroProfileDumpTimers();
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
MicroProfileDumpHtml("profile.html");
|
||||
MicroProfileDumpHtmlToFile();
|
||||
}
|
||||
|
||||
void Profiler::Shutdown() {
|
||||
drawer_.reset();
|
||||
window_ = nullptr;
|
||||
MicroProfileShutdown();
|
||||
}
|
||||
|
||||
uint32_t Profiler::GetColor(const char* str) {
|
||||
std::hash<std::string> fn;
|
||||
size_t value = fn(str);
|
||||
return value & 0xFFFFFF;
|
||||
}
|
||||
|
||||
void Profiler::ThreadEnter(const char* name) {
|
||||
MicroProfileOnThreadCreate(name);
|
||||
}
|
||||
|
||||
void Profiler::ThreadExit() { MicroProfileOnThreadExit(); }
|
||||
|
||||
bool Profiler::OnKeyDown(int key_code) {
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||
switch (key_code) {
|
||||
case VK_OEM_3: // `
|
||||
MicroProfileTogglePause();
|
||||
return true;
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
case VK_TAB:
|
||||
MicroProfileToggleDisplayMode();
|
||||
return true;
|
||||
case 0x31: // 1
|
||||
MicroProfileModKey(1);
|
||||
return true;
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Profiler::OnKeyUp(int key_code) {
|
||||
switch (key_code) {
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
case 0x31: // 1
|
||||
MicroProfileModKey(0);
|
||||
return true;
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
|
||||
void Profiler::OnMouseDown(bool left_button, bool right_button) {
|
||||
MicroProfileMouseButton(left_button, right_button);
|
||||
}
|
||||
|
||||
void Profiler::OnMouseUp() { MicroProfileMouseButton(0, 0); }
|
||||
|
||||
void Profiler::OnMouseMove(int x, int y) { MicroProfileMousePosition(x, y, 0); }
|
||||
|
||||
void Profiler::OnMouseWheel(int x, int y, int dy) {
|
||||
MicroProfileMousePosition(x, y, dy);
|
||||
}
|
||||
|
||||
void Profiler::ToggleDisplay() { MicroProfileToggleDisplayMode(); }
|
||||
|
||||
void Profiler::TogglePause() { MicroProfileTogglePause(); }
|
||||
|
||||
#else
|
||||
|
||||
void Profiler::OnMouseDown(bool left_button, bool right_button) {}
|
||||
|
||||
void Profiler::OnMouseUp() {}
|
||||
|
||||
void Profiler::OnMouseMove(int x, int y) {}
|
||||
|
||||
void Profiler::OnMouseWheel(int x, int y, int dy) {}
|
||||
|
||||
void Profiler::ToggleDisplay() {}
|
||||
|
||||
void Profiler::TogglePause() {}
|
||||
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
|
||||
void Profiler::set_window(ui::Window* window) {
|
||||
assert_null(window_);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
window_ = window;
|
||||
drawer_ = std::make_unique<ui::MicroprofileDrawer>(window);
|
||||
|
||||
window_->on_painted.AddListener([](ui::UIEvent* e) { Profiler::Present(); });
|
||||
|
||||
// Pass through mouse events.
|
||||
window_->on_mouse_down.AddListener([](ui::MouseEvent* e) {
|
||||
if (Profiler::is_visible()) {
|
||||
Profiler::OnMouseDown(e->button() == ui::MouseEvent::Button::kLeft,
|
||||
e->button() == ui::MouseEvent::Button::kRight);
|
||||
e->set_handled(true);
|
||||
window_->Invalidate();
|
||||
}
|
||||
});
|
||||
window_->on_mouse_up.AddListener([](ui::MouseEvent* e) {
|
||||
if (Profiler::is_visible()) {
|
||||
Profiler::OnMouseUp();
|
||||
e->set_handled(true);
|
||||
window_->Invalidate();
|
||||
}
|
||||
});
|
||||
window_->on_mouse_move.AddListener([](ui::MouseEvent* e) {
|
||||
if (Profiler::is_visible()) {
|
||||
Profiler::OnMouseMove(e->x(), e->y());
|
||||
e->set_handled(true);
|
||||
window_->Invalidate();
|
||||
}
|
||||
});
|
||||
window_->on_mouse_wheel.AddListener([](ui::MouseEvent* e) {
|
||||
if (Profiler::is_visible()) {
|
||||
Profiler::OnMouseWheel(e->x(), e->y(), -e->dy());
|
||||
e->set_handled(true);
|
||||
window_->Invalidate();
|
||||
}
|
||||
});
|
||||
|
||||
// Watch for toggle/mode keys and such.
|
||||
window_->on_key_down.AddListener([](ui::KeyEvent* e) {
|
||||
if (Profiler::is_visible()) {
|
||||
Profiler::OnKeyDown(e->key_code());
|
||||
e->set_handled(true);
|
||||
window_->Invalidate();
|
||||
}
|
||||
});
|
||||
window_->on_key_up.AddListener([](ui::KeyEvent* e) {
|
||||
if (Profiler::is_visible()) {
|
||||
Profiler::OnKeyUp(e->key_code());
|
||||
e->set_handled(true);
|
||||
window_->Invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Profiler::Present() {
|
||||
SCOPE_profile_cpu_f("internal");
|
||||
MicroProfileFlip();
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
if (!window_ || !drawer_) {
|
||||
return;
|
||||
}
|
||||
drawer_->Begin();
|
||||
MicroProfileDraw(window_->width(), window_->height());
|
||||
drawer_->End();
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool Profiler::is_enabled() { return false; }
|
||||
bool Profiler::is_visible() { return false; }
|
||||
void Profiler::Initialize() {}
|
||||
void Profiler::Dump() {}
|
||||
void Profiler::Shutdown() {}
|
||||
uint32_t Profiler::GetColor(const char* str) { return 0; }
|
||||
void Profiler::ThreadEnter(const char* name) {}
|
||||
void Profiler::ThreadExit() {}
|
||||
bool Profiler::OnKeyDown(int key_code) { return false; }
|
||||
bool Profiler::OnKeyUp(int key_code) { return false; }
|
||||
void Profiler::OnMouseDown(bool left_button, bool right_button) {}
|
||||
void Profiler::OnMouseUp() {}
|
||||
void Profiler::OnMouseMove(int x, int y) {}
|
||||
void Profiler::OnMouseWheel(int x, int y, int dy) {}
|
||||
void Profiler::set_display(std::unique_ptr<ui::MicroprofilerDrawer> display) {}
|
||||
void Profiler::Present() {}
|
||||
|
||||
#endif // XE_OPTION_PROFILING
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#if XE_OPTION_PROFILING
|
||||
|
||||
uint32_t MicroProfileGpuInsertTimeStamp() { return 0; }
|
||||
|
||||
uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey) { return 0; }
|
||||
|
||||
uint64_t MicroProfileTicksPerSecondGpu() { return 0; }
|
||||
|
||||
const char* MicroProfileGetThreadName() { return "TODO: get thread name!"; }
|
||||
|
||||
#if XE_OPTION_PROFILING_UI
|
||||
|
||||
void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor,
|
||||
MicroProfileBoxType type) {
|
||||
auto drawer = xe::Profiler::drawer();
|
||||
if (!drawer) {
|
||||
return;
|
||||
}
|
||||
drawer->DrawBox(nX, nY, nX1, nY1, nColor,
|
||||
static_cast<xe::ui::MicroprofileDrawer::BoxType>(type));
|
||||
}
|
||||
|
||||
void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices,
|
||||
uint32_t nColor) {
|
||||
auto drawer = xe::Profiler::drawer();
|
||||
if (!drawer) {
|
||||
return;
|
||||
}
|
||||
drawer->DrawLine2D(nVertices, pVertices, nColor);
|
||||
}
|
||||
|
||||
void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText,
|
||||
uint32_t nLen) {
|
||||
auto drawer = xe::Profiler::drawer();
|
||||
if (!drawer) {
|
||||
return;
|
||||
}
|
||||
drawer->DrawText(nX, nY, nColor, pText, nLen);
|
||||
}
|
||||
|
||||
#endif // XE_OPTION_PROFILING_UI
|
||||
|
||||
#endif // XE_OPTION_PROFILING
|
||||
179
src/xenia/base/profiling.h
Normal file
179
src/xenia/base/profiling.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_BASE_PROFILING_H_
|
||||
#define XENIA_BASE_PROFILING_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/base/string.h"
|
||||
|
||||
#if XE_PLATFORM_WIN32
|
||||
#define XE_OPTION_PROFILING 1
|
||||
#define XE_OPTION_PROFILING_UI 1
|
||||
#else
|
||||
#define XE_OPTION_PROFILING 0
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
|
||||
#if XE_OPTION_PROFILING
|
||||
// Pollutes the global namespace. Yuck.
|
||||
#define MICROPROFILE_MAX_THREADS 128
|
||||
#include <microprofile/microprofile.h>
|
||||
#endif // XE_OPTION_PROFILING
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
class MicroprofileDrawer;
|
||||
class Window;
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
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) \
|
||||
MICROPROFILE_DEFINE(name, group_name, scope_name, \
|
||||
xe::Profiler::GetColor(scope_name))
|
||||
|
||||
// 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) \
|
||||
MICROPROFILE_DEFINE_GPU(name, group_name, scope_name, \
|
||||
xe::Profiler::GetColor(scope_name))
|
||||
|
||||
// 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) \
|
||||
MICROPROFILE_SCOPEI(group_name, scope_name, \
|
||||
xe::Profiler::GetColor(scope_name))
|
||||
|
||||
// Enters a CPU profiling scope by function name, active for the duration of
|
||||
// the containing block. No previous definition required.
|
||||
#define SCOPE_profile_cpu_f(group_name) \
|
||||
MICROPROFILE_SCOPEI(group_name, __FUNCTION__, \
|
||||
xe::Profiler::GetColor(__FUNCTION__))
|
||||
|
||||
// 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) \
|
||||
MICROPROFILE_SCOPEGPUI(group_name, scope_name, \
|
||||
xe::Profiler::GetColor(scope_name))
|
||||
|
||||
// Enters a GPU profiling scope by function name, active for the duration of
|
||||
// the containing block. No previous definition required.
|
||||
#define SCOPE_profile_gpu_f(group_name) \
|
||||
MICROPROFILE_SCOPEGPUI(group_name, __FUNCTION__, \
|
||||
xe::Profiler::GetColor(__FUNCTION__))
|
||||
|
||||
// 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)
|
||||
#define DEFINE_profile_gpu(name, group_name, scope_name)
|
||||
#define DECLARE_profile_cpu(name)
|
||||
#define DECLARE_profile_gpu(name)
|
||||
#define SCOPE_profile_cpu(name) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define SCOPE_profile_cpu_f(name) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define SCOPE_profile_cpu_i(group_name, scope_name) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define SCOPE_profile_gpu(name) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define SCOPE_profile_gpu_f(name) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define SCOPE_profile_gpu_i(group_name, scope_name) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define COUNT_profile_cpu(name, count) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define COUNT_profile_gpu(name, count) \
|
||||
do { \
|
||||
} while (false)
|
||||
|
||||
#ifndef MICROPROFILE_TEXT_WIDTH
|
||||
#define MICROPROFILE_TEXT_WIDTH 1
|
||||
#define MICROPROFILE_TEXT_HEIGHT 1
|
||||
#endif // !MICROPROFILE_TEXT_WIDTH
|
||||
|
||||
#endif // XE_OPTION_PROFILING
|
||||
|
||||
class Profiler {
|
||||
public:
|
||||
static bool is_enabled();
|
||||
static bool is_visible();
|
||||
|
||||
// Initializes the profiler. Call at startup.
|
||||
static void Initialize();
|
||||
// Dumps data to stdout.
|
||||
static void Dump();
|
||||
// Cleans up profiling, releasing all memory.
|
||||
static void Shutdown();
|
||||
|
||||
// Computes a color from the given string.
|
||||
static uint32_t GetColor(const char* str);
|
||||
|
||||
// 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();
|
||||
|
||||
static bool OnKeyDown(int key_code);
|
||||
static bool OnKeyUp(int key_code);
|
||||
static void OnMouseDown(bool left_button, bool right_button);
|
||||
static void OnMouseUp();
|
||||
static void OnMouseMove(int x, int y);
|
||||
static void OnMouseWheel(int x, int y, int dy);
|
||||
static void ToggleDisplay();
|
||||
static void TogglePause();
|
||||
|
||||
// Initializes input and drawing with the given display.
|
||||
static void set_window(ui::Window* window);
|
||||
// Gets the current display, if any.
|
||||
static ui::MicroprofileDrawer* drawer() { return drawer_.get(); }
|
||||
// Presents the profiler to the bound display, if any.
|
||||
static void Present();
|
||||
|
||||
private:
|
||||
static ui::Window* window_;
|
||||
static std::unique_ptr<ui::MicroprofileDrawer> drawer_;
|
||||
};
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_PROFILING_H_
|
||||
Reference in New Issue
Block a user