feat(cli): 0.R2 - ludic deps reports the widest function and ratchets it
widest_function: the most states any function or entry point of the program's own takes, with which one; --check holds it like the other numbers and --baseline writes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
808c4a6f7a
commit
55c1de8734
5 changed files with 64933 additions and 59230 deletions
|
|
@ -116,9 +116,46 @@ function deps_flush() -> void {
|
|||
deps_line(f, g_dp_aliases[i])
|
||||
i += 1
|
||||
}
|
||||
deps_widths(f)
|
||||
file_close(f)
|
||||
}
|
||||
|
||||
# 0.R2: how many states each function and entry point takes - `width <n> <name> <file>:<line> <pkg>`,
|
||||
# the program's own code only (not the runtime's)
|
||||
function deps_widths(f: pointer) -> void {
|
||||
var i = 0
|
||||
while i < len(prog) {
|
||||
let d = prog[i]
|
||||
if d.file != null and not is_runtime_file(d.file) {
|
||||
var n = 0
|
||||
var name = d.s
|
||||
if d.kind == N_FN {
|
||||
var k = 0
|
||||
while k < len(d.kids) {
|
||||
if d.kids[k].kind == N_PARAM and is_state_ty(d.kids[k].ty) { n += 1 }
|
||||
k += 1
|
||||
}
|
||||
}
|
||||
if (d.kind == N_MAIN or d.kind == N_SYS) and d.a != null {
|
||||
if d.kind == N_MAIN { name = "entry" }
|
||||
n = deps_body_states(d.a)
|
||||
}
|
||||
var pkg = 0
|
||||
if not (pkg_of_file(d.file) == "") { pkg = 1 }
|
||||
if n > 0 { deps_line(f, `width {itoa(n)} {name} {d.file}:{itoa(d.line)} {itoa(pkg)}`) }
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
function deps_body_states(b: Node) -> int {
|
||||
var n = 0
|
||||
var k = 0
|
||||
while k < len(b.kids) and b.kids[k].tps != null and (b.kids[k].tps == "state") {
|
||||
n += 1
|
||||
k += 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
# A local that holds another module's global record (or a piece of one) - `let t = thing_cur`,
|
||||
# `let s = slots[i]` - writes into that module's state when it is written through: `t.used = 1`.
|
||||
# That is caught here for a local bound straight from the global (or from such a local) in the
|
||||
|
|
|
|||
62051
selfhost/ludicc.seed.ll
62051
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -18,7 +18,8 @@
|
|||
# other module (a leaf); largest_cycle: the largest set of modules that all reach each other, not
|
||||
# counting the edges inside a declared layer (which may go round by design - reported beside it);
|
||||
# cross_writes: assignments to a global of another module; globals_written_from_outside: those
|
||||
# globals, each counted once.
|
||||
# globals, each counted once; widest_function: the most states any function or entry point of the
|
||||
# program's own takes (0.R2 - a reducer takes one, and the dispatchers should come down to a few).
|
||||
var dp_mods: []pointer = null
|
||||
var dp_pkg: []int = null
|
||||
var dp_uses: []pointer = null
|
||||
|
|
@ -32,6 +33,8 @@ var dp_aliases: []pointer = null # writes through a local holding another m
|
|||
var dp_wowner: []pointer = null
|
||||
var dp_wname: []pointer = null
|
||||
var dp_wfrom: []pointer = null
|
||||
var dp_wide_n: int = 0 # 0.R2: the widest function's state parameters, and which
|
||||
var dp_wide_at: pointer = ""
|
||||
|
||||
function dp_words(line: pointer) -> []pointer {
|
||||
let out = new []pointer
|
||||
|
|
@ -64,6 +67,7 @@ function dp_load(path: pointer) -> bool {
|
|||
if text == null { return false }
|
||||
dp_mods = new []pointer; dp_pkg = new []int; dp_uses = new []pointer; dp_layer = new []pointer
|
||||
dp_ef = new []int; dp_et = new []int; dp_ec = new []int; dp_en = new []pointer
|
||||
dp_wide_n = 0; dp_wide_at = ""
|
||||
dp_writes = new []pointer; dp_aliases = new []pointer; dp_wowner = new []pointer; dp_wname = new []pointer; dp_wfrom = new []pointer
|
||||
let lines = split_lines(text)
|
||||
for i in 0 .. len(lines) {
|
||||
|
|
@ -85,6 +89,10 @@ function dp_load(path: pointer) -> bool {
|
|||
push(dp_en, w[4])
|
||||
}
|
||||
if len(w) >= 6 and w[0] == "alias" { push(dp_aliases, lines[i]) }
|
||||
if len(w) >= 5 and w[0] == "width" and w[4] == "0" and s_to_int(w[1]) > dp_wide_n {
|
||||
dp_wide_n = s_to_int(w[1])
|
||||
dp_wide_at = `{w[2]} ({w[3]})`
|
||||
}
|
||||
if len(w) >= 5 and w[0] == "write" {
|
||||
push(dp_wowner, w[1])
|
||||
push(dp_wname, w[2])
|
||||
|
|
@ -196,7 +204,7 @@ var dp_vals: []int = null
|
|||
var dp_cycle: []int = null
|
||||
var dp_cycle_all: []int = null # the same with the layers' own edges counted
|
||||
function dp_numbers() -> void {
|
||||
dp_names = ["modules", "dependencies", "largest_cycle", "cross_writes", "globals_written_from_outside"]
|
||||
dp_names = ["modules", "dependencies", "largest_cycle", "cross_writes", "globals_written_from_outside", "widest_function"]
|
||||
var mods = 0
|
||||
for k in 0 .. len(dp_mods) { if dp_own(k) { mods += 1 } }
|
||||
var deps = 0
|
||||
|
|
@ -217,13 +225,15 @@ function dp_numbers() -> void {
|
|||
if not dup { push(seen, key) }
|
||||
}
|
||||
}
|
||||
dp_vals = [mods, deps, len(dp_cycle), writes, len(seen)]
|
||||
dp_vals = [mods, deps, len(dp_cycle), writes, len(seen), dp_wide_n]
|
||||
}
|
||||
|
||||
# ---- the command --------------------------------------------------------------
|
||||
function dp_print_numbers() -> void {
|
||||
for i in 0 .. len(dp_names) { print(`{dp_names[i]}: {string(dp_vals[i])}`) }
|
||||
print(`in the largest cycle: {dp_sorted_names(dp_cycle)}`)
|
||||
if dp_wide_n == 1 { print(`the widest function: {dp_wide_at}, 1 state`) }
|
||||
if dp_wide_n > 1 { print(`the widest function: {dp_wide_at}, {string(dp_wide_n)} states`) }
|
||||
let layers = dp_layers()
|
||||
if layers != "" {
|
||||
print(`layers: {layers}`)
|
||||
|
|
|
|||
|
|
@ -476,13 +476,19 @@ function deps_case() -> void {
|
|||
let lbl = "ludic deps: the numbers, --check against a baseline, --dot, --writes"
|
||||
let p = "examples/modules/tangle.ludic"
|
||||
let got = capture(`bin/ludic deps {p} 2>&1`)
|
||||
let want = "modules: 3\ndependencies: 2\nlargest_cycle: 2\ncross_writes: 1\nglobals_written_from_outside: 1\nin the largest cycle: a b\n"
|
||||
let want = "modules: 3\ndependencies: 2\nlargest_cycle: 2\ncross_writes: 1\nglobals_written_from_outside: 1\nwidest_function: 1\nin the largest cycle: a b\nthe widest function: a_run (examples/modules/tangle/a/index.ludic:3), 1 state\n"
|
||||
if not (s_trim(got) == s_trim(want)) { bad2(lbl, `said [{s_trim(got)}]`); return }
|
||||
let base = `{tmp_dir()}/deps-base.txt`
|
||||
if not shq(`bin/ludic deps {p} --baseline {base} > /dev/null`) { bad2(lbl, "--baseline failed"); return }
|
||||
if not shq(`bin/ludic deps {p} --check {base} > /dev/null`) { bad2(lbl, "--check failed against its own baseline"); return }
|
||||
write_file(base, "dependencies 1\nlargest_cycle 2\ncross_writes 1\nglobals_written_from_outside 1\n")
|
||||
if shq(`bin/ludic deps {p} --check {base} > /dev/null`) { bad2(lbl, "--check passed with more dependencies than the baseline"); return }
|
||||
# 0.R2: the widest function is a ratchet too
|
||||
write_file(base, "dependencies 2\nlargest_cycle 2\ncross_writes 1\nglobals_written_from_outside 1\nwidest_function 0\n")
|
||||
if shq(`bin/ludic deps {p} --check {base} > {tmp_dir()}/wide.out`) { bad2(lbl, "--check passed with a wider function than the baseline"); return }
|
||||
if not shq(`grep -q 'widest_function 1 (baseline 0) WORSE' {tmp_dir()}/wide.out`) { bad2(lbl, capture(`cat {tmp_dir()}/wide.out`)); return }
|
||||
let pk = capture(`bin/ludic deps examples/actions/pack.ludic 2>&1`)
|
||||
if not s_contains(pk, "the widest function: entry (examples/actions/pack.ludic:29), 2 states") { bad2(lbl, `widest: [{s_trim(pk)}]`); return }
|
||||
if not shq(`bin/ludic deps {p} --dot | grep -q '"a" -> "b"'`) { bad2(lbl, "--dot has no a -> b edge"); return }
|
||||
if not shq(`bin/ludic deps {p} --writes | grep -q 'b b_count a examples/modules/tangle/a/index.ludic:4'`) { bad2(lbl, "--writes misses a's write to b_count"); return }
|
||||
if not shq(`bin/ludic deps {p} --writes | grep -q 'warning: b b_rec a examples/modules/tangle/a/index.ludic:12 through the local r'`) { bad2(lbl, "--writes misses the write through a local"); return }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue