Skip to content

Commit

Permalink
Allow displaying time-based CPU usage (#47)
Browse files Browse the repository at this point in the history
* Allow time-based CPU usage
  • Loading branch information
tiberiusbrown authored Mar 8, 2024
1 parent ced3b80 commit 6ae052f
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 14 deletions.
10 changes: 10 additions & 0 deletions src/absim.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,14 +800,24 @@ struct arduboy_t
std::array<uint64_t, NUM_INSTRS> profiler_counts;
uint64_t profiler_total;
uint64_t profiler_total_with_sleep;

// counts for previous frame
uint64_t prev_profiler_total;
uint64_t prev_profiler_total_with_sleep;
uint64_t prev_frame_cycles;
uint32_t total_frames;
uint32_t total_ms;
uint32_t frame_bytes_total;
uint32_t frame_bytes;
std::vector<float> frame_cpu_usage;

// time-based cpu usage
std::vector<float> ms_cpu_usage_raw;
std::vector<float> ms_cpu_usage;
uint64_t prev_profiler_total_ms;
uint64_t prev_profiler_total_with_sleep_ms;
uint64_t prev_ms_cycles;

bool profiler_enabled;

uint64_t cached_profiler_total;
Expand Down
38 changes: 38 additions & 0 deletions src/absim_arduboy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,18 @@ void arduboy_t::reset()
profiler_reset();
frame_cpu_usage.clear();
total_frames = 0;
total_ms = 0;
cpu.reset();
display.reset();
fx.reset();
paused = false;
break_step = 0xffffffff;

prev_profiler_total = 0;
prev_profiler_total_with_sleep = 0;
prev_ms_cycles = 0;
ms_cpu_usage.clear();

if(breakpoints.test(0))
paused = true;
}
Expand Down Expand Up @@ -464,6 +470,38 @@ ARDENS_FORCEINLINE uint32_t arduboy_t::cycle()
}
}

// time-based cpu usage
if(cpu.cycle_count >= prev_ms_cycles)
{
constexpr size_t MS_PROF_FILT_NUM = 5;
constexpr uint64_t PROF_MS = 1000000000ull * 20 / CYCLE_PS;
prev_ms_cycles += PROF_MS;

// one millisecond has passed: store cpu usage
uint64_t ms_total = profiler_total - prev_profiler_total_ms;
uint64_t ms_sleep = profiler_total_with_sleep - prev_profiler_total_with_sleep_ms;
prev_profiler_total_ms = profiler_total;
prev_profiler_total_with_sleep_ms = profiler_total_with_sleep;
double f = ms_sleep ? double(ms_total) / double(ms_sleep) : 0.0;
ms_cpu_usage_raw.push_back((float)f);
if(ms_cpu_usage_raw.size() >= MS_PROF_FILT_NUM)
{
float t = 0.f;
for(size_t i = 0; i < MS_PROF_FILT_NUM; ++i)
t += ms_cpu_usage_raw[ms_cpu_usage_raw.size() - MS_PROF_FILT_NUM + i];
ms_cpu_usage.push_back(t * (1.f / MS_PROF_FILT_NUM));
}
++total_ms;

// limit memory usage
if(ms_cpu_usage.size() >= 65536)
{
ms_cpu_usage.erase(
ms_cpu_usage.begin(),
ms_cpu_usage.begin() + 32768);
}
}

return cycles;
}

Expand Down
3 changes: 3 additions & 0 deletions src/absim_snapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,12 @@ static std::string serdes_snapshot(Archive& ar, arduboy_t& a)
ar(a.profiler_total_with_sleep);
ar(a.prev_frame_cycles);
ar(a.total_frames);
ar(a.prev_ms_cycles);
ar(a.total_ms);
ar(a.frame_bytes_total);
ar(a.frame_bytes);
ar(a.frame_cpu_usage);
ar(a.ms_cpu_usage);
ar(a.profiler_enabled);
ar(a.cached_profiler_total);
ar(a.cached_profiler_total_with_sleep);
Expand Down
2 changes: 2 additions & 0 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static void settings_read_line(
ARDENS_BOOL_SETTING(record_wav);
ARDENS_BOOL_SETTING(recording_sameasdisplay);
ARDENS_BOOL_SETTING(nondeterminism);
ARDENS_BOOL_SETTING(frame_based_cpu_usage);

ARDENS_BOOL_SETTING(ab.stack_overflow);
ARDENS_BOOL_SETTING(ab.null_deref);
Expand Down Expand Up @@ -125,6 +126,7 @@ static void settings_write_all(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ARDENS_BOOL_SETTING(record_wav);
ARDENS_BOOL_SETTING(recording_sameasdisplay);
ARDENS_BOOL_SETTING(nondeterminism);
ARDENS_BOOL_SETTING(frame_based_cpu_usage);

ARDENS_BOOL_SETTING(ab.stack_overflow);
ARDENS_BOOL_SETTING(ab.null_deref);
Expand Down
1 change: 1 addition & 0 deletions src/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct settings_t
bool profiler_group_symbols = false;
bool enable_step_breaks = true;
bool nondeterminism = false;
bool frame_based_cpu_usage = true;

struct
{
Expand Down
49 changes: 35 additions & 14 deletions src/window_cpu_usage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@

extern std::unique_ptr<absim::arduboy_t> arduboy;

static int xaxis_ms_formatter(double value, char* buf, int size, void* user)
{
(void)user;
return snprintf(buf, (size_t)size, "%.1f", value * 0.02);
}

static int yaxis_formatter(double value, char* buf, int size, void* user)
{
(void)user;
Expand All @@ -18,21 +24,29 @@ static void window_contents()
{
using namespace ImPlot;

if(arduboy->frame_cpu_usage.empty())
bool& frame_based = settings.frame_based_cpu_usage;

if(!arduboy)
return;
if(!frame_based && arduboy->ms_cpu_usage.empty() ||
frame_based && arduboy->frame_cpu_usage.empty())
return;

{
float usage = 0.f;
size_t i;
for(i = 0; i < 16; ++i)
size_t n = frame_based ? 16 : 3;
auto const& d = frame_based ? arduboy->frame_cpu_usage : arduboy->ms_cpu_usage;
for(i = 0; i < n; ++i)
{
if(i >= arduboy->frame_cpu_usage.size())
if(i >= d.size())
break;
usage += arduboy->frame_cpu_usage[arduboy->frame_cpu_usage.size() - i - 1];
usage += d[d.size() - i - 1];
}
usage /= i;
bool red = arduboy->frame_cpu_usage.back() > 0.999;
usage /= n;
bool red = usage > 0.999f;
if(red) ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255));
ImGui::AlignTextToFramePadding();
ImGui::Text("CPU Usage: %5.1f%%", usage * 100);
if(red) ImGui::PopStyleColor();
}
Expand All @@ -46,9 +60,13 @@ static void window_contents()
fps_i = (fps_i + 1) % fps_queue.size();
fps = std::accumulate(fps_queue.begin(), fps_queue.end(), 0.f) * (1.f / fps_queue.size());
ImGui::SameLine();
ImGui::Text(" FPS: %5.1f", fps);
ImGui::AlignTextToFramePadding();
ImGui::Text(" FPS: %5.1f ", fps);
}

ImGui::SameLine();
ImGui::Checkbox("Align to frames", &frame_based);

constexpr auto plot_flags =
ImPlotFlags_NoTitle |
ImPlotFlags_NoLegend |
Expand All @@ -61,8 +79,9 @@ static void window_contents()
auto* plot = GetCurrentPlot();
constexpr double ZOOM = 4.0;
constexpr double IZOOM = 1.0 / ZOOM;
double n = double(arduboy->total_frames);
double m = n - arduboy->frame_cpu_usage.size();
double n = double(frame_based? arduboy->total_frames : arduboy->total_ms);
auto const& d = frame_based ? arduboy->frame_cpu_usage : arduboy->ms_cpu_usage;
double m = n - d.size();
double w = plot->FrameRect.GetWidth();

double z = plot->Axes[ImAxis_X1].Range.Size();
Expand All @@ -74,8 +93,10 @@ static void window_contents()
ImPlotAxisFlags_NoHighlight |
//ImPlotAxisFlags_NoDecorations |
0;
SetupAxis(ImAxis_X1, "Frame", axis_flags);
SetupAxis(ImAxis_X1, frame_based ? "Frame" : "Time (s)", axis_flags);
SetupAxis(ImAxis_Y1, nullptr, axis_flags);
if(!frame_based)
SetupAxisFormat(ImAxis_X1, xaxis_ms_formatter);
SetupAxisFormat(ImAxis_Y1, yaxis_formatter);

double lim_min = m;
Expand Down Expand Up @@ -103,13 +124,13 @@ static void window_contents()
SetupFinish();
PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
PlotShaded("##usage",
arduboy->frame_cpu_usage.data(),
(int)arduboy->frame_cpu_usage.size(),
d.data(),
(int)d.size(),
0.0, 1.0, m);
PopStyleVar();
PlotLine("##usage",
arduboy->frame_cpu_usage.data(),
(int)arduboy->frame_cpu_usage.size(),
d.data(),
(int)d.size(),
1.0, m);
EndPlot();
}
Expand Down

0 comments on commit 6ae052f

Please sign in to comment.