Measure semantic activation refresh independently from download and idle time
This commit is contained in:
1 parent
9aae3f8216
commit
19d949fd13
6 files changed
+140
-22
No files matched your search
+28
-13
@@ -30,7 +30,11 @@ import {
|
|||||||
spanDepth,
|
spanDepth,
|
||||||
briefMs,
|
briefMs,
|
||||||
} from "./search-performance";
|
} from "./search-performance";
|
||||||
import type { MeasuredResponse, SearchLane } from "./search-performance";
|
import type {
|
||||||
|
MeasuredResponse,
|
||||||
|
SearchLane,
|
||||||
|
SearchRefreshTrigger,
|
||||||
|
} from "./search-performance";
|
||||||
import { displayPath } from "./path-display";
|
import { displayPath } from "./path-display";
|
||||||
import { ResultSelection } from "./selection-state";
|
import { ResultSelection } from "./selection-state";
|
||||||
import {
|
import {
|
||||||
@@ -449,7 +453,7 @@ async function refreshSemanticStatus() {
|
|||||||
canSearchSemantically() &&
|
canSearchSemantically() &&
|
||||||
latestSearch?.id === requestId
|
latestSearch?.id === requestId
|
||||||
)
|
)
|
||||||
submitSearch(latestSearch, "hybrid");
|
refreshIndexedSearch("semantic_activation");
|
||||||
if (working || (!status.ready && !error)) queueSemanticRefresh();
|
if (working || (!status.ready && !error)) queueSemanticRefresh();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
element("semantic-status").textContent =
|
element("semantic-status").textContent =
|
||||||
@@ -1088,7 +1092,22 @@ function submitSearch(request: SearchRequest, lane: SearchLane) {
|
|||||||
(lane === "lexical" ? lexicalLane : hybridLane).submit(request);
|
(lane === "lexical" ? lexicalLane : hybridLane).submit(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshIndexedSearch() {
|
function searchMeasurementContext() {
|
||||||
|
return {
|
||||||
|
model: semanticStatus?.worker_info?.model ?? null,
|
||||||
|
device: semanticStatus?.worker_info?.device ?? null,
|
||||||
|
runtime: semanticStatus?.worker_info?.runtime ?? null,
|
||||||
|
threads: semanticStatus?.worker_info?.threads ?? null,
|
||||||
|
dimensions: semanticStatus?.worker_info?.dimensions ?? null,
|
||||||
|
semantic_ready: canSearchSemantically(),
|
||||||
|
semantic_generation: semanticStatus?.generation ?? null,
|
||||||
|
indexed_chunks: semanticStatus?.chunks ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshIndexedSearch(
|
||||||
|
trigger: SearchRefreshTrigger = "filesystem_refresh",
|
||||||
|
) {
|
||||||
const previous = latestSearch;
|
const previous = latestSearch;
|
||||||
if (
|
if (
|
||||||
!previous ||
|
!previous ||
|
||||||
@@ -1106,7 +1125,11 @@ function refreshIndexedSearch() {
|
|||||||
...previous,
|
...previous,
|
||||||
id: ++requestId,
|
id: ++requestId,
|
||||||
started: refreshStarted,
|
started: refreshStarted,
|
||||||
measurement: previous.measurement.freshForRefresh(refreshStarted),
|
measurement: previous.measurement.freshForRefresh(
|
||||||
|
refreshStarted,
|
||||||
|
trigger,
|
||||||
|
searchMeasurementContext(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
latestSearch = refreshed;
|
latestSearch = refreshed;
|
||||||
submitSearch(refreshed, "lexical");
|
submitSearch(refreshed, "lexical");
|
||||||
@@ -1188,15 +1211,7 @@ async function search(inputAt = performance.now()) {
|
|||||||
inputAt,
|
inputAt,
|
||||||
performance.now(),
|
performance.now(),
|
||||||
element<HTMLInputElement>("performance-toggle").checked,
|
element<HTMLInputElement>("performance-toggle").checked,
|
||||||
{
|
searchMeasurementContext(),
|
||||||
model: semanticStatus?.worker_info?.model ?? null,
|
|
||||||
device: semanticStatus?.worker_info?.device ?? null,
|
|
||||||
runtime: semanticStatus?.worker_info?.runtime ?? null,
|
|
||||||
threads: semanticStatus?.worker_info?.threads ?? null,
|
|
||||||
dimensions: semanticStatus?.worker_info?.dimensions ?? null,
|
|
||||||
semantic_ready: canSearchSemantically(),
|
|
||||||
indexed_chunks: semanticStatus?.chunks ?? null,
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
latestSearch = request;
|
latestSearch = request;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export interface MeasuredResponse<T> {
|
|||||||
metrics: NativeMetrics;
|
metrics: NativeMetrics;
|
||||||
}
|
}
|
||||||
export type SearchLane = "lexical" | "hybrid";
|
export type SearchLane = "lexical" | "hybrid";
|
||||||
|
export type SearchRefreshTrigger = "filesystem_refresh" | "semantic_activation";
|
||||||
export interface AttemptStart {
|
export interface AttemptStart {
|
||||||
lane: SearchLane;
|
lane: SearchLane;
|
||||||
startedAt: number;
|
startedAt: number;
|
||||||
@@ -44,6 +45,7 @@ interface InputTimingSummary {
|
|||||||
|
|
||||||
export class SearchMeasurement {
|
export class SearchMeasurement {
|
||||||
private originalInput: Readonly<InputTimingSummary> | null = null;
|
private originalInput: Readonly<InputTimingSummary> | null = null;
|
||||||
|
private trigger: "user_search" | SearchRefreshTrigger = "user_search";
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
inputAt: number;
|
inputAt: number;
|
||||||
scheduledAt: number;
|
scheduledAt: number;
|
||||||
@@ -74,9 +76,14 @@ export class SearchMeasurement {
|
|||||||
this.debug = debug;
|
this.debug = debug;
|
||||||
this.context = { ...context };
|
this.context = { ...context };
|
||||||
}
|
}
|
||||||
/** Filesystem updates are independent requests, not elapsed user idle time. */
|
/** Background updates are independent requests, not elapsed user idle time. */
|
||||||
freshForRefresh(now: number): SearchMeasurement {
|
freshForRefresh(
|
||||||
const refreshed = new SearchMeasurement(now, now, this.debug, this.context);
|
now: number,
|
||||||
|
trigger: SearchRefreshTrigger = "filesystem_refresh",
|
||||||
|
context = this.context,
|
||||||
|
): SearchMeasurement {
|
||||||
|
const refreshed = new SearchMeasurement(now, now, this.debug, context);
|
||||||
|
refreshed.trigger = trigger;
|
||||||
// Preserve one fixed-size numeric snapshot, never an ancestor trace/history.
|
// Preserve one fixed-size numeric snapshot, never an ancestor trace/history.
|
||||||
// Pending responses on the old request cannot rewrite this snapshot.
|
// Pending responses on the old request cannot rewrite this snapshot.
|
||||||
refreshed.originalInput = Object.freeze({
|
refreshed.originalInput = Object.freeze({
|
||||||
@@ -165,7 +172,7 @@ export class SearchMeasurement {
|
|||||||
export() {
|
export() {
|
||||||
return {
|
return {
|
||||||
version: 1,
|
version: 1,
|
||||||
trigger: this.originalInput ? "filesystem_refresh" : "user_search",
|
trigger: this.trigger,
|
||||||
original_input: this.originalInput ? { ...this.originalInput } : null,
|
original_input: this.originalInput ? { ...this.originalInput } : null,
|
||||||
context: this.context,
|
context: this.context,
|
||||||
clock_note:
|
clock_note:
|
||||||
|
|||||||
@@ -161,3 +161,30 @@ test('repeated refreshes retain a bounded immutable numeric origin without repla
|
|||||||
assert.equal(origin.first_results_ms, 72);
|
assert.equal(origin.first_results_ms, 72);
|
||||||
assert.equal(origin.hybrid_final_results_ms, null);
|
assert.equal(origin.hybrid_final_results_ms, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('semantic activation excludes download time and records the promoted context separately', () => {
|
||||||
|
const original = new SearchMeasurement(100, 100, true, {indexed_chunks:3});
|
||||||
|
original.submitted('hybrid', 220);
|
||||||
|
finish(original, 'hybrid', 220, 230, native, false);
|
||||||
|
original.displayed('hybrid', 230, 238, 3);
|
||||||
|
const context = {indexed_chunks:4, semantic_ready:true};
|
||||||
|
const promoted = original.freshForRefresh(144000, 'semantic_activation', context);
|
||||||
|
context.indexed_chunks = 999;
|
||||||
|
promoted.submitted('lexical', 144000);
|
||||||
|
finish(promoted, 'lexical', 144001, 144004, native, false);
|
||||||
|
promoted.displayed('lexical', 144004, 144005, 1);
|
||||||
|
promoted.submitted('hybrid', 144120);
|
||||||
|
finish(promoted, 'hybrid', 144120, 144128, native, false);
|
||||||
|
promoted.displayed('hybrid', 144128, 144138, 4);
|
||||||
|
const report = promoted.export();
|
||||||
|
assert.equal(report.trigger, 'semantic_activation');
|
||||||
|
assert.equal(report.first_results_ms, 5);
|
||||||
|
assert.equal(report.hybrid_final_results_ms, 138);
|
||||||
|
assert.equal(report.context.indexed_chunks, 4);
|
||||||
|
assert.equal(report.original_input.hybrid_final_results_ms, 138);
|
||||||
|
assert.equal(report.attempts.length, 2);
|
||||||
|
assert.equal(original.export().context.indexed_chunks, 3);
|
||||||
|
const next = promoted.freshForRefresh(300000);
|
||||||
|
assert.equal(next.export().trigger, 'filesystem_refresh');
|
||||||
|
assert.deepEqual(next.export().original_input, report.original_input);
|
||||||
|
});
|
||||||
@@ -61,9 +61,14 @@ passed **51**, and both strict all-target Clippy checks, formatting and the
|
|||||||
frontend production build passed. The actual Google integration above was run
|
frontend production build passed. The actual Google integration above was run
|
||||||
separately; ignored entries in the default suite are not execution evidence.
|
separately; ignored entries in the default suite are not execution evidence.
|
||||||
|
|
||||||
Native UI interaction during a genuine delayed HTTPS media download, failure,
|
Native Linux UI interaction during a genuine delayed HTTPS media download,
|
||||||
retry and promotion remains to be executed. The prepared Linux QA plan uses only
|
failure, retry and full promotion passed on `9aae3f8`, retaining the query worker
|
||||||
an owned loopback CONNECT proxy and isolated app environment; it does not change
|
and explicit selection. Its actual first unseen query reported 84 ms native and
|
||||||
|
293 ms through the DOM update on four fixture files. A later cached debug request
|
||||||
|
is a separate sample. The test exposed a semantic-activation clock defect;
|
||||||
|
the frontend now starts an independent refresh measurement, but a focused native
|
||||||
|
retest remains pending. See [native evidence](LINUX-DESKTOP-VALIDATION.md).
|
||||||
|
The owned loopback CONNECT proxy and isolated app environment do not change
|
||||||
the product's pinned download URL or verification. Native Windows/macOS, GPU,
|
the product's pinned download URL or verification. Native Windows/macOS, GPU,
|
||||||
large libraries and actual first-input measurements remain open. Document indexing
|
large libraries and actual first-input measurements remain open. Document indexing
|
||||||
still needs to finish a publishable generation; earlier model readiness does not
|
still needs to finish a publishable generation; earlier model readiness does not
|
||||||
|
|||||||
@@ -272,3 +272,63 @@ All owned test and benchmark handles ended successfully. Subsequent process
|
|||||||
inspection found no surviving Google workers, Cargo or Rust compiler processes.
|
inspection found no surviving Google workers, Cargo or Rust compiler processes.
|
||||||
Native desktop packaging with this new worker, actual GPU, macOS and
|
Native desktop packaging with this new worker, actual GPU, macOS and
|
||||||
representative performance remain open.
|
representative performance remain open.
|
||||||
|
|
||||||
|
## Genuine first-use media download: `9aae3f8`
|
||||||
|
|
||||||
|
Native embedded Release build passed in 2m 52s, using matching
|
||||||
|
`index-STH19o-O.js`. Executable SHA-256:
|
||||||
|
`229312e05629555956c659a83d56fa3dcc9e8830736a062c9208ce704ce11fa6`;
|
||||||
|
frontend SHA-256:
|
||||||
|
`dc3ee20bc7bb3eda347c142ee9fab3e10b8d17037402d21c5cc6de1a5f0dd967`.
|
||||||
|
The isolated resource override used the normal Linux query-role worker
|
||||||
|
`b52d50a1e676bd4bf64124daff1c4ce83d86a8bde01e4eaf09838cbb24a4c28f`.
|
||||||
|
|
||||||
|
The fresh owned `desktop-qa-earlytext` directory isolated XDG cache/config/data,
|
||||||
|
settings, index, decoded scratch and model cache. Initially only the verified
|
||||||
|
309,855,456-byte backbone was present, hardlinked from the verified native cache.
|
||||||
|
A fixture contained three document/code files and a small BMP. The app's
|
||||||
|
HTTPS_PROXY/HTTP_PROXY pointed only its own process environment to an owned
|
||||||
|
loopback CONNECT proxy at `127.0.0.1:18943`, throttled to 4 MiB/s. The proxy
|
||||||
|
forwarded opaque TLS to real Hugging Face/CDN HTTPS; there was no TLS interception,
|
||||||
|
production URL override or global network change.
|
||||||
|
|
||||||
|
Actual native UI evidence:
|
||||||
|
|
||||||
|
- While the genuine projector download was incomplete (202,664,870-byte partial,
|
||||||
|
no installed projector), generation 1 contained three text chunks. The UI
|
||||||
|
reported text search ready and media preparation in progress. The first
|
||||||
|
actual remembered input found the supplier passage: one basic observation of
|
||||||
|
**84 ms native / 293 ms displayed**. This is not cold startup or warm p95.
|
||||||
|
- Closing owned proxy tunnels and rejecting further CONNECT attempts caused
|
||||||
|
three download attempts to fail and removed the partial file. Generation 1
|
||||||
|
and query worker PID 397 remained usable. Expanded model details showed
|
||||||
|
media setup failure, text availability and an actual Retry model setup button.
|
||||||
|
- Restoring proxy forwarding and clicking that UI button restarted the genuine
|
||||||
|
pinned download. A separate cached debug rerun during retry measured
|
||||||
|
**2.0 ms native / 44 ms first / 138 ms final displayed**; it is not the first
|
||||||
|
user input. Its copied timing report contained no query text or source paths.
|
||||||
|
- Verified full projector installation produced the exact 554,821,024 bytes and
|
||||||
|
SHA-256 `c4a8a52691ecef40618438928bdf9e68379b854e24166f292592353db0aab64f`.
|
||||||
|
Generation 2 contained four chunks, including image content. The retained
|
||||||
|
CPU query worker stayed PID 397 through failure, retry and promotion. Explicit
|
||||||
|
selection of `retry.rs` remained selected when the image entered ahead of it.
|
||||||
|
|
||||||
|
This interaction uncovered a separate semantic-activation timing defect:
|
||||||
|
full-media promotion reused the prior search measurement and displayed
|
||||||
|
**SHOWN 143,928 ms** despite an 8.0 ms native search. The copied report retained
|
||||||
|
`trigger: user_search` and the old three-chunk context. This value includes
|
||||||
|
media download/idle time and must not be presented as fresh search latency.
|
||||||
|
Watcher refresh timing was already corrected; semantic readiness/activation
|
||||||
|
needs the equivalent independent refresh measurement and another native retest.
|
||||||
|
|
||||||
|
Local ignored evidence: `.searchi/qa/linux-earlytext-*.png`,
|
||||||
|
`linux-earlytext-{retry-search,promotion-search}.json`, `linux-earlytext-states.jsonl`
|
||||||
|
and `linux-earlytext-cpu-audit.json`. Native `desktop-qa-earlytext` retains proxy
|
||||||
|
events, logs and fixture data. The owned proxy helper is
|
||||||
|
`.searchi/linux-validation/opaque_proxy.py`. The private GPU-masked software
|
||||||
|
display audit found no GPU providers or descriptors; the query worker used Zen4
|
||||||
|
CPU, one thread and zero swap. Both owned UI/proxy handles ended successfully,
|
||||||
|
Xvfb exited zero, and process inspection found no surviving app, worker, WebKit,
|
||||||
|
DBus, clipboard, display or proxy helpers. Outer `/dev/dxg` remained real.
|
||||||
|
Physical desktop, installed resource discovery, representative relevance,
|
||||||
|
first-install cold storage, p95, GPU and macOS gates remain open.
|
||||||
+6
-2
@@ -83,13 +83,17 @@ model loading must not be silently included in a warm-query claim.
|
|||||||
|
|
||||||
## Reproducible performance validation
|
## Reproducible performance validation
|
||||||
|
|
||||||
Automatic filesystem refreshes start a new frontend measurement at the refresh
|
Automatic filesystem and semantic-readiness/publication refreshes start a new
|
||||||
event. `trigger: "filesystem_refresh"` distinguishes them from user searches;
|
frontend measurement at the refresh event. `trigger: "filesystem_refresh"` or
|
||||||
|
`"semantic_activation"` distinguishes them from user searches;
|
||||||
`SHOWN` and `latest_displayed_ms` exclude time spent idle before that event.
|
`SHOWN` and `latest_displayed_ms` exclude time spent idle before that event.
|
||||||
`original_input` retains a fixed-size snapshot of the original debounce and
|
`original_input` retains a fixed-size snapshot of the original debounce and
|
||||||
display timings. Refreshes do not replay previous attempts or append ancestor
|
display timings. Refreshes do not replay previous attempts or append ancestor
|
||||||
traces. A refresh before the first response leaves that original response timing
|
traces. A refresh before the first response leaves that original response timing
|
||||||
null rather than inventing a first-input measurement.
|
null rather than inventing a first-input measurement.
|
||||||
|
The refreshed context captures current generation/readiness/chunk counts rather
|
||||||
|
than retaining the pre-publication context. Semantic activation also invalidates
|
||||||
|
older queued responses and reruns the progressive lanes with the current filters.
|
||||||
|
|
||||||
Record build profile, CPU/device and thread budget, VM/host resources, corpus and
|
Record build profile, CPU/device and thread budget, VM/host resources, corpus and
|
||||||
active generation, filters, cold/warm state, concurrent indexing and setup costs.
|
active generation, filters, cold/warm state, concurrent indexing and setup costs.
|
||||||
|
|||||||
Reference in new issue
Block a user