feat(cli): time the offline store-load separately from graph build

The graph_build_ms timer covered only builder.build() (the in-memory int-CSR
pack, a few hundred ms). It excluded the real pre-scoring cost: reading and
deserializing every kind:3 contact list out of the store. Add store_load_ms
(offline path) so the three phases — store load, CSR build, scoring — are each
measured and reported (stderr + JSON), instead of the load hiding behind a
misleadingly small build number.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RWk2ZMrGBSr4WenKgwqmbB
This commit is contained in:
Claude
2026-07-07 01:50:07 +00:00
parent f24e0f92d4
commit d20f3d71e3
@@ -173,6 +173,11 @@ object GrapeRankCommand {
var rounds = 0
var relaysContactedCount = 0
var contactListsFed = 0
// Wall time to read + deserialize the contact lists out of the store
// (offline path only; online streams them in during the crawl). This
// is the real pre-scoring cost — the int-CSR build afterwards is a
// cheap in-memory pack.
var storeLoadMs: Long? = null
val hopOf = HashMap<HexKey, Int>()
if (!offline) {
@@ -365,13 +370,15 @@ object GrapeRankCommand {
)
} else {
// Offline: stream contact lists from the local store into the graph.
val loadStart = System.nanoTime()
for (event in ctx.store.query<Event>(Filter(kinds = listOf(ContactListEvent.KIND)))) {
if (event is ContactListEvent) {
builder.addFollows(event.pubKey, event.verifiedFollowKeySet())
contactListsFed++
}
}
System.err.println("[graperank] offline: $contactListsFed contact lists from local store")
storeLoadMs = (System.nanoTime() - loadStart) / 1_000_000
System.err.println("[graperank] offline: $contactListsFed contact lists from local store in $storeLoadMs ms")
}
// Mutes + reports come from the store (both paths). Far fewer than contact
@@ -426,6 +433,7 @@ object GrapeRankCommand {
"graph_users" to graph.nodeCount,
"graph_edges" to graph.edgeCount(),
"users_scored" to rankedIds.size,
"store_load_ms" to storeLoadMs,
"graph_build_ms" to buildMs,
"scoring_ms" to scoringMs,
"scores" to