From 10ed4ee4b7c69520da04a6a759061467048fe8df Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 22 Oct 2019 22:04:58 -0700 Subject: [PATCH] Profiler UI features; more extensions to fancy strings --- custom/4coder_draw.cpp | 18 +++ custom/4coder_fancy.cpp | 224 +++++++++++++++++++++++++++- custom/4coder_profile_inspect.cpp | 138 +++++++++++++---- custom/4coder_profile_inspect.h | 2 + custom/generated/command_metadata.h | 2 +- 5 files changed, 347 insertions(+), 37 deletions(-) diff --git a/custom/4coder_draw.cpp b/custom/4coder_draw.cpp index 92962ba5..eb3346f8 100644 --- a/custom/4coder_draw.cpp +++ b/custom/4coder_draw.cpp @@ -691,5 +691,23 @@ get_tool_tip_box(Rect_f32 container, Vec2_f32 p, Vec2_f32 box_dims){ return(Rf32_xy_wh(q, box_dims)); } +function Rect_f32 +draw_tool_tip(Application_Links *app, Face_ID face, Fancy_Block *block, + Vec2_f32 p, Rect_f32 region, f32 x_padding, f32 x_half_padding, + FColor back_color){ + Rect_f32 box = Rf32(p, p); + if (block->line_count > 0){ + Vec2_f32 dims = get_fancy_block_dim(app, face, block); + dims += V2f32(x_padding, 2.f); + box = get_tool_tip_box(region, p, dims); + Rect_f32 prev_clip = draw_set_clip(app, box); + draw_rectangle(app, box, 6.f, back_color); + draw_fancy_block(app, face, fcolor_zero(), block, + box.p0 + V2f32(x_half_padding, 1.f)); + draw_set_clip(app, prev_clip); + } + return(box); +} + // BOTTOM diff --git a/custom/4coder_fancy.cpp b/custom/4coder_fancy.cpp index 2dc1f158..c63ff6bd 100644 --- a/custom/4coder_fancy.cpp +++ b/custom/4coder_fancy.cpp @@ -138,9 +138,9 @@ push_fancy_string(Arena *arena, Fancy_Line *line, FColor color, String_Const_u8 return(push_fancy_string(arena, line, 0, color, 0, 0, value)); } function Fancy_String* -push_fancy_string(Arena *arena, Fancy_Line *line, f32 pre_margn, f32 post_margin, +push_fancy_string(Arena *arena, Fancy_Line *line, f32 pre_margin, f32 post_margin, String_Const_u8 value){ - return(push_fancy_string(arena, line, 0, fcolor_zero(), pre_margn, post_margin, + return(push_fancy_string(arena, line, 0, fcolor_zero(), pre_margin, post_margin, value)); } function Fancy_String* @@ -188,9 +188,9 @@ push_fancy_stringfv(Arena *arena, Fancy_Line *line, FColor color, return(push_fancy_stringfv(arena, line, 0, color, 0, 0, format, args)); } function Fancy_String* -push_fancy_stringfv(Arena *arena, Fancy_Line *line, f32 pre_margn, f32 post_margin, +push_fancy_stringfv(Arena *arena, Fancy_Line *line, f32 pre_margin, f32 post_margin, char *format, va_list args){ - return(push_fancy_stringfv(arena, line, 0, fcolor_zero(), pre_margn, post_margin, + return(push_fancy_stringfv(arena, line, 0, fcolor_zero(), pre_margin, post_margin, format, args)); } function Fancy_String* @@ -253,11 +253,11 @@ push_fancy_stringf(Arena *arena, Fancy_Line *line, FColor color, StringFEnd(); } function Fancy_String* -push_fancy_stringf(Arena *arena, Fancy_Line *line, f32 pre_margn, f32 post_margin, +push_fancy_stringf(Arena *arena, Fancy_Line *line, f32 pre_margin, f32 post_margin, char *format, ...){ StringFBegin(); StringFPass(push_fancy_stringfv(arena, line, 0, fcolor_zero(), - pre_margn, post_margin, format, args)); + pre_margin, post_margin, format, args)); StringFEnd(); } function Fancy_String* @@ -270,6 +270,218 @@ push_fancy_stringf(Arena *arena, Fancy_Line *line, //////////////////////////////// +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, Face_ID face, FColor fore, + f32 pre_margin, f32 post_margin, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fore, pre_margin, post_margin, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fore, pre_margin, post_margin, + "%-*.*s...", max - 3, string_expand(value))); + } +} +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, Face_ID face, FColor fore, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fore, 0.f, 0.f, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fore, 0.f, 0.f, + "%-*.*s...", max - 3, string_expand(value))); + } +} +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, Face_ID face, + f32 pre_margin, f32 post_margin, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), + pre_margin, post_margin, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), + pre_margin, post_margin, + "%-*.*s...", max - 3, string_expand(value))); + } +} +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, FColor fore, + f32 pre_margin, f32 post_margin, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fore, pre_margin, post_margin, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fore, pre_margin, post_margin, + "%-*.*s...", max - 3, string_expand(value))); + } +} +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, Face_ID face, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), 0.f, 0.f, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), 0.f, 0.f, + "%-*.*s...", max - 3, string_expand(value))); + } +} +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, FColor fore, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + "%-*.*s...", max - 3, string_expand(value))); + } +} +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, + f32 pre_margin, f32 post_margin, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + pre_margin, post_margin, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + pre_margin, post_margin, + "%-*.*s...", max - 3, string_expand(value))); + } +} +function Fancy_String* +push_fancy_string_fixed(Arena *arena, Fancy_Line *line, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + "%-*.*s", max, string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + "%-*.*s...", max - 3, string_expand(value))); + } +} + +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, Face_ID face, FColor fore, + f32 pre_margin, f32 post_margin, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fore, pre_margin, post_margin, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fore, pre_margin, post_margin, + "%.*s...", max - 3, value.str)); + } +} +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, Face_ID face, FColor fore, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fore, 0.f, 0.f, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fore, 0.f, 0.f, + "%.*s...", max - 3, value.str)); + } +} +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, Face_ID face, + f32 pre_margin, f32 post_margin, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), + pre_margin, post_margin, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), + pre_margin, post_margin, + "%.*s...", max - 3, value.str)); + } +} +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, FColor fore, + f32 pre_margin, f32 post_margin, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fore, pre_margin, post_margin, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fore, pre_margin, post_margin, + "%.*s...", max - 3, value.str)); + } +} +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, Face_ID face, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), 0.f, 0.f, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, face, fcolor_zero(), 0.f, 0.f, + "%.*s...", max - 3, value.str)); + } +} +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, FColor fore, + String_Const_u8 value, i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fore, 0.f, 0.f, + "%.*s...", max - 3, value.str)); + } +} +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, + f32 pre_margin, f32 post_margin, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + pre_margin, post_margin, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), + pre_margin, post_margin, + "%.*s...", max - 3, value.str)); + } +} +function Fancy_String* +push_fancy_string_trunc(Arena *arena, Fancy_Line *line, String_Const_u8 value, + i32 max){ + if (value.size <= max){ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + "%.*s", string_expand(value))); + } + else{ + return(push_fancy_stringf(arena, line, 0, fcolor_zero(), 0.f, 0.f, + "%.*s...", max - 3, value.str)); + } +} + +//////////////////////////////// + function Fancy_Line* push_fancy_line(Arena *arena, Fancy_Block *block, Face_ID face, FColor fore, String_Const_u8 text){ diff --git a/custom/4coder_profile_inspect.cpp b/custom/4coder_profile_inspect.cpp index 3674d009..ae5639ee 100644 --- a/custom/4coder_profile_inspect.cpp +++ b/custom/4coder_profile_inspect.cpp @@ -114,6 +114,7 @@ profile_parse_record(Arena *arena, Profile_Inspection *insp, sll_queue_push(slot->first_hit, slot->last_hit, node_ptr); slot->hit_count += 1; node_ptr->ptr = node; + node->unique_counter = (u64)slot->hit_count; } if (quit_loop){ @@ -244,6 +245,36 @@ profile_node_name(Profile_Node *node){ return(result); } +function String_Const_u8 +profile_node_location(Profile_Node *node){ + String_Const_u8 result = {}; + if (node->slot != 0){ + result = node->slot->location; + } + return(result); +} + +function void +profile_qsort_nodes(Profile_Node **nodes, i32 first, i32 one_past_last){ + if (first + 1 < one_past_last){ + i32 pivot_index = one_past_last - 1; + Profile_Node *pivot = nodes[pivot_index]; + u64 pivot_time = range_size(pivot->time); + i32 j = first; + for (i32 i = first; i < one_past_last; i += 1){ + Profile_Node *node = nodes[i]; + u64 node_time = range_size(node->time); + if (node_time > pivot_time){ + Swap(Profile_Node*, nodes[i], nodes[j]); + j += 1; + } + } + Swap(Profile_Node*, nodes[pivot_index], nodes[j]); + profile_qsort_nodes(nodes, first, j); + profile_qsort_nodes(nodes, j + 1, one_past_last); + } +} + function void profile_draw_node(Application_Links *app, View_ID view, Face_ID face_id, Profile_Node *node, Rect_f32 rect, @@ -255,6 +286,7 @@ profile_draw_node(Application_Links *app, View_ID view, Face_ID face_id, Face_Metrics metrics = get_face_metrics(app, face_id); f32 line_height = metrics.line_height; f32 normal_advance = metrics.normal_advance; + f32 block_height = line_height*2.f; f32 x_padding = normal_advance*1.5f; f32 x_half_padding = x_padding*0.5f; @@ -348,8 +380,23 @@ profile_draw_node(Application_Links *app, View_ID view, Face_ID face_id, if (rect_contains_point(box, m_p)){ insp->full_name_hovered = profile_node_name(child); + insp->unique_counter_hovered = child->unique_counter; insp->hover_node = child; } + + if (range_size(child_y) >= line_height){ + String_Const_u8 child_name = profile_node_name(child); + Fancy_Line line = {}; + push_fancy_string(scratch, &line, fcolor_id(Stag_Pop1), + child_name); + push_fancy_stringf(scratch, &line, fcolor_id(Stag_Default), + 0.5f, 0.f, "#%4llu", child->unique_counter); + + Vec2_f32 p = V2f32(x.min + x_half_padding, + child_y.min); + draw_fancy_line(app, face_id, fcolor_zero(), + &line, p); + } } } } @@ -358,10 +405,9 @@ profile_draw_node(Application_Links *app, View_ID view, Face_ID face_id, { x = rect_range_x(info_box); - y = rect_range_y(info_box); x_pos = x.min + x_half_padding; - f32 y_pos = y.min; + f32 y_pos = info_box.y0; // NOTE(allen): duration { @@ -373,6 +419,51 @@ profile_draw_node(Application_Links *app, View_ID view, Face_ID face_id, &list, V2f32(x_pos, y_pos + 1.f)); y_pos += line_height + 2.f; } + + i32 child_count = node->child_count; + Profile_Node **children_array = push_array(scratch, Profile_Node*, child_count); + i32 counter = 0; + for (Profile_Node *child = node->first_child; + child != 0; + child = child->next){ + children_array[counter] = child; + counter += 1; + } + + profile_qsort_nodes(children_array, 0, child_count); + + Profile_Node **child_ptr = children_array; + for (i32 i = 0; i < child_count; i += 1, child_ptr += 1){ + Profile_Node *child = *child_ptr; + y = If32_size(y_pos, block_height); + + f32 ratio = ((f32)range_size(child->time))/((f32)range_size(node->time)); + + String_Const_u8 child_name = profile_node_name(child); + Fancy_Line line = {}; + push_fancy_string_trunc(scratch, &line, child_name, 10); + push_fancy_stringf(scratch, &line, fcolor_id(Stag_Default), 0.5f, 0.f, + "#%4llu", child->unique_counter); + push_fancy_stringf(scratch, &line, fcolor_id(Stag_Pop2), + 0.5f, 0.f, "%6.4f", ratio); + + Vec2_f32 p = V2f32(x.min + x_half_padding, + (y.min + y.max - line_height)*0.5f); + draw_fancy_line(app, face_id, fcolor_id(Stag_Pop1), &line, p); + + Rect_f32 box = Rf32(x, y); + FColor margin = fcolor_id(Stag_Margin); + if (rect_contains_point(box, m_p)){ + insp->full_name_hovered = child_name; + insp->unique_counter_hovered = child->unique_counter; + insp->location_jump_hovered = profile_node_location(child); + insp->hover_node = child; + margin = fcolor_id(Stag_Margin_Hover); + } + draw_rectangle_outline(app, box, 6.f, 3.f, margin); + + y_pos = y.max; + } } } @@ -412,6 +503,7 @@ profile_render(Application_Links *app, Frame_Info frame_info, View_ID view){ inspect->tab_id_hovered = ProfileInspectTab_None; block_zero_struct(&inspect->full_name_hovered); + inspect->unique_counter_hovered = 0; block_zero_struct(&inspect->location_jump_hovered); inspect->hover_thread = 0; inspect->hover_slot = 0; @@ -526,20 +618,11 @@ profile_render(Application_Links *app, Frame_Info frame_info, View_ID view){ node = node->next){ Range_f32 y = If32_size(y_pos, block_height); - b32 name_too_long = false; - i32 name_width = 45; + u32 name_width = 45; + b32 name_too_long = (node->name.size > name_width); Fancy_Line list = {}; - if (node->name.size > name_width){ - push_fancy_stringf(scratch, &list, fcolor_id(Stag_Pop1), - "%.*s... ", - name_width - 3, node->name.str); - name_too_long = true; - } - else{ - push_fancy_stringf(scratch, &list, fcolor_id(Stag_Pop1), - "%-*.*s ", - name_width, string_expand(node->name)); - } + push_fancy_string_fixed(scratch, &list, fcolor_id(Stag_Pop1), + node->name, name_width); if (node->corrupted_time){ push_fancy_string(scratch, &list, fcolor_id(Stag_Pop2), @@ -634,27 +717,22 @@ profile_render(Application_Links *app, Frame_Info frame_info, View_ID view){ FColor back_color = fcolor_change_alpha(app, f_black, 0.5f); if (inspect->full_name_hovered.size > 0){ - Fancy_Line *line = push_fancy_line(scratch, &block); - push_fancy_stringf(scratch, line, text_color, "%.*s", + Fancy_Line *line = push_fancy_line(scratch, &block, text_color); + push_fancy_stringf(scratch, line, "%.*s", string_expand(inspect->full_name_hovered)); + if (inspect->unique_counter_hovered > 0){ + push_fancy_stringf(scratch, line, text_color, 0.5f, 0.f, + "#%4llu", inspect->unique_counter_hovered); + } } if (inspect->location_jump_hovered.size > 0){ - Fancy_Line *line = push_fancy_line(scratch, &block); - push_fancy_stringf(scratch, line, text_color, "[shift] '%.*s'", + Fancy_Line *line = push_fancy_line(scratch, &block, text_color); + push_fancy_stringf(scratch, line, "[shift] '%.*s'", string_expand(inspect->location_jump_hovered)); } - if (block.line_count > 0){ - Vec2_f32 dims = get_fancy_block_dim(app, face_id, &block); - dims += V2f32(x_padding, 2.f); - - Rect_f32 box = get_tool_tip_box(region, m_p, dims); - draw_set_clip(app, box); - - draw_rectangle(app, box, 6.f, back_color); - draw_fancy_block(app, face_id, fcolor_zero(), &block, - V2f32(box.x0 + x_half_padding, box.y0 + 1.f)); - } + draw_tool_tip(app, face_id, &block, m_p, region, + x_padding, x_half_padding, back_color); } } diff --git a/custom/4coder_profile_inspect.h b/custom/4coder_profile_inspect.h index 2083f815..8da8f4ab 100644 --- a/custom/4coder_profile_inspect.h +++ b/custom/4coder_profile_inspect.h @@ -32,6 +32,7 @@ struct Profile_Node{ struct Profile_Inspection_Thread *thread; Range_u64 time; Profile_ID id; + u64 unique_counter; Profile_Node *first_child; Profile_Node *last_child; @@ -79,6 +80,7 @@ struct Profile_Inspection{ Profile_Inspection_Tab tab_id_hovered; String_Const_u8 full_name_hovered; + u64 unique_counter_hovered; String_Const_u8 location_jump_hovered; Profile_Inspection_Thread *hover_thread; Profile_Slot *hover_slot; diff --git a/custom/generated/command_metadata.h b/custom/generated/command_metadata.h index 23d54a8b..c9099702 100644 --- a/custom/generated/command_metadata.h +++ b/custom/generated/command_metadata.h @@ -441,7 +441,7 @@ static Command_Metadata fcoder_metacmd_table[211] = { { PROC_LINKS(miblo_decrement_time_stamp, 0), false, "miblo_decrement_time_stamp", 26, "Decrement a time stamp under the cursor by one second. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 237 }, { PROC_LINKS(miblo_increment_time_stamp_minute, 0), false, "miblo_increment_time_stamp_minute", 33, "Increment a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 243 }, { PROC_LINKS(miblo_decrement_time_stamp_minute, 0), false, "miblo_decrement_time_stamp_minute", 33, "Decrement a time stamp under the cursor by one minute. (format [m]m:ss or h:mm:ss", 81, "w:\\4ed\\code\\custom\\4coder_miblo_numbers.cpp", 43, 249 }, -{ PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "w:\\4ed\\code\\custom\\4coder_profile_inspect.cpp", 45, 692 }, +{ PROC_LINKS(profile_inspect, 0), true, "profile_inspect", 15, "Inspect all currently collected profiling information in 4coder's self profiler.", 80, "w:\\4ed\\code\\custom\\4coder_profile_inspect.cpp", 45, 770 }, { PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 }, { PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "w:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 21 }, };