ppsspp/profiler/profiler.cpp

176 lines
4.1 KiB
C++
Raw Normal View History

2015-05-12 19:50:56 +02:00
// Ultra-lightweight category profiler with history.
2012-03-24 23:39:19 +01:00
#include <vector>
#include <string>
#include <map>
#include <string.h>
#include "base/logging.h"
#include "base/timeutil.h"
2015-05-12 19:50:56 +02:00
#include "gfx_es2/draw_buffer.h"
#include "profiler/profiler.h"
2012-03-24 23:39:19 +01:00
2015-05-12 19:50:56 +02:00
#define MAX_CATEGORIES 16 // Can be any number
#define MAX_DEPTH 16 // Can be any number
2015-05-12 19:50:56 +02:00
#define HISTORY_SIZE 256 // Must be power of 2
2012-03-24 23:39:19 +01:00
2015-05-12 19:50:56 +02:00
#ifndef _DEBUG
// If the compiler can collapse identical strings, we don't even need the strcmp.
#define UNIFIED_CONST_STR
#endif
2012-03-24 23:39:19 +01:00
2015-05-13 22:26:51 +02:00
struct Category {
const char *name;
};
2015-05-12 19:50:56 +02:00
struct CategoryFrame {
2015-05-13 22:26:51 +02:00
CategoryFrame() {
memset(time_taken, 0, sizeof(time_taken));
}
2015-05-12 19:50:56 +02:00
float time_taken[MAX_CATEGORIES];
2015-05-15 18:14:28 +02:00
int count[MAX_CATEGORIES];
2012-03-24 23:39:19 +01:00
};
2015-05-12 19:50:56 +02:00
struct Profiler {
int frameCount;
int historyPos;
int depth;
int parentCategory[MAX_DEPTH];
2015-05-13 22:26:51 +02:00
double eventStart[MAX_CATEGORIES];
2015-05-12 19:50:56 +02:00
double curFrameStart;
};
2012-03-24 23:39:19 +01:00
2015-05-12 19:50:56 +02:00
static Profiler profiler;
static Category categories[MAX_CATEGORIES];
static CategoryFrame *history;
2012-03-24 23:39:19 +01:00
2015-05-12 19:50:56 +02:00
void internal_profiler_init() {
2015-05-13 22:26:51 +02:00
memset(&profiler, 0, sizeof(profiler));
for (int i = 0; i < MAX_DEPTH; i++) {
profiler.parentCategory[i] = -1;
}
2015-05-12 19:50:56 +02:00
history = new CategoryFrame[HISTORY_SIZE];
2012-03-24 23:39:19 +01:00
}
int internal_profiler_find_cat(const char *category_name) {
2015-05-13 22:26:51 +02:00
int i;
for (i = 0; i < MAX_CATEGORIES; i++) {
2015-05-12 19:50:56 +02:00
const char *catname = categories[i].name;
if (!catname)
break;
#ifdef UNIFIED_CONST_STR
2015-05-13 22:26:51 +02:00
if (catname == category_name) {
2015-05-12 19:50:56 +02:00
#else
2015-05-13 22:26:51 +02:00
if (!strcmp(catname, category_name)) {
2015-05-12 19:50:56 +02:00
#endif
return i;
}
}
2015-05-13 22:26:51 +02:00
if (i < MAX_CATEGORIES && category_name) {
categories[i].name = category_name;
return i;
}
2015-05-12 19:50:56 +02:00
return -1;
2012-03-24 23:39:19 +01:00
}
// Suspend, also used to prepare for leaving.
static void internal_profiler_suspend(int category, double now) {
double diff = now - profiler.eventStart[category];
history[profiler.historyPos].time_taken[category] += (float)diff;
profiler.eventStart[category] = 0.0;
}
// Resume, also used as part of entering.
static void internal_profiler_resume(int category, double now) {
profiler.eventStart[category] = now;
}
int internal_profiler_enter(const char *category_name) {
int category = internal_profiler_find_cat(category_name);
if (category == -1 || !history) {
return category;
}
if (profiler.eventStart[category] == 0.0f) {
double now = real_time_now();
int parent = profiler.parentCategory[profiler.depth];
// Temporarily suspend the parent on entering a child.
if (parent != -1) {
internal_profiler_suspend(parent, now);
}
internal_profiler_resume(category, now);
profiler.depth++;
profiler.parentCategory[profiler.depth] = category;
} else {
2015-06-14 13:01:21 +02:00
FLOG("profiler: recursive enter (%i - %s)", category, category_name);
}
return category;
}
2015-05-12 19:50:56 +02:00
void internal_profiler_leave(int category) {
2015-05-15 18:14:28 +02:00
if (category == -1 || !history) {
2015-05-12 19:50:56 +02:00
return;
2015-05-15 18:14:28 +02:00
}
if (category < 0 || category >= MAX_CATEGORIES) {
ELOG("Bad category index %d", category);
2015-06-14 13:01:21 +02:00
profiler.depth--;
return;
2015-05-15 18:14:28 +02:00
}
double now = real_time_now();
internal_profiler_suspend(category, now);
2015-05-15 18:14:28 +02:00
history[profiler.historyPos].count[category]++;
profiler.depth--;
if (profiler.depth < 0) {
FLOG("Profiler enter/leave mismatch!");
}
int parent = profiler.parentCategory[profiler.depth];
if (parent != -1) {
// Resume tracking the parent.
internal_profiler_resume(parent, now);
}
2012-03-24 23:39:19 +01:00
}
2015-05-12 19:50:56 +02:00
void internal_profiler_end_frame() {
if (profiler.depth != 0) {
FLOG("Can't be inside a profiler scope at end of frame!");
}
2015-05-12 19:50:56 +02:00
profiler.curFrameStart = real_time_now();
profiler.historyPos++;
profiler.historyPos &= (HISTORY_SIZE - 1);
2015-05-13 22:26:51 +02:00
memset(&history[profiler.historyPos], 0, sizeof(history[profiler.historyPos]));
2012-03-24 23:39:19 +01:00
}
2015-05-13 22:26:51 +02:00
const char *Profiler_GetCategoryName(int i) {
2015-05-12 19:50:56 +02:00
return i >= 0 ? categories[i].name : "N/A";
2012-03-24 23:39:19 +01:00
}
2015-05-13 22:26:51 +02:00
int Profiler_GetHistoryLength() {
return HISTORY_SIZE;
}
int Profiler_GetNumCategories() {
2015-05-12 19:50:56 +02:00
for (int i = 0; i < MAX_CATEGORIES; i++) {
if (!categories[i].name)
return i;
}
return 0;
2012-03-24 23:39:19 +01:00
}
2015-05-13 22:26:51 +02:00
void Profiler_GetHistory(int category, float *data, int count) {
for (int i = 0; i < HISTORY_SIZE; i++) {
2015-05-15 18:14:28 +02:00
int x = i - count + profiler.historyPos + 1;
while (x < 0)
2015-05-13 22:26:51 +02:00
x += HISTORY_SIZE;
while (x >= HISTORY_SIZE)
2015-05-13 22:26:51 +02:00
x -= HISTORY_SIZE;
data[i] = history[x].time_taken[category];
}
}