profiler zone chunking

This commit is contained in:
jacob 2026-04-01 02:16:09 -05:00
parent 13c3bc0df4
commit ef5b79e52f
6 changed files with 443 additions and 446 deletions

View File

@ -1,38 +1,6 @@
////////////////////////////////////////////////////////////
//~ Profile zone
// void PushProfZoneEx(char *name_cstr_lit, b32 end_zone)
// {
// ProfTrack *track = Base_tl.prof.thread_track;
// if (!track)
// {
// Arena *perm = PermArena();
// {
// track = PushStruct(perm, ProfTrack);
// Base_tl.prof.thread_track = track;
// }
// LockTicketMutex(&Base.prof.register_track_tm);
// {
// Base_tl.prof.track_idx = Atomic32Fetch(&Base.prof.tracks_count);
// Base.prof.tracks[Base_tl.prof.track_idx] = track;
// Atomic32FetchAdd(&Base.prof.tracks_count, 1);
// }
// UnlockTicketMutex(&Base.prof.register_track_tm);
// }
// u64 sample_seq = track->top_sample_seq;
// ProfSample *sample = &track->samples[sample_seq % ProfTrackSamplesCap];
// {
// // TODO: Wrap rdtsc for cpu-relative <-> program-relative timestamp conversion
// sample->stamp = __rdtsc() | ((u64)(!!end_zone) << 63);
// // sample->stamp = TimeNs() | ((u64)(!!end_zone) << 63);
// sample->name_cstr_lit = name_cstr_lit;
// }
// track->top_sample_seq = sample_seq + 1;
// }
void BeginProfZone(char *name_cstr_lit)
{
ProfTrack *track = Base_tl.prof.thread_track;
@ -53,7 +21,7 @@ void BeginProfZone(char *name_cstr_lit)
UnlockTicketMutex(&Base.prof.register_track_tm);
}
u64 sample_seq = *NonAtomic(&track->top_sample_seq);
ProfSample *sample = &track->samples[sample_seq % ProfTrackSamplesCap];
ProfSample *sample = &track->samples_ring[sample_seq % ProfSamplesRingCap];
{
sample->flags = 0;
sample->name_cstr_lit = name_cstr_lit;
@ -67,7 +35,7 @@ void EndProfZone(void)
i64 tsc = EndTsc();
ProfTrack *track = Base_tl.prof.thread_track;
u64 sample_seq = *NonAtomic(&track->top_sample_seq);
ProfSample *sample = &track->samples[sample_seq % ProfTrackSamplesCap];
ProfSample *sample = &track->samples_ring[sample_seq % ProfSamplesRingCap];
{
sample->flags = ProfSampleFlag_EndZone;
sample->tsc = tsc;

View File

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////
//~ Profile types
#define ProfTrackSamplesCap Kibi(256)
#define ProfSamplesRingCap Kibi(256)
#define MaxRegisteredProfTracks Kibi(32)
Enum(ProfSampleFlag)
@ -22,7 +22,7 @@ Struct(ProfTrack)
{
u64 id;
Atomic64 top_sample_seq;
ProfSample samples[ProfTrackSamplesCap];
ProfSample samples_ring[ProfSamplesRingCap];
};
Struct(RegisteredProfTracksArray)

View File

@ -3862,11 +3862,14 @@ G_BackbufferHandle G_PrepareBackbuffer(G_SwapchainHandle swapchain_handle, G_For
// Wait for available backbuffer
if (swapchain->waitable)
{
DWORD wait_result = WaitForSingleObject(swapchain->waitable, 500);
if (wait_result == WAIT_TIMEOUT)
ProfZoneDF("Wait on swapchain")
{
ID3D12Fence_SetEventOnCompletion(swapchain->present_fence, swapchain->present_fence_target, swapchain->present_event);
WaitForSingleObject(swapchain->present_event, INFINITE);
DWORD wait_result = WaitForSingleObject(swapchain->waitable, 500);
if (wait_result == WAIT_TIMEOUT)
{
ID3D12Fence_SetEventOnCompletion(swapchain->present_fence, swapchain->present_fence_target, swapchain->present_event);
WaitForSingleObject(swapchain->present_event, INFINITE);
}
}
}

View File

@ -5377,8 +5377,7 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Collect profiler samples
ProfZoneDF("Collect profiler samples")
if (PROFILING_ENABLED)
if (PROFILING_ENABLED) ProfZoneDF("Collect profiler samples")
{
RegisteredProfTracksArray prof_tracks = FetchRegisteredProfTracks(frame->arena);
for (u64 track_idx = 0; track_idx < prof_tracks.count; ++track_idx)
@ -5386,38 +5385,139 @@ void V_TickForever(WaveLaneCtx *lane)
ProfTrack *prof_track = prof_tracks.tracks[track_idx];
//- Fetch collection track
V_ProfilerTrackCollection *col_track = 0;
V_ZoneTrack *zone_track = 0;
{
for (col_track = V.first_profiler_track_collection; col_track; col_track = col_track->next)
for (zone_track = V.first_zone_track; zone_track; zone_track = zone_track->next)
{
if (col_track->prof_track->id == prof_track->id)
if (zone_track->prof_track->id == prof_track->id)
{
break;
}
}
if (!col_track)
if (!zone_track)
{
col_track = PushStruct(perm, V_ProfilerTrackCollection);
col_track->samples_arena = AcquireArena(Gibi(64));
col_track->prof_track = prof_track;
col_track->samples = ArenaFirst(col_track->samples_arena, ProfSample);
SllQueuePush(V.first_profiler_track_collection, V.last_profiler_track_collection, col_track);
zone_track = PushStruct(perm, V_ZoneTrack);
zone_track->prof_track = prof_track;
zone_track->id = V.zone_tracks_count++;
SllQueuePush(V.first_zone_track, V.last_zone_track, zone_track);
// Init sentinel skip list chunks
for (u64 row_idx = 0; row_idx < countof(zone_track->rows); ++row_idx)
{
V_ZoneRow *row = &zone_track->rows[row_idx];
row->first_chunk = PushStruct(perm, V_ZoneChunk);
row->first_chunk->start_ns = I64Min;
row->first_chunk->end_ns = I64Min;
row->last_chunk = PushStruct(perm, V_ZoneChunk);
row->last_chunk->start_ns = I64Max;
row->last_chunk->end_ns = I64Max;
for (u64 level = 0; level < V_ZoneChunkLevelsCount; ++level)
{
row->first_chunk->nexts[level] = row->last_chunk;
row->last_chunk->prevs[level] = row->first_chunk;
}
}
}
}
//- Copy new samples
u64 copy_sample_start_seq = col_track->next_collection_seq;
u64 copy_sample_end_seq = Atomic64Fetch(&prof_track->top_sample_seq);
u64 copy_samples_count = copy_sample_end_seq - copy_sample_start_seq;
ProfSample *copy_samples_dst = PushStructsNoZero(col_track->samples_arena, ProfSample, copy_samples_count);
for (u64 src_sample_seq = copy_sample_start_seq; src_sample_seq < copy_sample_end_seq; ++src_sample_seq)
//- Process new samples
{
u64 src_idx = src_sample_seq % ProfTrackSamplesCap;
u64 dst_idx = src_sample_seq - copy_sample_start_seq;
copy_samples_dst[dst_idx] = prof_track->samples[src_idx];
// TODO: Clamp collection size
u64 sample_start_seq = zone_track->next_collection_sample_seq;
u64 sample_end_seq = Atomic64Fetch(&prof_track->top_sample_seq);
u64 samples_count = sample_end_seq - sample_start_seq;
f64 ns_per_tsc = GetNsPerTsc();
i64 startup_tsc = GetStartupTsc();
for (u64 sample_seq = sample_start_seq; sample_seq < sample_end_seq; ++sample_seq)
{
u64 sample_idx = sample_seq % ProfSamplesRingCap;
ProfSample *sample = &prof_track->samples_ring[sample_idx];
i64 sample_time_ns = (sample->tsc - startup_tsc) * ns_per_tsc;
b32 is_begin_zone = !(sample->flags & ProfSampleFlag_EndZone);
b32 is_end_zone = !is_begin_zone;
if (is_begin_zone)
{
//- Start zone
if (zone_track->current_sample_depth < V_MaxZoneDepth)
{
u64 zone_id = V.total_zones_count++;
V_ZoneRow *row = &zone_track->rows[zone_track->current_sample_depth];
//- Fetch chunk
V_ZoneChunk *chunk = row->last_chunk->prevs[0];
{
b32 is_first_chunk = chunk->end_ns == I64Min;
if (chunk->zones_count >= V_MaxZonesPerChunk || is_first_chunk)
{
chunk = PushStruct(perm, V_ZoneChunk);
chunk->end_ns = I64Max;
for (u32 level = 0; level < V_ZoneChunkLevelsCount; ++level)
{
// Insert into skip list
V_ZoneChunk *prev_chunk = row->last_chunk->prevs[level];
DllQueueInsertNP(
row->first_chunk,
row->last_chunk,
prev_chunk,
chunk,
nexts[level],
prevs[level]
);
if (MixU64(zone_id) % 2)
{
// Exit skip list initialization
break;
}
}
}
}
//- Push zone
u64 chunk_zone_idx = chunk->zones_count++;
V_Zone *zone = &chunk->zones[chunk_zone_idx];
{
zone->id = zone_id;
zone->start_ns = sample_time_ns;
zone->end_ns = I64Max;
// TODO: More efficient name processing
char *name_cstr = sample->name_cstr_lit;
String name = StringFromCstrNoLimit(name_cstr);
zone->name = name;
u64 color_seed = HashString(name);
f32 h = (Norm16(color_seed >> 0) * 1) * 360;
f32 s = TweakFloat("Profiler zone saturation", 0.50, 0, 1);
f32 v = TweakFloat("Profiler zone brightness", 1.00, 0, 1);
zone->color = SrgbFromHsv(h, s, v);
}
zone_track->rows_count = MaxU64(zone_track->rows_count, zone_track->current_sample_depth);
}
zone_track->current_sample_depth += 1;
}
else if (is_end_zone)
{
//- End zone
zone_track->current_sample_depth -= 1;
if (zone_track->current_sample_depth < V_MaxZoneDepth)
{
V_ZoneRow *row = &zone_track->rows[zone_track->current_sample_depth];
V_ZoneChunk *chunk = row->last_chunk->prevs[0];
V_Zone *zone = &chunk->zones[chunk->zones_count - 1];
zone->end_ns = sample_time_ns;
chunk->end_ns = sample_time_ns;
}
}
}
zone_track->next_collection_sample_seq = sample_end_seq;
}
col_track->next_collection_seq = copy_sample_end_seq;
col_track->samples_count += copy_samples_count;
}
}
@ -5427,8 +5527,6 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Build profiler
@ -5465,47 +5563,6 @@ void V_TickForever(WaveLaneCtx *lane)
profiler->graph_dims = DimsFromRng2(UI_Rect(profiler_graph_box));
//- Init test samples
// // FIXME: Remove this
// Struct(SampleState)
// {
// i64 ready_samples_count;
// Arena *samples_arena;
// };
// Struct(Sample)
// {
// u64 zone_id;
// u64 thread_id;
// i64 start_ns;
// i64 end_ns;
// };
// PERSIST i64 sample_states_count = 1;
// PERSIST SampleState *sample_states = 0;
// if (!sample_states)
// {
// sample_states = PushStructs(perm, SampleState, sample_states_count);
// for (i64 sample_state_idx = 0; sample_state_idx < sample_states_count; ++sample_state_idx)
// {
// SampleState *ss = &sample_states[sample_state_idx];
// ss->samples_arena = AcquireArena(Gibi(64));
// ss->ready_samples_count = 128;
// for (i64 sample_idx = 0; sample_idx < ss->ready_samples_count; ++sample_idx)
// {
// Sample *sample = PushStruct(ss->samples_arena, Sample);
// sample->zone_id = (u64)"Hello there";
// sample->thread_id = 0;
// sample->start_ns = NsFromSeconds(sample_idx);
// sample->end_ns = NsFromSeconds(sample_idx + 1);
// }
// }
// }
// FIXME: Remove this
{
@ -5533,7 +5590,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Size graph_height = UI_Fnt(2, 1);
UI_Size main_height = UI_Grow(1, 0);
UI_Size zone_height = UI_Fnt(1.25, 0);
UI_Size track_height = UI_Fnt(25, 0);
UI_Size track_height = UI_Fnt(10, 0);
f32 zone_text_padding_px = UI_Top(FontSize) * 0.2;
// Vec2 old_main_dims = DimsFromRng2(UI_Rect(main_box));
@ -5625,6 +5682,7 @@ void V_TickForever(WaveLaneCtx *lane)
}
// Drag ruler
// TODO: When measuring stopped, lerp ruler closed
b32 is_measuring = 0;
if (UI_Downs(main_box, Button_M1))
{
@ -5664,6 +5722,100 @@ void V_TickForever(WaveLaneCtx *lane)
// FIXME: Remove this
f64 view_range_len_px = DimsFromRng2(UI_Rect(main_box)).x;
f64 view_range_len_ns = view_range_len_px * profiler->ns_per_px;
f64 view_start_ns = profiler->view_ns;
f64 view_end_ns = view_start_ns + view_range_len_ns;
//- Visible zones
Struct(VisRow)
{
VisRow *next;
V_ZoneRow *zone_row;
V_ZoneChunk *closest_zone_chunk;
};
Struct(VisTrack)
{
VisTrack *next;
V_ZoneTrack *zone_track;
VisRow *first_row;
VisRow *last_row;
};
VisTrack *first_vis_track = 0;
VisTrack *last_vis_track = 0;
//- Compute visible zones
ProfZoneDF("Compute visible zones")
{
for (V_ZoneTrack *zone_track = V.first_zone_track; zone_track; zone_track = zone_track->next)
{
// TODO: Ignore non-visible tracks
VisTrack *vis_track = PushStruct(frame->arena, VisTrack);
SllQueuePush(first_vis_track, last_vis_track, vis_track);
vis_track->zone_track = zone_track;
// TODO: Ignore non-visible rows
for (u64 row_idx = 0; row_idx < zone_track->rows_count; ++row_idx)
{
V_ZoneRow *zone_row = &zone_track->rows[row_idx];
V_ZoneChunk *closest_start = zone_row->last_chunk;
{
for (i32 level = countof(closest_start->prevs) - 1; level >= 0; --level)
{
while (closest_start->prevs[level] && closest_start->prevs[level]->end_ns >= view_start_ns)
{
closest_start = closest_start->prevs[level];
}
}
}
if (closest_start->end_ns >= view_start_ns && closest_start->start_ns <= view_end_ns)
{
VisRow *vis_row = PushStruct(perm, VisRow);
SllQueuePush(vis_track->first_row, vis_track->last_row, vis_row);
vis_row->zone_row = zone_row;
vis_row->closest_zone_chunk = closest_start;
}
}
}
}
// f64 ns_per_px = MaxF64((profiler->view_end_ns - profiler->view_start_ns) / old_main_dims.x, 1);
@ -5676,13 +5828,20 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Size timeline_cursor_width = UI_Fnt(0.15, 1);
UI_Key hovered_zone_box = Zi;
V_ZoneDesc *hovered_zone = 0;
V_Zone *hovered_zone = 0;
f64 ruler_len_ns = 0;
Vec4 main_color = profiler_color;
main_color.r *= 0.75;
main_color.g *= 0.75;
main_color.b *= 0.75;
Vec4 main_color_sampled = profiler_color;
main_color_sampled.r *= 0.75;
main_color_sampled.g *= 0.75;
main_color_sampled.b *= 0.75;
Vec4 main_color_unsampled = main_color_sampled;
main_color_unsampled.r *= 0.85;
main_color_unsampled.g *= 0.85;
main_color_unsampled.b *= 0.85;
// main_color_sampled.g += 0.05;
UI_SetNext(Parent, vis_ui_box);
UI_SetNext(BorderColor, theme.col.window_bd);
@ -5699,132 +5858,6 @@ void V_TickForever(WaveLaneCtx *lane)
UI_BuildSpacer(window_padding, Axis_X);
UI_SetDF(Parent, UI_BuildColumn())
{
//- Build zone tracks
i64 highest_sample_ns = 0;
V_ZoneTrack *first_zone_track = 0;
V_ZoneTrack *last_zone_track = 0;
{
for (V_ProfilerTrackCollection *col_track = V.first_profiler_track_collection; col_track; col_track = col_track->next)
{
// FIXME: Remove this
// if (track_idx == 0) continue;
V_ZoneTrack *zone_track = PushStruct(frame->arena, V_ZoneTrack);
DllQueuePush(first_zone_track, last_zone_track, zone_track);
// FIXME: Atomic
u64 samples_count = col_track->samples_count;
ProfSample *samples = col_track->samples;
u64 start_sample_idx = 0;
samples_count = MinU64(samples_count, 512);
// samples_count = MinU64(samples_count, Kibi(16));
// u64 samples_start_seq = track_top_sample_seq - MinU64(track_top_sample_seq, ProfTrackSamplesCap);
// u64 samples_end_seq = track_top_sample_seq;
// for (u64 sample_seq = samples_start_seq; sample_seq < samples_end_seq
// samples_end_seq = MinU64(samples_end_seq, samples_start_seq + 512);
// samples_end_seq = MinU64(samples_end_seq, samples_start_seq + 64);
// // samples_end_seq = MinU64(samples_end_seq, samples_start_seq + Kibi(16));
// u64 zones_count = samples_end_seq - samples_start_seq;
// zones_count = MinU64(zones_count, 1000);
// V_ZoneDesc *zones = PushStructs(frame->arena, V_ZoneDesc, zones_count);
//- Create zones
ProfZoneDF("Create zones")
{
// FIXME: Clamp depth
// u64 zone_idx = 0;
u64 depth = 0;
for (u64 sample_idx = start_sample_idx; sample_idx < samples_count; ++sample_idx)
{
ProfSample *sample = &samples[sample_idx];
// u64 elapsed_ns = NsFromTsc
i64 time_ns = (sample->tsc - GetStartupTsc()) * GetNsPerTsc();
b32 is_end = !!(sample->flags & ProfSampleFlag_EndZone);
if (is_end)
{
depth -= 1;
V_ZoneDesc *zone = zone_track->last_zone;
// FIXME: OOB
for (; zone->depth > depth;)
{
zone = zone->prev;
}
zone->end_ns = time_ns;
// zone->end_sample_seq = sample_seq;
highest_sample_ns = MaxI64(highest_sample_ns, time_ns);
}
else
{
V_ZoneDesc *zone = PushStruct(frame->arena, V_ZoneDesc);
zone->start_ns = time_ns;
DllQueuePush(zone_track->first_zone, zone_track->last_zone, zone);
char *name_cstr = sample->name_cstr_lit;
String name = StringFromCstrNoLimit(name_cstr);
// TODO: Also factor in sample source code location
u64 seed = HashString(name);
// u64 seed = MixU64((u64)name_cstr);
f32 h = (Norm16(seed >> 0) * 1) * 360;
// f32 s = TweakFloat("Profiler zone saturation", 0.85, 0, 1);
// f32 v = TweakFloat("Profiler zone brightness", 0.50, 0, 1);
f32 s = TweakFloat("Profiler zone saturation", 0.50, 0, 1);
f32 v = TweakFloat("Profiler zone brightness", 1.00, 0, 1);
zone->color = SrgbFromHsv(h, s, v);
// zone->start_sample_seq = sample_seq;
zone->name = name;
zone->depth = depth;
// TODO: Real zone ID
zone->id = MixU64s(sample_idx, col_track->prof_track->id);
depth += 1;
zone_track->zone_rows_count = MaxU64(depth, zone_track->zone_rows_count);
}
}
}
//- Push zones to rows
zone_track->zone_rows = PushStructs(frame->arena, V_ZoneRow, zone_track->zone_rows_count);
for (V_ZoneDesc *zone = zone_track->first_zone; zone; zone = zone->next)
{
// FIXME: Large depth
V_ZoneRow *row = &zone_track->zone_rows[zone->depth];
row->count += 1;
DllQueuePushNP(row->first_zone, row->last_zone, zone, next_in_row, prev_in_row);
}
}
}
//- Header
// UI_SetDF(BackgroundColor, Color_Red)
// UI_SetNext(BorderColor, Color_Red);
@ -5836,6 +5869,9 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetDF(TextColor, theme.col.hint)
UI_BuildLabelF("Profiler");
}
UI_BuildSpacer(window_padding, Axis_Y);
UI_BuildDivider(UI_Px(1, 1), theme.col.divider, Axis_Y);
//- Graph
@ -5846,121 +5882,80 @@ void V_TickForever(WaveLaneCtx *lane)
}
// UI_BuildDivider(UI_Px(1, 1), theme.col.divider, Axis_Y);
UI_BuildDivider(UI_Px(1, 1), theme.col.divider, Axis_Y);
UI_BuildSpacer(window_padding, Axis_Y);
//- Main area
UI_SetNext(BackgroundColor, main_color);
UI_SetNext(BackgroundColor, main_color_unsampled);
UI_SetNext(Height, main_height);
UI_SetNext(Rounding, UI_Rpx(4));
UI_SetNext(Rounding, UI_Rpx(10));
// UI_SetNext(Flags, UI_BoxFlag_CaptureMouse | UI_BoxFlag_CaptureThroughChildren | UI_BoxFlag_Scissor);
UI_SetNext(Flags, UI_BoxFlag_CaptureMouse | UI_BoxFlag_CaptureThroughChildren);
// UI_SetNext(Flags, UI_BoxFlag_CaptureMouse);
UI_SetDF(Parent, UI_BuildColumnEx(main_box))
{
//- Ruler
UI_SetDF(Opacity, profiler->ruler_opacity)
//- Active area background
UI_SetDF(Opacity, 0.75)
{
f64 aabg_left_ns = MaxF64(0, profiler->view_ns);
f64 aabg_right_ns = MinF64(frame->time_ns, view_end_ns);
f64 aabg_len_ns = aabg_right_ns - aabg_left_ns;
f64 aabg_len_px = aabg_len_ns / profiler->ns_per_px;
f64 aabg_cursor_offset_px = (aabg_left_ns - profiler->view_ns) / profiler->ns_per_px;
f32 aabg_offset_px = (aabg_left_ns - profiler->view_ns) / profiler->ns_per_px;
Vec2 aabg_cursor_pos = VEC2(aabg_cursor_offset_px, 0);
Vec2 aabg_pos = VEC2(aabg_offset_px, 0);
UI_Size aabg_width = UI_Px(aabg_len_px, 1);
Vec4 aabg_color = main_color_sampled;
// Ruler rect
{
f64 ruler_left_ns = MinF64(profiler->ruler_start_ns, profiler->cursor_ns);
f64 ruler_right_ns = MaxF64(profiler->ruler_start_ns, profiler->cursor_ns);
ruler_len_ns = ruler_right_ns - ruler_left_ns;
f64 ruler_len_px = ruler_len_ns / profiler->ns_per_px;
f64 ruler_cursor_offset_px = (profiler->ruler_start_ns - profiler->view_ns) / profiler->ns_per_px;
f32 ruler_offset_px = (ruler_left_ns - profiler->view_ns) / profiler->ns_per_px;
Vec2 ruler_cursor_pos = VEC2(ruler_cursor_offset_px, 0);
Vec2 ruler_pos = VEC2(ruler_offset_px, 0);
UI_Size ruler_width = UI_Px(ruler_len_px, 1);
Vec4 ruler_color = VEC4(0.25, 0.25, 0.25, 0.25);
// Ruler rect
{
// UI_SetNext(BorderSize, 1);
// UI_SetNext(BorderColor, Color_White);
// UI_SetDF(Opacity, profiler->ruler_opacity)
UI_SetNext(Width, ruler_width);
UI_SetNext(FloatingPos, ruler_pos);
UI_SetNext(BackgroundColor, ruler_color);
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_BuildBoxEx(UI_KeyF("ruler"));
}
// Ruler cursor
{
// UI_SetNext(BorderSize, 1);
// UI_SetNext(BorderColor, Color_White);
UI_SetNext(BackgroundColor, timeline_cursor_color);
UI_SetNext(Width, timeline_cursor_width);
UI_SetNext(FloatingPos, ruler_cursor_pos);
UI_SetNext(Anchor, UI_Region_Top);
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_BuildBoxEx(UI_KeyF("ruler cursor"));
}
// UI_SetNext(BorderSize, 1);
// UI_SetNext(BorderColor, Color_White);
UI_SetNext(Width, aabg_width);
UI_SetNext(FloatingPos, aabg_pos);
UI_SetNext(BackgroundColor, aabg_color);
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_BuildBoxEx(UI_KeyF("active area background"));
}
}
//- Zone tracks
{
u64 zone_track_idx = 0;
for (V_ZoneTrack *zone_track = first_zone_track; zone_track; zone_track = zone_track->next)
for (VisTrack *vis_track = first_vis_track; vis_track; vis_track = vis_track->next)
{
// FIXME: Remove this
// if (track_idx != 0) continue;
V_ZoneTrack *zone_track = vis_track->zone_track;
UI_Key track_box = UI_KeyF("track %F", FmtUint(zone_track_idx));
UI_SetNext(Height, track_height);
// UI_SetNext(Flags, UI_BoxFlag_CaptureMouse);
UI_SetDF(Tag, track_box.v)
UI_SetDF(Parent, UI_BuildColumnEx(track_box))
UI_SetDF(Parent, UI_BuildColumn())
{
// // Binary search to find samples range
// // FIXME: Atomic
// ProfSample *samples = track->samples;
// u64 samples_start_seq = track->top_sample_seq - MinU64(track->top_sample_seq, ProfTrackSamplesCap);
// u64 samples_end_seq = track->new_sample_seq;
// {
// // i64 search_seq = samples_start_seq + (samples_end_seq - samples_start_seq) / 2;
// i64 search_start_seq = samples_start_seq;
// i64 search_end_seq = samples_end_seq;
// while (search_end_seq > search_start_seq)
// {
// if (samples[search_start_seq % ProfTrackSamplesCap].
// }
// samples_start_seq = search_start_seq;
// }
// FIXME: Remove this
f64 view_range_len_px = DimsFromRng2(UI_Rect(main_box)).x;
f64 view_range_len_ns = view_range_len_px * profiler->ns_per_px;
// Build zone rows
for (VisRow *row = vis_track->first_row; row; row = row->next)
{
for (u64 zone_row_idx = 0; zone_row_idx < zone_track->zone_rows_count; ++zone_row_idx)
//- Zone row
// UI_SetNext(Height, zone_height);
UI_SetNext(Height, zone_height);
UI_SetDF(Parent, UI_BuildRow())
{
V_ZoneRow *row = &zone_track->zone_rows[zone_row_idx];
//- Zone row
// UI_SetNext(Height, zone_height);
UI_SetNext(Height, zone_height);
UI_SetDF(Parent, UI_BuildRow())
for (V_ZoneChunk *chunk = row->closest_zone_chunk; chunk && chunk->start_ns <= view_end_ns; chunk = chunk->nexts[0])
{
//- Zones in row
for (V_ZoneDesc *zone = row->first_zone; zone; zone = zone->next_in_row)
b32 reached_end_of_visible_chunk = 0;
for (u64 chunk_zone_idx = 0; chunk_zone_idx < chunk->zones_count && !reached_end_of_visible_chunk; ++chunk_zone_idx)
{
// FIXME: Clamp to end of timeline
i64 visual_start_ns = MaxI64(zone->start_ns, profiler->view_ns);
i64 visual_end_ns = MinI64(zone->end_ns, profiler->view_ns + view_range_len_ns);
f64 visual_len_px = (visual_end_ns - visual_start_ns) / profiler->ns_per_px;
V_Zone *zone = &chunk->zones[chunk_zone_idx];
if (visual_len_px > 1)
i64 visual_zone_start_ns = MaxI64(zone->start_ns, profiler->view_ns);
i64 visual_zone_end_ns = MinI64(zone->end_ns, profiler->view_ns + view_range_len_ns);
f64 visual_zone_len_px = (visual_zone_end_ns - visual_zone_start_ns) / profiler->ns_per_px;
if (visual_zone_start_ns > view_end_ns || zone->end_ns == I64Max)
{
reached_end_of_visible_chunk = 1;
}
else if (visual_zone_end_ns >= view_start_ns && visual_zone_len_px > 5)
{
UI_Key zone_box = UI_KeyF("Zone %F", FmtUint(zone->id));
if (UI_HotAbsolute(zone_box))
@ -5998,8 +5993,8 @@ void V_TickForever(WaveLaneCtx *lane)
f64 zone_offset_px = (visual_start_ns - profiler->view_ns) / profiler->ns_per_px;
f64 zone_len_ns = visual_end_ns - visual_start_ns;
f64 zone_offset_px = (visual_zone_start_ns - profiler->view_ns) / profiler->ns_per_px;
f64 zone_len_ns = visual_zone_end_ns - visual_zone_start_ns;
f64 zone_len_px = zone_len_ns / profiler->ns_per_px;
@ -6048,15 +6043,16 @@ void V_TickForever(WaveLaneCtx *lane)
// UI_BuildSpacer(UI_Px(zone_text_padding_px, 0), Axis_X);
// UI_BuildSpacer(UI_Grow(1, 0), Axis_X);
UI_SetNext(Width, UI_Shrink(0, 1));
// UI_SetNext(Width, UI_Shrink(0, 1));
UI_SetNext(Width, UI_Shrink(0, 0));
// UI_SetNext(Width, UI_Grow(1, 1));
UI_SetNext(ChildAlignment, UI_Region_Center);
// UI_SetNext(ChildAlignment, UI_Region_Left);
UI_SetNext(FontSize, UI_Top(FontSize) * theme.h5);
UI_SetNext(TextColor, zone_text_color);
UI_SetNext(Text, zone->name);
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_DontTruncateText);
// UI_SetNext(Flags, UI_BoxFlag_DrawText);
// UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_DontTruncateText);
UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_BuildRow();
// UI_BuildSpacer(UI_Px(zone_text_padding_px, 1), Axis_X);
@ -6068,49 +6064,7 @@ void V_TickForever(WaveLaneCtx *lane)
}
}
}
// for (u64 zone_idx = 0; zone_idx < zones_count; ++zone_idx)
// {
// V_ZoneDesc *zone = &zones[zone_idx];
// UI_Key zone_box = UI_KeyF("Zone %F", FmtUint(zone_idx));
// Vec4 zone_color = zone->color;
// zone_color = LerpSrgb(zone_color, Color_Cyan, UI_Hot(zone_box));
// // Vec4 zone_color_bd = Zi;
// // zone_color_bd
// i64 zone_len_ns = zone->end_ns - zone->start_ns;
// f32 zone_len_px = zone_len_ns / profiler->ns_per_px;
// // i6
// f32 zone_offset_px = (zone->start_ns - profiler->view_ns) / profiler->ns_per_px;
// Vec2 zone_pos = VEC2(zone_offset_px, 0);
// UI_Size zone_width = UI_Px(zone_len_px, 1);
// UI_SetNext(Text, StringF(frame->arena, "ZONE %F", FmtUint(zone_idx)));
// // if (do_break && UI_IsMouseHovered(zone_box))
// if (do_break && zone_idx == 0)
// {
// UI_SetNext(DebugBreakFlags, UI_DebugBreakFlag_BuildFeedback | UI_DebugBreakFlag_CheckCursorHover);
// }
// UI_SetNext(Width, zone_width);
// UI_SetNext(Height, zone_height);
// UI_SetNext(BackgroundColor, zone_color);
// UI_SetNext(FloatingPos, zone_pos);
// UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_DontClampFloatingX | UI_BoxFlag_DontClampFloatingY | UI_BoxFlag_CaptureMouse);
// // UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_DontClampFloatingX | UI_BoxFlag_DontClampFloatingY);
// UI_SetDF(Parent, UI_BuildBoxEx(zone_box))
// {
// }
// }
}
zone_track_idx += 1;
}
}
@ -6118,9 +6072,49 @@ void V_TickForever(WaveLaneCtx *lane)
//- Ruler
UI_SetDF(Opacity, profiler->ruler_opacity)
{
{
f64 ruler_left_ns = MinF64(profiler->ruler_start_ns, profiler->cursor_ns);
f64 ruler_right_ns = MaxF64(profiler->ruler_start_ns, profiler->cursor_ns);
ruler_len_ns = ruler_right_ns - ruler_left_ns;
f64 ruler_len_px = ruler_len_ns / profiler->ns_per_px;
f64 ruler_cursor_offset_px = (profiler->ruler_start_ns - profiler->view_ns) / profiler->ns_per_px;
f32 ruler_offset_px = (ruler_left_ns - profiler->view_ns) / profiler->ns_per_px;
Vec2 ruler_cursor_pos = VEC2(ruler_cursor_offset_px, 0);
Vec2 ruler_pos = VEC2(ruler_offset_px, 0);
UI_Size ruler_width = UI_Px(ruler_len_px, 1);
Vec4 ruler_color = VEC4(0.25, 0.25, 0.25, 0.25);
// Ruler rect
{
// UI_SetNext(BorderSize, 1);
// UI_SetNext(BorderColor, Color_White);
// UI_SetDF(Opacity, profiler->ruler_opacity)
UI_SetNext(Width, ruler_width);
UI_SetNext(FloatingPos, ruler_pos);
UI_SetNext(BackgroundColor, ruler_color);
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_BuildBoxEx(UI_KeyF("ruler"));
}
// Ruler cursor
{
// UI_SetNext(BorderSize, 1);
// UI_SetNext(BorderColor, Color_White);
UI_SetNext(BackgroundColor, timeline_cursor_color);
UI_SetNext(Width, timeline_cursor_width);
UI_SetNext(FloatingPos, ruler_cursor_pos);
UI_SetNext(Anchor, UI_Region_Top);
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_BuildBoxEx(UI_KeyF("ruler cursor"));
}
}
}
//- Timeline cursor
{
@ -6182,24 +6176,24 @@ void V_TickForever(WaveLaneCtx *lane)
{
// UI_SetNext(TextColor, theme.col.positive);
// UI_SetNext(TextColor, theme.col.button_active);
UI_BuildLabelF("%F", FmtTimeNs(ruler_len_ns, .p = 3));
UI_BuildLabelF("%F", FmtTimeNs(ruler_len_ns, .p = 2));
}
if (show_hovered_zone)
{
V_ZoneDesc *zone = hovered_zone;
V_Zone *zone = hovered_zone;
// UI_BuildLabelF("Hi!!");
i64 zone_elapsed_ns = zone->end_ns - zone->start_ns;
// UI_BuildLabelF("%Fms", FmtFloat(MsFromNs(zone_elapsed_ns), .p = 3));
// UI_BuildLabelF("%Fms", FmtFloat(MsFromNs(zone_elapsed_ns), .p = 2));
UI_SetDF(Parent, UI_BuildRow())
{
UI_SetNext(TextColor, theme.col.hint);
UI_BuildLabelF("%F: ", FmtString(zone->name));
UI_BuildLabelF("%F", FmtTimeNs(zone_elapsed_ns, .p = 3));
UI_BuildLabelF("%F", FmtTimeNs(zone_elapsed_ns, .p = 2));
}
}
@ -6227,8 +6221,8 @@ void V_TickForever(WaveLaneCtx *lane)
UI_SetDF(TextColor, theme.col.warn)
UI_SetDF(Parent, UI_BuildRow())
{
// UI_BuildIcon(theme.icon_font, UI_Icon_Warning);
UI_BuildIcon(theme.icon_font, UI_Icon_Info);
UI_BuildIcon(theme.icon_font, UI_Icon_Warning);
// UI_BuildIcon(theme.icon_font, UI_Icon_Info);
UI_BuildLabelF(" Profiling an unoptimized build");
}
}
@ -6245,6 +6239,49 @@ void V_TickForever(WaveLaneCtx *lane)
}
//////////////////////////////
//- Build notifications

View File

@ -240,29 +240,37 @@ Struct(V_Palette)
////////////////////////////////////////////////////////////
//~ Profiler types
Struct(V_ZoneDesc)
#define V_MaxZonesPerChunk 256
#define V_ZoneChunkLevelsCount 32
#define V_MaxZoneDepth 128
Struct(V_Zone)
{
V_ZoneDesc *prev;
V_ZoneDesc *next;
V_ZoneDesc *prev_in_row;
V_ZoneDesc *next_in_row;
String name;
u64 id;
u32 depth;
Vec4 color;
i64 start_ns;
i64 end_ns;
};
Struct(V_ZoneChunk)
{
V_ZoneChunk *nexts[V_ZoneChunkLevelsCount];
V_ZoneChunk *prevs[V_ZoneChunkLevelsCount];
i64 start_ns;
i64 end_ns;
u64 zones_count;
V_Zone zones[V_MaxZonesPerChunk];
};
Struct(V_ZoneRow)
{
u64 count;
V_ZoneDesc *first_zone;
V_ZoneDesc *last_zone;
// Skip list sentinels
V_ZoneChunk *first_chunk;
V_ZoneChunk *last_chunk;
};
Struct(V_ZoneTrack)
@ -270,13 +278,28 @@ Struct(V_ZoneTrack)
V_ZoneTrack *next;
V_ZoneTrack *prev;
V_ZoneDesc *first_zone;
V_ZoneDesc *last_zone;
// FIXME: Set this
u64 id;
u64 zone_rows_count;
V_ZoneRow *zone_rows;
u64 rows_count;
V_ZoneRow rows[V_MaxZoneDepth];
ProfTrack *prof_track;
u64 next_collection_sample_seq;
u64 current_sample_depth;
};
Struct(V_Profiler)
{
Vec2 graph_dims;
@ -386,18 +409,6 @@ Struct(V_ObservationBin)
#define V_MaxInterpRatio 4
Struct(V_ProfilerTrackCollection)
{
V_ProfilerTrackCollection *next;
u64 samples_count;
ProfSample *samples;
Arena *samples_arena;
ProfTrack *prof_track;
u64 next_collection_seq;
};
Struct(V_Frame)
{
Arena *arena;
@ -446,11 +457,10 @@ Struct(V_Ctx)
Arena *transient_markers_arena;
Arena *persistent_markers_arena;
V_ProfilerTrackCollection *first_profiler_track_collection;
V_ProfilerTrackCollection *last_profiler_track_collection;
u64 profiler_samples_count;
ProfSample *profile_samples;
u64 total_zones_count;
u64 zone_tracks_count;
V_ZoneTrack *first_zone_track;
V_ZoneTrack *last_zone_track;
i64 panels_count;
i64 windows_count;

View File

@ -199,43 +199,22 @@ UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
dfs->visited = 1;
result.box = box;
result.pre = 1;
// Push floating children to dfs stack
// Push children to dfs stack
for (UI_Box *child = box->last; child; child = child->prev)
{
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating))
UI_BoxIterDfsNode *child_dfs = iter->first_free;
if (child_dfs)
{
UI_BoxIterDfsNode *child_dfs = iter->first_free;
if (child_dfs)
{
SllQueuePop(iter->first_free, iter->last_free);
ZeroStruct(child_dfs);
}
else
{
child_dfs = PushStruct(arena, UI_BoxIterDfsNode);
}
child_dfs->box = child;
SllStackPush(iter->first, child_dfs);
SllQueuePop(iter->first_free, iter->last_free);
ZeroStruct(child_dfs);
}
}
// Push non-floating children to dfs stack
for (UI_Box *child = box->last; child; child = child->prev)
{
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
else
{
UI_BoxIterDfsNode *child_dfs = iter->first_free;
if (child_dfs)
{
SllQueuePop(iter->first_free, iter->last_free);
ZeroStruct(child_dfs);
}
else
{
child_dfs = PushStruct(arena, UI_BoxIterDfsNode);
}
child_dfs->box = child;
SllStackPush(iter->first, child_dfs);
child_dfs = PushStruct(arena, UI_BoxIterDfsNode);
}
child_dfs->box = child;
SllStackPush(iter->first, child_dfs);
}
}
else