forgeTimings

tcmts.dev.forgeTimings · #wdhmxqab · term · runs on the server

uses process

How long what the web UI's pages compute takes on a codebase (tcm run tcmts.dev.forgeTimings <dir>): the warm-up a server starts with, and the longest it holds up other work; each step the first time (cold), as the first requests after the head moves make it; then the history summaries of the latest check entries compared with diffNamespaces of their names read whole.

import { historyList, stateAt } from "#codebase/tcmts/cli/changes";
import { openApart } from "#codebase/tcmts/cli/codebase";
import { diffNamespaces } from "#codebase/tcmts/cli/diff";
import {
  childrenOf, entrySummary, nameHistory, namesNow, pageOf, placeMix, projectNow, releaseHas, roleNow, shareCache,
  summaryOf, testsReaching, warmUp,
} from "#codebase/tcmts/share";
import type { Share } from "#codebase/tcmts/share";

export async function forgeTimings(
  dir: string,
  name = "tcmts.core.hash.shortHash",
  check = "60",
): Promise<void> {
  const cb = openApart(dir);
  const fresh = (): Pick<Share, "cb" | "cache"> => ({ cb, cache: shareCache() });
  const time = <T>(label: string, f: () => T): T => {
    const t = performance.now();
    const v = f();
    console.log(`${label.padEnd(44)} ${(performance.now() - t).toFixed(1).padStart(9)} ms`);
    return v;
  };
  // the warm-up, first (from cold): how long, and the longest a page asked for meanwhile would wait
  const warm = fresh();
  let longest = 0;
  let last = performance.now();
  const tick = setInterval(() => {
    const now = performance.now();
    longest = Math.max(longest, now - last);
    last = now;
  }, 1);
  const t = performance.now();
  await warmUp(warm);
  clearInterval(tick);
  console.log(
    `${"warm-up".padEnd(44)} ${(performance.now() - t).toFixed(1).padStart(9)} ms, the longest wait ${longest.toFixed(1)} ms`,
  );

  const s = fresh();
  const rows = time("names (files too)", () => namesNow(s));
  time("project", () => projectNow(s));
  time("the map's bars (placement)", () =>
    childrenOf(rows, projectNow(s).root).namespaces.forEach((n) => placeMix(s, n.rows, n.name)),
  );
  time("roles of every name", () => rows.forEach((r) => roleNow(s, r)));
  const list = time("historyList 61", () => historyList(cb, 61));
  time("history page 0 (30 summaries)", () =>
    list.slice(0, 30).forEach((h) => entrySummary(s, h.hash)),
  );
  time("history page 1 (30 summaries)", () =>
    list.slice(30, 60).forEach((h) => entrySummary(s, h.hash)),
  );
  const trees = s.cache.trees(cb);
  const under = name.split(".").slice(0, 2).join(".");
  time(
    `history under ${under} (400 entries)`,
    () =>
      historyList(cb, 400).filter(
        (h) =>
          trees
            .delta(cb.store.causal(h.parents[0]!)?.namespace, cb.store.causal(h.hash)!.namespace)
            .some((d) => d.path.startsWith(`${under}.`)) && entrySummary(s, h.hash),
      ).length,
  );
  const hash = rows.find((r) => r.path === name)?.hash;
  if (!hash) throw new Error(`no ${name}`);
  time(`pageOf ${name}`, () => pageOf(s as Share, hash));
  time(`testsReaching ${name}`, () => testsReaching(cb, hash).length);
  time(`nameHistory ${name}`, () => nameHistory(s, name));
  time(
    "releases containing it",
    () => cb.store.releases().filter((r) => releaseHas(s, r.causal, hash)).length,
  );

  // the summaries are diffNamespaces' of the entries' names read whole
  const checked = fresh();
  let differ = 0;
  const n = Number(check);
  for (const h of historyList(cb, n)) {
    const d = diffNamespaces(
      stateAt(cb, h.parents[0]!),
      stateAt(cb, h.hash),
      (x) => cb.store.getDef(x)!.ir,
    );
    const whole = summaryOf(d);
    if (JSON.stringify(whole) !== JSON.stringify(entrySummary(checked, h.hash))) {
      differ++;
      console.log(`  differs: ${h.short} ${h.command}`);
    }
  }
  console.log(
    `summaries of the latest ${n} entries: ${differ ? `${differ} differ` : "all the same as diffNamespaces'"}`,
  );
  if (differ) process.exitCode = 1;
}

uses