Aliaksei Budavei | fe8508e | 2025-04-19 11:35:02 +0200 | [diff] [blame] | 1 | vim9script |
| 2 | |
| 3 | # Whenever indent plugins contain "search*()" lines explicitly annotated with |
| 4 | # "VIM_INDENT_TEST_TRACE_(START|END)" comment markers; this script can then be |
| 5 | # used as shown to measure and record elapsed time for such decorated calls. |
| 6 | # |
| 7 | # Usage: |
| 8 | # cd runtime/indent |
| 9 | # vim -u NONE -S testdir/tools/tracer.vim \ |
| 10 | # html.vim javascript.vim \ |
| 11 | # ../autoload/python.vim ../autoload/dist/vimindent.vim |
| 12 | # git diff |
| 13 | # make clean test |
| 14 | # vim testdir/00-TRACE_LOG.fail |
| 15 | |
| 16 | def GenerateTempletForTracing(fname: string, vname: string): list<string> |
| 17 | #### ONLY INSTRUMENT "search*()"es FOR INDENT TESTS. |
| 18 | |
| 19 | const templet: list<string> =<< trim eval END |
| 20 | |
| 21 | if getcwd() =~# '\<runtime/indent$' |
| 22 | |
| 23 | def! g:IndentTestTrace(id: string, start: list<number>, result: any): any |
| 24 | const end: list<number> = reltime(start) |
| 25 | |
| 26 | if !has_key(g:indent_test_trace_times, id) |
| 27 | g:indent_test_trace_times[id] = [] |
| 28 | endif |
| 29 | |
| 30 | g:indent_test_trace_times[id] |
| 31 | ->add(reltimefloat(end)) |
| 32 | return result |
| 33 | enddef |
| 34 | |
| 35 | def! g:IndentTestInitTracing() |
| 36 | # Possibly use a later "{fname}", cf. ":runtime indent/foo.vim". |
| 37 | autocmd_add([{{ |
| 38 | replace: true, |
| 39 | group: 'tracing', |
| 40 | event: 'QuitPre', |
| 41 | bufnr: bufnr(), |
| 42 | cmd: 'g:IndentTestWriteTraceTimes()', |
| 43 | }}]) |
| 44 | g:indent_test_trace_times = {{}} |
| 45 | enddef |
| 46 | |
| 47 | def! g:IndentTestWriteTraceTimes() |
| 48 | # Anticipate usage by multiple languages. |
| 49 | const token: string = printf('%02x', (rand() % 26)) |
| 50 | writefile(['" {fname}:', |
| 51 | "let {vname}_" .. token .. " = " .. string(g:indent_test_trace_times), |
| 52 | "let {vname}_" .. token .. "_summary = " .. string(g:indent_test_trace_times |
| 53 | ->items() |
| 54 | ->reduce((outer: dict<dict<any>>, times: list<any>) => |
| 55 | extend({{[times[0]]: times[1] |
| 56 | ->copy() |
| 57 | ->reduce((inner: dict<any>, v: float) => |
| 58 | extend({{ |
| 59 | min: inner.min < v ? inner.min : v, |
| 60 | max: inner.max > v ? inner.max : v, |
| 61 | sum: (inner.sum + v), |
| 62 | avg: ((inner.sum + v) / inner.count), |
| 63 | }}, |
| 64 | inner, |
| 65 | "keep"), |
| 66 | {{ |
| 67 | min: v:numbermax - 0.0, |
| 68 | max: v:numbermin + 0.0, |
| 69 | sum: 0.0, |
| 70 | avg: 0.0, |
| 71 | count: len(times[1]), |
| 72 | }})}}, |
| 73 | outer), |
| 74 | {{}}))], |
| 75 | (!empty($VIM_INDENT_TEST_LOG) && filewritable($VIM_INDENT_TEST_LOG)) |
| 76 | ? $VIM_INDENT_TEST_LOG |
| 77 | : "testdir/00-TRACE_LOG.fail", |
| 78 | "a") |
| 79 | enddef |
| 80 | |
| 81 | call g:IndentTestInitTracing() |
| 82 | |
| 83 | else |
| 84 | |
| 85 | def! g:IndentTestTrace(_: string, _: list<number>, result: any): any |
| 86 | return result |
| 87 | enddef |
| 88 | |
| 89 | endif |
| 90 | |
| 91 | END |
| 92 | return templet |
| 93 | enddef |
| 94 | |
| 95 | def InstrumentMarkedEntry(): bool |
| 96 | const marker_start: string = 'VIM_INDENT_TEST_TRACE_START' |
| 97 | const start: number = search('\C\<' .. marker_start .. '\>', 'ceW') |
| 98 | |
| 99 | if start == 0 |
| 100 | return false |
| 101 | endif |
| 102 | |
| 103 | const marker_end: string = 'VIM_INDENT_TEST_TRACE_END' |
| 104 | const end: number = search('\C\<' .. marker_end .. '\>', 'ceW') |
| 105 | |
| 106 | if end == 0 |
| 107 | return false |
| 108 | endif |
| 109 | |
| 110 | const tracee: list<string> = matchlist( |
| 111 | getline(start + 1), |
| 112 | '\(^.\+\)\(\<search\%(pair\)\=\%(pos\)\=\s*(.*$\)') |
| 113 | |
| 114 | if empty(get(tracee, 1, '')) || empty(get(tracee, 2, '')) |
| 115 | return false |
| 116 | endif |
| 117 | |
| 118 | const end_line: string = getline(end) |
| 119 | const tracer: string = printf('%sg:IndentTestTrace("%s", reltime(), %s', |
| 120 | tracee[1], |
| 121 | strpart(end_line, (stridx(end_line, marker_end) + strlen(marker_end) + 1)), |
| 122 | tracee[2]) |
| 123 | |
| 124 | if (end - start) > 1 |
| 125 | setline((start + 1), tracer) |
| 126 | setline((end - 1), getline(end - 1) .. ')') |
| 127 | else |
| 128 | setline((start + 1), tracer .. ')') |
| 129 | endif |
| 130 | |
| 131 | return true |
| 132 | enddef |
| 133 | |
| 134 | def ProcessIndentPluginCmdlineArgs() |
| 135 | const names: list<string> = range(char2nr('a'), char2nr('z')) |
| 136 | ->map((_: number, n: number) => nr2char(n, true)) |
| 137 | var entries: number = 0 |
| 138 | var next: number = 0 |
| 139 | |
| 140 | for fname: string in argv(-1) |
| 141 | if filereadable(fname) && filewritable(fname) |
| 142 | execute 'new ' .. fname |
| 143 | call cursor(1, 1) |
| 144 | |
| 145 | while InstrumentMarkedEntry() |
| 146 | entries += 1 |
| 147 | endwhile |
| 148 | |
| 149 | if entries > 0 |
| 150 | append(1, GenerateTempletForTracing(fname, get(names, next, names[-1]))) |
| 151 | wq |
| 152 | endif |
| 153 | |
| 154 | entries = 0 |
| 155 | next += 1 |
| 156 | endif |
| 157 | endfor |
| 158 | enddef |
| 159 | |
| 160 | if empty(system('git status --porcelain=v1')) |
| 161 | ProcessIndentPluginCmdlineArgs() |
| 162 | endif |
| 163 | |
| 164 | quitall |
| 165 | |
| 166 | # vim:fdm=syntax:sw=2:ts=8:noet:nosta: |