From f81628172a2258f6a27dab8cd82aa0a80ae0dc58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 24 Jun 2025 10:48:38 +0200 Subject: [PATCH 1/8] Compress table header name --- site/frontend/src/pages/detailed-query/page.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/frontend/src/pages/detailed-query/page.vue b/site/frontend/src/pages/detailed-query/page.vue index 904417a97..dbcefb1a5 100644 --- a/site/frontend/src/pages/detailed-query/page.vue +++ b/site/frontend/src/pages/detailed-query/page.vue @@ -449,7 +449,7 @@ loadData(); @click.prevent=" changeSortParameters('incrementalLoading', 'desc') " - >Incremental loading (s)Incr. loading (s) Incremental loading deltaIncr. loading delta From a9246e6aeb047fa7acc308a1b2d7a749c1a7f70d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 24 Jun 2025 10:55:33 +0200 Subject: [PATCH 2/8] Create function for constructing row elements --- .../src/pages/detailed-query/utils.ts | 95 +++++++------------ 1 file changed, 34 insertions(+), 61 deletions(-) diff --git a/site/frontend/src/pages/detailed-query/utils.ts b/site/frontend/src/pages/detailed-query/utils.ts index e8de53195..f6f70f5c4 100644 --- a/site/frontend/src/pages/detailed-query/utils.ts +++ b/site/frontend/src/pages/detailed-query/utils.ts @@ -244,85 +244,58 @@ export function createTableData( // Add totals row first const totals = profile.totals; const totalsDelta = delta?.totals; - result.push({ - isTotal: true, - label: totals.label, + result.push(createRowData(true, totals, totalsDelta)); + + // Add query data rows + profile.query_data.forEach((query, idx) => { + const queryDelta = delta?.query_data[idx]; + result.push(createRowData(false, query, queryDelta)); + }); + + return result; +} + +function createRowData( + isTotal: boolean, + value: ProfileElement, + delta?: ProfileElement +): TableRowData { + return { + isTotal, + label: value.label, timePercent: - totals.percent_total_time < 0 + value.percent_total_time < 0 ? { value: -1, formatted: "-", title: "No wall-time stat collected for this run", } : { - value: totals.percent_total_time, - formatted: totals.percent_total_time.toFixed(2) + "%*", + value: value.percent_total_time, + formatted: value.percent_total_time.toFixed(2) + "%", title: "% of cpu-time stat", }, - timeSeconds: toSeconds(totals.self_time), - timeDelta: totalsDelta + timeSeconds: toSeconds(value.self_time), + timeDelta: delta ? createDelta( - toSeconds(totals.self_time), - toSeconds(totalsDelta.self_time), + toSeconds(value.self_time), + toSeconds(delta.self_time), false ) : null, - executions: totals.invocation_count, - executionsDelta: totalsDelta - ? createDelta(totals.invocation_count, totalsDelta.invocation_count, true) + executions: value.invocation_count, + executionsDelta: delta + ? createDelta(value.invocation_count, delta.invocation_count, true) : null, - incrementalLoading: toSeconds(totals.incremental_load_time), - incrementalLoadingDelta: totalsDelta + incrementalLoading: toSeconds(value.incremental_load_time), + incrementalLoadingDelta: delta ? createDelta( - toSeconds(totals.incremental_load_time), - toSeconds(totalsDelta.incremental_load_time), + toSeconds(value.incremental_load_time), + toSeconds(delta.incremental_load_time), false ) : null, - }); - - // Add query data rows - profile.query_data.forEach((query, idx) => { - const queryDelta = delta?.query_data[idx]; - result.push({ - isTotal: false, - label: query.label, - timePercent: - query.percent_total_time < 0 - ? { - value: -1, - formatted: "-", - title: "No wall-time stat collected for this run", - } - : { - value: query.percent_total_time, - formatted: query.percent_total_time.toFixed(2) + "%", - title: "", - }, - timeSeconds: toSeconds(query.self_time), - timeDelta: queryDelta - ? createDelta( - toSeconds(query.self_time), - toSeconds(queryDelta.self_time), - false - ) - : null, - executions: query.invocation_count, - executionsDelta: queryDelta - ? createDelta(query.invocation_count, queryDelta.invocation_count, true) - : null, - incrementalLoading: toSeconds(query.incremental_load_time), - incrementalLoadingDelta: queryDelta - ? createDelta( - toSeconds(query.incremental_load_time), - toSeconds(queryDelta.incremental_load_time), - false - ) - : null, - }); - }); - - return result; + }; } export function createArtifactData(data: SelfProfileResponse | null): { From 02ead2aa19556e178dc0113ab49d2cd66d30f1e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 24 Jun 2025 17:23:17 +0200 Subject: [PATCH 3/8] Separate query data and query delta data in TypeScript --- .../src/pages/detailed-query/utils.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/site/frontend/src/pages/detailed-query/utils.ts b/site/frontend/src/pages/detailed-query/utils.ts index f6f70f5c4..7745445b0 100644 --- a/site/frontend/src/pages/detailed-query/utils.ts +++ b/site/frontend/src/pages/detailed-query/utils.ts @@ -14,10 +14,17 @@ export interface ProfileElement { label: string; self_time: number; percent_total_time: number; - number_of_cache_misses?: number; - number_of_cache_hits?: number; + number_of_cache_misses: number; + number_of_cache_hits: number; invocation_count: number; - blocked_time?: number; + blocked_time: number; + incremental_load_time: number; +} + +export interface ProfileElementDelta { + self_time: number; + invocation_count: number; + number_of_cache_hits: number; incremental_load_time: number; } @@ -34,7 +41,13 @@ export interface ProfileData { export interface SelfProfileResponse { profile: ProfileData; - base_profile_delta?: ProfileData; + base_profile_delta?: ProfileDataDelta; +} + +export interface ProfileDataDelta { + totals: ProfileElementDelta; + query_data: ProfileElementDelta[]; + artifact_sizes: ArtifactSize[]; } export function toSeconds(time: number): number { @@ -221,7 +234,7 @@ export interface DeltaData { isIntegral: boolean; } -interface TableRowData { +export interface TableRowData { isTotal: boolean; label: string; timePercent: {value: number; formatted: string; title: string}; @@ -258,7 +271,7 @@ export function createTableData( function createRowData( isTotal: boolean, value: ProfileElement, - delta?: ProfileElement + delta: ProfileElementDelta | undefined ): TableRowData { return { isTotal, From 295165b8577f1d2e41992b4741a2adfc7d47ec68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 24 Jun 2025 17:23:42 +0200 Subject: [PATCH 4/8] Use strong typing for column names --- site/frontend/src/pages/detailed-query/page.vue | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/site/frontend/src/pages/detailed-query/page.vue b/site/frontend/src/pages/detailed-query/page.vue index dbcefb1a5..2d518105d 100644 --- a/site/frontend/src/pages/detailed-query/page.vue +++ b/site/frontend/src/pages/detailed-query/page.vue @@ -21,9 +21,10 @@ const showIncr = ref(true); const showDelta = ref(true); type SortDirection = "asc" | "desc"; +type ColumnName = keyof TableRowData; // Client-side sorting state -const currentSortColumn = ref("timeSeconds"); +const currentSortColumn = ref("timeSeconds"); const currentSortDirection = ref("desc"); // Computed properties for UI data @@ -173,10 +174,10 @@ function loadSortFromUrl(urlParams: Dict) { const sort = urlParams["sort"] ?? "-timeSeconds"; // Default to descending timeSeconds // Handle sort format: either "columnName" for asc or "-columnName" for desc if (sort.startsWith("-")) { - currentSortColumn.value = sort.substring(1); + currentSortColumn.value = sort.substring(1) as ColumnName; currentSortDirection.value = "desc"; } else { - currentSortColumn.value = sort; + currentSortColumn.value = sort as ColumnName; currentSortDirection.value = "asc"; } } @@ -223,7 +224,7 @@ function populateUIData(responseData: SelfProfileResponse, state: Selector) { } function changeSortParameters( - columnName: string, + columnName: ColumnName, defaultDirection: SortDirection ) { // Toggle direction if clicking the same column, otherwise use default direction @@ -239,7 +240,7 @@ function changeSortParameters( storeSortToUrl(); } -function getHeaderClass(columnName: string): string { +function getHeaderClass(columnName: keyof TableRowData): string { if (columnName === currentSortColumn.value) { if (currentSortDirection.value === "asc") { return "header-sort-asc"; From b6d1cdff3a879c8cea33bca4f77930ee2c8546f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 24 Jun 2025 17:22:52 +0200 Subject: [PATCH 5/8] Add cache hits to self-profile data API response --- site/src/api.rs | 1 + site/src/request_handlers/self_profile.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/site/src/api.rs b/site/src/api.rs index ba3bc2be2..3b78d729d 100644 --- a/site/src/api.rs +++ b/site/src/api.rs @@ -504,6 +504,7 @@ pub mod self_profile { // Nanoseconds pub self_time: i64, pub invocation_count: i32, + pub number_of_cache_hits: i32, // Nanoseconds pub incremental_load_time: i64, } diff --git a/site/src/request_handlers/self_profile.rs b/site/src/request_handlers/self_profile.rs index db1707451..84c6bbd0f 100644 --- a/site/src/request_handlers/self_profile.rs +++ b/site/src/request_handlers/self_profile.rs @@ -214,6 +214,8 @@ fn get_self_profile_delta( self_time: profile.totals.self_time as i64 - base_profile.totals.self_time as i64, invocation_count: profile.totals.invocation_count as i32 - base_profile.totals.invocation_count as i32, + number_of_cache_hits: profile.totals.number_of_cache_hits as i32 + - base_profile.totals.number_of_cache_hits as i32, incremental_load_time: profile.totals.incremental_load_time as i64 - base_profile.totals.incremental_load_time as i64, }; @@ -230,6 +232,8 @@ fn get_self_profile_delta( let delta = self_profile::QueryDataDelta { self_time: qd.self_time as i64 - base_qd.self_time as i64, invocation_count: qd.invocation_count as i32 - base_qd.invocation_count as i32, + number_of_cache_hits: qd.number_of_cache_hits as i32 + - base_qd.number_of_cache_hits as i32, incremental_load_time: qd.incremental_load_time as i64 - base_qd.incremental_load_time as i64, }; @@ -240,6 +244,7 @@ fn get_self_profile_delta( let delta = self_profile::QueryDataDelta { self_time: qd.self_time as i64, invocation_count: qd.invocation_count as i32, + number_of_cache_hits: qd.number_of_cache_hits as i32, incremental_load_time: qd.incremental_load_time as i64, }; From aebb890583c49017c8b8ecae2cceba6d21b61726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 10:41:00 +0200 Subject: [PATCH 6/8] Add query cache hits --- .../src/pages/detailed-query/page.vue | 37 +++++++++++++++++++ .../src/pages/detailed-query/utils.ts | 10 +++++ 2 files changed, 47 insertions(+) diff --git a/site/frontend/src/pages/detailed-query/page.vue b/site/frontend/src/pages/detailed-query/page.vue index 2d518105d..5cda988c9 100644 --- a/site/frontend/src/pages/detailed-query/page.vue +++ b/site/frontend/src/pages/detailed-query/page.vue @@ -12,6 +12,7 @@ import { createTableData, createArtifactData, DeltaData, + TableRowData, } from "./utils"; const loading = ref(true); @@ -76,6 +77,15 @@ const tableData = computed(() => { ? Math.abs(b.executionsDelta.percentage) : 0; break; + case "cacheHits": // Hits + aValue = a.cacheHits; + bValue = b.cacheHits; + // Use percentage change as secondary sort for equal absolute values + aSecondary = + a.cacheHitsDelta !== null ? Math.abs(a.cacheHitsDelta.percentage) : 0; + bSecondary = + b.cacheHitsDelta !== null ? Math.abs(b.cacheHitsDelta.percentage) : 0; + break; case "incrementalLoading": // Incremental loading (s) aValue = a.incrementalLoading; bValue = b.incrementalLoading; @@ -117,6 +127,15 @@ const tableData = computed(() => { ? Math.abs(b.executionsDelta.percentage) : 0; break; + case "cacheHitsDelta": // Cache hits delta + aValue = a.cacheHitsDelta !== null ? a.cacheHitsDelta.delta : -Infinity; + bValue = b.cacheHitsDelta !== null ? b.cacheHitsDelta.delta : -Infinity; + // Use percentage as secondary sort for equal delta values + aSecondary = + a.cacheHitsDelta !== null ? Math.abs(a.cacheHitsDelta.percentage) : 0; + bSecondary = + b.cacheHitsDelta !== null ? Math.abs(b.cacheHitsDelta.percentage) : 0; + break; case "incrementalLoadingDelta": // Incremental loading delta aValue = a.incrementalLoadingDelta !== null @@ -440,6 +459,20 @@ loadData(); >Executions delta + + Hits + + + Hits delta + + {{ row.cacheHits }} + + + {{ row.incrementalLoading.toFixed(3) }} diff --git a/site/frontend/src/pages/detailed-query/utils.ts b/site/frontend/src/pages/detailed-query/utils.ts index 7745445b0..4d8da1542 100644 --- a/site/frontend/src/pages/detailed-query/utils.ts +++ b/site/frontend/src/pages/detailed-query/utils.ts @@ -242,6 +242,8 @@ export interface TableRowData { timeDelta: DeltaData | null; executions: number; executionsDelta: DeltaData | null; + cacheHits: number; + cacheHitsDelta: DeltaData | null; incrementalLoading: number; incrementalLoadingDelta: DeltaData | null; } @@ -300,6 +302,14 @@ function createRowData( executionsDelta: delta ? createDelta(value.invocation_count, delta.invocation_count, true) : null, + cacheHits: value.number_of_cache_hits, + cacheHitsDelta: delta + ? createDelta( + value.number_of_cache_hits, + delta.number_of_cache_hits, + true + ) + : null, incrementalLoading: toSeconds(value.incremental_load_time), incrementalLoadingDelta: delta ? createDelta( From 6a837d5399fce4445ffe7f3771fedf7087c2c80d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 18:18:04 +0200 Subject: [PATCH 7/8] Shorten math comparisons --- .../src/pages/detailed-query/page.vue | 48 +++++-------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/site/frontend/src/pages/detailed-query/page.vue b/site/frontend/src/pages/detailed-query/page.vue index 5cda988c9..caf063f04 100644 --- a/site/frontend/src/pages/detailed-query/page.vue +++ b/site/frontend/src/pages/detailed-query/page.vue @@ -59,32 +59,22 @@ const tableData = computed(() => { aValue = a.timeSeconds; bValue = b.timeSeconds; // Use percentage change as secondary sort for equal absolute values - aSecondary = - a.timeDelta !== null ? Math.abs(a.timeDelta.percentage) : 0; - bSecondary = - b.timeDelta !== null ? Math.abs(b.timeDelta.percentage) : 0; + aSecondary = Math.abs(a.timeDelta?.percentage ?? 0); + bSecondary = Math.abs(b.timeDelta?.percentage ?? 0); break; case "executions": // Executions aValue = a.executions; bValue = b.executions; // Use percentage change as secondary sort for equal absolute values - aSecondary = - a.executionsDelta !== null - ? Math.abs(a.executionsDelta.percentage) - : 0; - bSecondary = - b.executionsDelta !== null - ? Math.abs(b.executionsDelta.percentage) - : 0; + aSecondary = Math.abs(a.executionsDelta?.percentage ?? 0); + bSecondary = Math.abs(b.executionsDelta?.percentage ?? 0); break; case "cacheHits": // Hits aValue = a.cacheHits; bValue = b.cacheHits; // Use percentage change as secondary sort for equal absolute values - aSecondary = - a.cacheHitsDelta !== null ? Math.abs(a.cacheHitsDelta.percentage) : 0; - bSecondary = - b.cacheHitsDelta !== null ? Math.abs(b.cacheHitsDelta.percentage) : 0; + aSecondary = Math.abs(a.cacheHitsDelta?.percentage ?? 0); + bSecondary = Math.abs(b.cacheHitsDelta?.percentage ?? 0); break; case "incrementalLoading": // Incremental loading (s) aValue = a.incrementalLoading; @@ -118,23 +108,15 @@ const tableData = computed(() => { bValue = b.executionsDelta !== null ? b.executionsDelta.delta : -Infinity; // Use percentage as secondary sort for equal delta values - aSecondary = - a.executionsDelta !== null - ? Math.abs(a.executionsDelta.percentage) - : 0; - bSecondary = - b.executionsDelta !== null - ? Math.abs(b.executionsDelta.percentage) - : 0; + aSecondary = Math.abs(a.executionsDelta?.percentage ?? 0); + bSecondary = Math.abs(b.executionsDelta?.percentage ?? 0); break; case "cacheHitsDelta": // Cache hits delta aValue = a.cacheHitsDelta !== null ? a.cacheHitsDelta.delta : -Infinity; bValue = b.cacheHitsDelta !== null ? b.cacheHitsDelta.delta : -Infinity; // Use percentage as secondary sort for equal delta values - aSecondary = - a.cacheHitsDelta !== null ? Math.abs(a.cacheHitsDelta.percentage) : 0; - bSecondary = - b.cacheHitsDelta !== null ? Math.abs(b.cacheHitsDelta.percentage) : 0; + aSecondary = Math.abs(a.cacheHitsDelta?.percentage ?? 0); + bSecondary = Math.abs(b.cacheHitsDelta?.percentage ?? 0); break; case "incrementalLoadingDelta": // Incremental loading delta aValue = @@ -146,14 +128,8 @@ const tableData = computed(() => { ? b.incrementalLoadingDelta.delta : -Infinity; // Use percentage as secondary sort for equal delta values - aSecondary = - a.incrementalLoadingDelta !== null - ? Math.abs(a.incrementalLoadingDelta.percentage) - : 0; - bSecondary = - b.incrementalLoadingDelta !== null - ? Math.abs(b.incrementalLoadingDelta.percentage) - : 0; + aSecondary = Math.abs(a.incrementalLoadingDelta?.percentage ?? 0); + bSecondary = Math.abs(b.incrementalLoadingDelta?.percentage ?? 0); break; default: aValue = a.label; From 5da3cb4b90e4fa00f6b4b1be6f7f2d3fd3a87d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 8 Jul 2025 10:42:39 +0200 Subject: [PATCH 8/8] Update analyzeme to `12.0.3` --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bffbd9400..0ff3d610d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,14 +62,14 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "analyzeme" -version = "12.0.0" +version = "12.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20feead6e1e9722cb326230127d5ca89fe5c4609cb0dd047c3b58c81a26cfd18" +checksum = "e204612e886ffe830ae0a943d9b66bd3418adb17d859d81cb1c457eee38557aa" dependencies = [ "decodeme 10.1.3", - "decodeme 12.0.0", + "decodeme 12.0.3", "measureme 10.1.3", - "measureme 12.0.0", + "measureme 12.0.3", "memchr", "rustc-hash", "serde", @@ -614,11 +614,11 @@ dependencies = [ [[package]] name = "decodeme" -version = "12.0.0" +version = "12.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad52c78335c03452cb0404e5ae32e9e291f15186091be8d2e22d942f417475e0" +checksum = "ecd00d8cf813abee38134c06d9164d1b82f75158c0dbfdb1fde429dee1e2ce9d" dependencies = [ - "measureme 12.0.0", + "measureme 12.0.3", "memchr", "rustc-hash", "serde", @@ -1585,9 +1585,9 @@ dependencies = [ [[package]] name = "measureme" -version = "12.0.0" +version = "12.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed2d26a61b68ba37bf203340b6b6addf4da2c2e7cfb0cff700792088d69ebc9" +checksum = "6ebd1ebda747ae161a4a377bf93f87e18d46faad2331cc0c7d25b84b1d445f49" dependencies = [ "log", "memmap2",