blob: d87315401ce8a19d57cd04b521af04a9dac7abdb [file] [log] [blame]
Aliaksei Budaveife8508e2025-04-19 11:35:02 +02001vim9script
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
16def 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
93enddef
94
95def 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
132enddef
133
134def 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
158enddef
159
160if empty(system('git status --porcelain=v1'))
161 ProcessIndentPluginCmdlineArgs()
162endif
163
164quitall
165
166# vim:fdm=syntax:sw=2:ts=8:noet:nosta: