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", diff --git a/site/frontend/src/pages/detailed-query/page.vue b/site/frontend/src/pages/detailed-query/page.vue index 904417a97..caf063f04 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); @@ -21,9 +22,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 @@ -57,23 +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 = Math.abs(a.cacheHitsDelta?.percentage ?? 0); + bSecondary = Math.abs(b.cacheHitsDelta?.percentage ?? 0); break; case "incrementalLoading": // Incremental loading (s) aValue = a.incrementalLoading; @@ -107,14 +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 = Math.abs(a.cacheHitsDelta?.percentage ?? 0); + bSecondary = Math.abs(b.cacheHitsDelta?.percentage ?? 0); break; case "incrementalLoadingDelta": // Incremental loading delta aValue = @@ -126,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; @@ -173,10 +169,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 +219,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 +235,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"; @@ -439,6 +435,20 @@ loadData(); >Executions delta + + Hits + + + Hits delta + Incremental loading (s)Incr. loading (s) Incremental loading deltaIncr. loading delta @@ -484,6 +494,10 @@ loadData(); + {{ 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 e8de53195..4d8da1542 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}; @@ -229,6 +242,8 @@ interface TableRowData { timeDelta: DeltaData | null; executions: number; executionsDelta: DeltaData | null; + cacheHits: number; + cacheHitsDelta: DeltaData | null; incrementalLoading: number; incrementalLoadingDelta: DeltaData | null; } @@ -244,85 +259,66 @@ 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: ProfileElementDelta | undefined +): 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, + cacheHits: value.number_of_cache_hits, + cacheHitsDelta: delta + ? createDelta( + value.number_of_cache_hits, + delta.number_of_cache_hits, + 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): { 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, };