mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 08:06:19 +00:00
perf(dashboard): deduplicate histogram samples and trim unused trend fields
Group identical positive samples before numeric logarithm evaluation while retaining histogram boundaries and weights. Remove nine unused trend fields and synchronize frontend types, preview data, and API documentation. Validate against the 30-million-row Docker dataset, matching retained statistics and reducing uncached today-summary median latency from 623 ms to 319 ms. Run 133 related tests, Clippy, formatting, frontend checks, and browser tab checks.
This commit is contained in:
@@ -686,20 +686,10 @@ pub(crate) fn trend_point_view(
|
||||
tokens_value: point.metrics.total_tokens,
|
||||
errors: format_compact_number(point.service_failure_count),
|
||||
errors_value: point.service_failure_count,
|
||||
latency: display_duration(point.average_latency_ms),
|
||||
latency_value: point.average_latency_ms,
|
||||
max_latency: display_duration(point.metrics.max_latency_ms),
|
||||
max_latency_value: point.metrics.max_latency_ms,
|
||||
min_latency: display_duration(point.metrics.min_latency_ms),
|
||||
min_latency_value: point.metrics.min_latency_ms,
|
||||
success_rate: success_rate_value
|
||||
.map_or_else(|| "—".to_owned(), |value| format!("{value:.1}%")),
|
||||
success_rate_value,
|
||||
first_token_p50_ms: point
|
||||
.metrics
|
||||
.first_token_latency_percentiles
|
||||
.p50_ms
|
||||
.map(|value| value.as_f64()),
|
||||
first_token_p95_ms: point
|
||||
.metrics
|
||||
.first_token_latency_percentiles
|
||||
@@ -711,20 +701,6 @@ pub(crate) fn trend_point_view(
|
||||
.p95_ms
|
||||
.map(|value| value.as_f64()),
|
||||
output_throughput_p50: point.metrics.output_throughput_p50,
|
||||
admission_decision_p95_ms: point
|
||||
.metrics
|
||||
.admission_decision_percentiles
|
||||
.p95_ms
|
||||
.map(|value| value.as_f64()),
|
||||
account_selection_wait_p95_ms: point
|
||||
.metrics
|
||||
.account_selection_wait_percentiles
|
||||
.p95_ms
|
||||
.map(|value| value.as_f64()),
|
||||
capacity_utilization: point
|
||||
.metrics
|
||||
.capacity_utilization_p95_basis_points
|
||||
.map(basis_points_rate),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -306,21 +306,12 @@ pub struct TrendPointView {
|
||||
pub tokens_value: u64,
|
||||
pub errors: String,
|
||||
pub errors_value: u64,
|
||||
pub latency: String,
|
||||
pub latency_value: Option<u64>,
|
||||
pub max_latency: String,
|
||||
pub max_latency_value: Option<u64>,
|
||||
pub min_latency: String,
|
||||
pub min_latency_value: Option<u64>,
|
||||
pub success_rate: String,
|
||||
pub success_rate_value: Option<f64>,
|
||||
pub first_token_p50_ms: Option<f64>,
|
||||
pub first_token_p95_ms: Option<f64>,
|
||||
pub latency_p95_ms: Option<f64>,
|
||||
pub output_throughput_p50: Option<u64>,
|
||||
pub admission_decision_p95_ms: Option<f64>,
|
||||
pub account_selection_wait_p95_ms: Option<f64>,
|
||||
pub capacity_utilization: Option<f64>,
|
||||
}
|
||||
|
||||
/// 趋势指标的稳定身份,展示名称由管理端本地化
|
||||
|
||||
@@ -89,8 +89,10 @@ pub(super) fn push_fact_aggregation_selected(
|
||||
}
|
||||
query.push(") sample(metric,value) where value is not null), sample_stats as (select output_bucket,name,metric,count(*) as count,sum(value) as sum,min(value) as minimum,max(value) as maximum,count(*) filter(where value=0) as zero");
|
||||
query.push(" from samples group by output_bucket,name,metric)");
|
||||
// 对数桶定义与 Histogram::add 相同,零值单独保留,不对零取对数
|
||||
query.push(", bin_counts as (select output_bucket,name,metric,floor(log(2::numeric,value::numeric)*16)::integer as bin,count(*) as count from samples where value>0 group by output_bucket,name,metric,bin), merged_bins as (select output_bucket,name,metric,jsonb_object_agg(bin,count) as bins from bin_counts group by output_bucket,name,metric)");
|
||||
// 先合并同值样本,避免逐条重复计算 numeric 对数,保持原有桶边界和样本权重
|
||||
// 零值仍由 sample_stats 单独保留,不参与对数计算
|
||||
query.push(", sample_values as materialized (select output_bucket,name,metric,value,count(*) as count from samples where value>0 group by output_bucket,name,metric,value)");
|
||||
query.push(", bin_counts as (select output_bucket,name,metric,floor(log(2::numeric,value::numeric)*16)::integer as bin,sum(count)::bigint as count from sample_values group by output_bucket,name,metric,bin), merged_bins as (select output_bucket,name,metric,jsonb_object_agg(bin,count) as bins from bin_counts group by output_bucket,name,metric)");
|
||||
query.push(", merged_distributions as (select s.output_bucket,s.name,jsonb_object_agg(s.metric,jsonb_build_object('count',s.count,'sum',s.sum,'minimum',s.minimum,'maximum',s.maximum,'zero',s.zero,'bins',");
|
||||
query.push("coalesce(b.bins,'{}'::jsonb)");
|
||||
query.push(")) as distributions");
|
||||
|
||||
@@ -1692,16 +1692,18 @@ async fn daily_rank_counts_follow_rebuilds_rollbacks_deletions_and_dirty_days()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sql_edge_histograms_match_persisted_power_of_two_boundaries() {
|
||||
async fn sql_edge_histograms_preserve_repeated_samples_and_power_of_two_boundaries() {
|
||||
let Some(database) = TestDatabase::create("analytics_sql_histogram_boundaries").await else {
|
||||
return;
|
||||
};
|
||||
let start = DateTime::parse_from_rfc3339("2026-09-01T10:00:00Z")
|
||||
.unwrap()
|
||||
.with_timezone(&Utc);
|
||||
for (index, value) in [0_i64, 1, 2, 4, 8, 16, 31, 32, 33, 64, 128, 1024, 1_048_576]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
for (index, value) in [
|
||||
0_i64, 0, 1, 1, 1, 2, 2, 4, 8, 16, 31, 32, 32, 33, 64, 128, 1024, 1_048_576,
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
let id = format!("sql_hist_{index}");
|
||||
seed(
|
||||
|
||||
@@ -2022,6 +2022,10 @@ errorCode, errorMessage, startedAt, completedAt, expiresAt, createdAt, updatedAt
|
||||
|
||||
图表颜色、系列身份和选中状态使用 `metric`,不根据译文或数组位置推断指标
|
||||
|
||||
`points[]` 提供趋势图与首页卡片使用的请求数、Tokens、缓存比例、错误数、成功率、
|
||||
`latencyValue`、首 Token P95、总延迟 P95 和输出吞吐 P50,以及时间标签与展示值
|
||||
内部调度分位数和容量分布通过用量洞察查询
|
||||
|
||||
### Dashboard 客户端身份
|
||||
|
||||
`wireProfiles[].attributes[]` 返回稳定的 `key` 和 `value`,字段名称由前端本地化
|
||||
|
||||
@@ -26,21 +26,12 @@ export interface DashboardTrendPoint {
|
||||
tokensValue: number
|
||||
errors: string
|
||||
errorsValue: number
|
||||
latency: string
|
||||
latencyValue: number | null
|
||||
maxLatency: string
|
||||
maxLatencyValue: number | null
|
||||
minLatency: string
|
||||
minLatencyValue: number | null
|
||||
successRate: string
|
||||
successRateValue: number | null
|
||||
firstTokenP50Ms: number | null
|
||||
firstTokenP95Ms: number | null
|
||||
latencyP95Ms: number | null
|
||||
outputThroughputP50: number | null
|
||||
admissionDecisionP95Ms: number | null
|
||||
accountSelectionWaitP95Ms: number | null
|
||||
capacityUtilization: number | null
|
||||
}
|
||||
|
||||
export type DashboardTrendMetric
|
||||
|
||||
@@ -81,21 +81,12 @@ function previewTrendPoint(requestsValue: number, index: number): DashboardTrend
|
||||
tokensValue: inputTokensValue + outputTokensValue,
|
||||
errors: errorsValue.toLocaleString('zh-CN'),
|
||||
errorsValue,
|
||||
latency: `${410 + index * 7} ms`,
|
||||
latencyValue: 410 + index * 7,
|
||||
maxLatency: `${760 + index * 12} ms`,
|
||||
maxLatencyValue: 760 + index * 12,
|
||||
minLatency: `${180 + index * 3} ms`,
|
||||
minLatencyValue: 180 + index * 3,
|
||||
successRate: `${successRateValue.toFixed(1)}%`,
|
||||
successRateValue,
|
||||
firstTokenP50Ms: 210 + index * 3,
|
||||
firstTokenP95Ms: 420 + index * 5,
|
||||
latencyP95Ms: 760 + index * 12,
|
||||
outputThroughputP50: 52 + (index % 5),
|
||||
admissionDecisionP95Ms: 2 + (index % 3),
|
||||
accountSelectionWaitP95Ms: 8 + (index % 4),
|
||||
capacityUtilization: 0.42 + (index % 6) * 0.04,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user