展示优化
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <rigtorp/MPMCQueue.h>
|
||||
@@ -367,6 +369,7 @@ struct Performance_Text_Span {
|
||||
Performance_Metric_Id field_id = Performance_Metric_Id::Generic_Number;
|
||||
Performance_Text_Role role = Performance_Text_Role::Value;
|
||||
std::string text;
|
||||
std::string field_key;
|
||||
double measured_width{};
|
||||
double reserved_width{};
|
||||
double x_offset{};
|
||||
@@ -405,6 +408,7 @@ struct Performance_Worker_State {
|
||||
std::atomic<std::uint64_t> next_content_version{1};
|
||||
Performance_Aggregate aggregate;
|
||||
std::array<Performance_Field_Layout_State, performance_field_count> field_layout_states{};
|
||||
std::unordered_map<std::string, double> field_max_value_widths;
|
||||
RectF last_scroll_track_rect;
|
||||
RectF last_scroll_thumb_rect;
|
||||
double last_content_viewport_height{};
|
||||
@@ -459,6 +463,7 @@ struct Performance_Layout_Builder {
|
||||
std::vector<Performance_Line_Layout> render_lines;
|
||||
std::vector<Performance_Display_Text_Run> text_runs;
|
||||
std::array<Performance_Field_Layout_State, performance_field_count> field_layout_states{};
|
||||
std::unordered_map<std::string, double> field_max_value_widths;
|
||||
RectF panel_rect;
|
||||
RectF scroll_bar_rect;
|
||||
RectF scroll_thumb_rect;
|
||||
@@ -1021,38 +1026,155 @@ struct Performance_Layout_Builder {
|
||||
|| (contains(line, "starvation_active:1"))
|
||||
|| (contains(line, "confidence:low") && contains(line, "consumer_paced"));
|
||||
}
|
||||
static bool whitespace(char value) {
|
||||
return std::isspace(static_cast<unsigned char>(value)) != 0;
|
||||
}
|
||||
static std::size_t metric_unit_offset(std::string_view value) {
|
||||
std::size_t index = 0;
|
||||
if (index < value.size() && (value[index] == '+' || value[index] == '-'))
|
||||
++index;
|
||||
bool has_digit = false;
|
||||
while (index < value.size()) {
|
||||
char current = value[index];
|
||||
if (std::isdigit(static_cast<unsigned char>(current))) {
|
||||
has_digit = true;
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
if (current == '.' || current == ',') {
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!has_digit || index == value.size())
|
||||
return std::string_view::npos;
|
||||
char unit = value[index];
|
||||
if (unit == '%' || std::isalpha(static_cast<unsigned char>(unit)))
|
||||
return index;
|
||||
return std::string_view::npos;
|
||||
}
|
||||
static std::size_t first_metric_item(std::string_view text, std::size_t begin) {
|
||||
std::size_t cursor = begin;
|
||||
while (cursor < text.size()) {
|
||||
while (cursor < text.size() && whitespace(text[cursor]))
|
||||
++cursor;
|
||||
std::size_t token_end = cursor;
|
||||
while (token_end < text.size() && !whitespace(text[token_end]))
|
||||
++token_end;
|
||||
if (text.substr(cursor, token_end - cursor).find(':') != std::string_view::npos)
|
||||
return cursor;
|
||||
cursor = token_end;
|
||||
}
|
||||
return std::string_view::npos;
|
||||
}
|
||||
std::vector<Performance_Text_Span> plain_line_runs(const std::string& text, Canvas& canvas) {
|
||||
std::vector<Performance_Text_Span> runs;
|
||||
auto append = [&](std::string value, Performance_Text_Role role, double offset) {
|
||||
std::unordered_map<std::string, std::size_t> field_occurrences;
|
||||
double offset = 0.0;
|
||||
bool warning = warning_line(text);
|
||||
double space_width = canvas.measure_text("0 0").width - canvas.measure_text("00").width;
|
||||
if (space_width <= 0.0)
|
||||
space_width = std::max(1.0, canvas.measure_text("0").width * 0.5);
|
||||
auto trim = [](std::string_view value) {
|
||||
while (!value.empty() && whitespace(value.front()))
|
||||
value.remove_prefix(1);
|
||||
while (!value.empty() && whitespace(value.back()))
|
||||
value.remove_suffix(1);
|
||||
return std::string(value);
|
||||
};
|
||||
auto append = [&](std::string value, Performance_Text_Role role, bool is_value = false, std::string field_key = {}) {
|
||||
if (value.empty())
|
||||
return;
|
||||
Performance_Text_Span run;
|
||||
run.text = std::move(value);
|
||||
run.field_key = std::move(field_key);
|
||||
run.role = role;
|
||||
run.value = is_value;
|
||||
run.column_index = 0;
|
||||
run.x_offset = offset;
|
||||
measure_run(canvas, run);
|
||||
if (std::all_of(run.text.begin(), run.text.end(), whitespace)) {
|
||||
run.measured_width = space_width * static_cast<double>(run.text.size());
|
||||
run.reserved_width = run.measured_width;
|
||||
}
|
||||
offset += run_width(run);
|
||||
runs.push_back(std::move(run));
|
||||
};
|
||||
auto make_field_key = [&](std::string_view section, std::string_view context, std::string_view label) {
|
||||
std::string key;
|
||||
key.reserve(section.size() + context.size() + label.size() + 3);
|
||||
key.append(section);
|
||||
key.push_back('|');
|
||||
key.append(context);
|
||||
key.push_back('|');
|
||||
key.append(label);
|
||||
std::size_t occurrence = field_occurrences[key]++;
|
||||
key.push_back('|');
|
||||
key += std::to_string(occurrence);
|
||||
return key;
|
||||
};
|
||||
auto append_value = [&](std::string_view value, const std::string& field_key) {
|
||||
Performance_Text_Role value_role = warning ? Performance_Text_Role::Warning : Performance_Text_Role::Value;
|
||||
std::size_t unit_offset = metric_unit_offset(value);
|
||||
if (unit_offset == std::string_view::npos) {
|
||||
append(std::string(value), value_role, true, field_key);
|
||||
return;
|
||||
}
|
||||
append(std::string(value.substr(0, unit_offset)), value_role, true, field_key);
|
||||
append(std::string(value.substr(unit_offset)), warning ? Performance_Text_Role::Warning : Performance_Text_Role::Unit);
|
||||
};
|
||||
std::size_t cursor = 0;
|
||||
std::string section;
|
||||
std::size_t section_end = text.find(']');
|
||||
if (!text.empty() && text.front() == '[' && section_end != std::string::npos) {
|
||||
std::string section = text.substr(0, section_end + 1);
|
||||
append(section, Performance_Text_Role::Section, 0.0);
|
||||
double section_width = runs.empty() ? 0.0 : runs.back().measured_width + canvas.measure_text(" ").width;
|
||||
Performance_Text_Role value_role = warning_line(text) ? Performance_Text_Role::Warning : Performance_Text_Role::Value;
|
||||
append(text.substr(section_end + 1), value_role, section_width);
|
||||
section = text.substr(0, section_end + 1);
|
||||
append(section, Performance_Text_Role::Section);
|
||||
cursor = section_end + 1;
|
||||
}
|
||||
std::size_t item_begin = first_metric_item(text, cursor);
|
||||
if (item_begin == std::string_view::npos) {
|
||||
append(text.substr(cursor), warning ? Performance_Text_Role::Warning : Performance_Text_Role::Value);
|
||||
return runs;
|
||||
}
|
||||
std::size_t colon = text.find(':');
|
||||
if (colon != std::string::npos) {
|
||||
std::string label = text.substr(0, colon + 1);
|
||||
append(label, Performance_Text_Role::Label, 0.0);
|
||||
double label_width = runs.empty() ? 0.0 : runs.back().measured_width + canvas.measure_text(" ").width;
|
||||
Performance_Text_Role value_role = warning_line(text) ? Performance_Text_Role::Warning : Performance_Text_Role::Value;
|
||||
append(text.substr(colon + 1), value_role, label_width);
|
||||
return runs;
|
||||
std::string context = trim(std::string_view(text).substr(cursor, item_begin - cursor));
|
||||
if (item_begin > cursor)
|
||||
append(text.substr(cursor, item_begin - cursor), Performance_Text_Role::Label);
|
||||
cursor = item_begin;
|
||||
while (cursor < text.size()) {
|
||||
std::size_t whitespace_end = cursor;
|
||||
while (whitespace_end < text.size() && whitespace(text[whitespace_end]))
|
||||
++whitespace_end;
|
||||
if (whitespace_end > cursor)
|
||||
append(text.substr(cursor, whitespace_end - cursor), Performance_Text_Role::Muted);
|
||||
cursor = whitespace_end;
|
||||
if (cursor >= text.size())
|
||||
break;
|
||||
std::size_t token_end = cursor;
|
||||
while (token_end < text.size() && !whitespace(text[token_end]))
|
||||
++token_end;
|
||||
std::size_t colon = text.find(':', cursor);
|
||||
if (colon == std::string::npos || colon >= token_end) {
|
||||
std::string token = text.substr(cursor, token_end - cursor);
|
||||
append(token, warning ? Performance_Text_Role::Warning : Performance_Text_Role::Label);
|
||||
std::size_t next = token_end;
|
||||
while (next < text.size() && whitespace(text[next]))
|
||||
++next;
|
||||
std::size_t next_end = next;
|
||||
while (next_end < text.size() && !whitespace(text[next_end]))
|
||||
++next_end;
|
||||
std::size_t next_colon = text.find(':', next);
|
||||
if (next < text.size() && next_colon != std::string::npos && next_colon < next_end)
|
||||
context = token;
|
||||
cursor = token_end;
|
||||
continue;
|
||||
}
|
||||
std::string_view label = std::string_view(text).substr(cursor, colon - cursor);
|
||||
std::string field_key = make_field_key(section, context, label);
|
||||
append(text.substr(cursor, colon - cursor + 1), Performance_Text_Role::Label);
|
||||
append_value(std::string_view(text).substr(colon + 1, token_end - colon - 1), field_key);
|
||||
cursor = token_end;
|
||||
}
|
||||
append(text, Performance_Text_Role::Value, 0.0);
|
||||
return runs;
|
||||
}
|
||||
void build_render_lines(Canvas& canvas) {
|
||||
@@ -1062,7 +1184,7 @@ struct Performance_Layout_Builder {
|
||||
Performance_Line_Layout line;
|
||||
std::vector<Performance_Text_Span> runs = plain_line_runs(text, canvas);
|
||||
for (auto& run : runs) {
|
||||
line.width = std::max(line.width, run.x_offset + run.measured_width);
|
||||
line.width = std::max(line.width, run.x_offset + run_width(run));
|
||||
line.runs.push_back(std::move(run));
|
||||
}
|
||||
if (!line.runs.empty())
|
||||
@@ -1223,6 +1345,12 @@ struct Performance_Layout_Builder {
|
||||
run.reserved_width = run.measured_width;
|
||||
return;
|
||||
}
|
||||
if (!run.field_key.empty()) {
|
||||
double& max_width = field_max_value_widths[run.field_key];
|
||||
max_width = std::max(max_width, run.measured_width);
|
||||
run.reserved_width = max_width;
|
||||
return;
|
||||
}
|
||||
auto index = static_cast<std::size_t>(run.field_id);
|
||||
if (index >= field_layout_states.size())
|
||||
index = static_cast<std::size_t>(Performance_Metric_Id::Generic_Number);
|
||||
@@ -1390,6 +1518,7 @@ struct Performance_Overlay_Private {
|
||||
Performance_Layout_Builder layout;
|
||||
layout.aggregate = worker_state.aggregate;
|
||||
layout.field_layout_states = worker_state.field_layout_states;
|
||||
layout.field_max_value_widths = worker_state.field_max_value_widths;
|
||||
layout.rebuild_lines();
|
||||
auto snapshot = std::make_shared<Performance_Display_Snapshot>();
|
||||
snapshot->content_version = worker_state.next_content_version.fetch_add(1, std::memory_order_acq_rel);
|
||||
@@ -1429,6 +1558,7 @@ struct Performance_Overlay_Private {
|
||||
layout.build_render_lines(measure_canvas);
|
||||
}
|
||||
worker_state.field_layout_states = layout.field_layout_states;
|
||||
worker_state.field_max_value_widths = layout.field_max_value_widths;
|
||||
snapshot->lines = layout.display_lines();
|
||||
layout.update_content_width(&state, worker_state.maximum_content_width, viewport.width);
|
||||
double line_height = std::max(1.0, metrics.line_height());
|
||||
|
||||
Reference in New Issue
Block a user