1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
if not modules then modules = { } end modules ['trac-inf'] = {
version = 1.001,
comment = "companion to trac-inf.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-- As we want to protect the global tables, we no longer store the timing
-- in the tables themselves but in a hidden timers table so that we don't
-- get warnings about assignments. This is more efficient than using rawset
-- and rawget.
local format, lower = string.format, string.lower
local concat = table.concat
local clock = os.gettimeofday or os.clock -- should go in environment
local write_nl = texio and texio.write_nl or print
statistics = statistics or { }
local statistics = statistics
statistics.enable = true
statistics.threshold = 0.01
local statusinfo, n, registered, timers = { }, 0, { }, { }
table.setmetatableindex(timers,function(t,k)
local v = { timing = 0, loadtime = 0 }
t[k] = v
return v
end)
local function hastiming(instance)
return instance and timers[instance]
end
local function resettiming(instance)
timers[instance or "notimer"] = { timing = 0, loadtime = 0 }
end
local function starttiming(instance)
local timer = timers[instance or "notimer"]
local it = timer.timing or 0
if it == 0 then
timer.starttime = clock()
if not timer.loadtime then
timer.loadtime = 0
end
end
timer.timing = it + 1
end
local function stoptiming(instance, report)
local timer = timers[instance or "notimer"]
local it = timer.timing
if it > 1 then
timer.timing = it - 1
else
local starttime = timer.starttime
if starttime then
local stoptime = clock()
local loadtime = stoptime - starttime
timer.stoptime = stoptime
timer.loadtime = timer.loadtime + loadtime
if report then
statistics.report("load time %0.3f",loadtime)
end
timer.timing = 0
return loadtime
end
end
return 0
end
local function elapsedtime(instance)
local timer = timers[instance or "notimer"]
return format("%0.3f",timer and timer.loadtime or 0)
end
local function elapsedindeed(instance)
local timer = timers[instance or "notimer"]
return (timer and timer.loadtime or 0) > statistics.threshold
end
local function elapsedseconds(instance,rest) -- returns nil if 0 seconds
if elapsedindeed(instance) then
return format("%s seconds %s", elapsedtime(instance),rest or "")
end
end
statistics.hastiming = hastiming
statistics.resettiming = resettiming
statistics.starttiming = starttiming
statistics.stoptiming = stoptiming
statistics.elapsedtime = elapsedtime
statistics.elapsedindeed = elapsedindeed
statistics.elapsedseconds = elapsedseconds
-- general function .. we might split this module
function statistics.register(tag,fnc)
if statistics.enable and type(fnc) == "function" then
local rt = registered[tag] or (#statusinfo + 1)
statusinfo[rt] = { tag, fnc }
registered[tag] = rt
if #tag > n then n = #tag end
end
end
function statistics.show(reporter)
if statistics.enable then
if not reporter then reporter = function(tag,data,n) write_nl(tag .. " " .. data) end end
-- this code will move
local register = statistics.register
register("luatex banner", function()
return lower(status.banner)
end)
register("control sequences", function()
return format("%s of %s + %s", status.cs_count, status.hash_size,status.hash_extra)
end)
register("callbacks", function()
local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
return format("%s direct, %s indirect, %s total", total-indirect, indirect, total)
end)
if jit then
local status = { jit.status() }
if status[1] then
register("luajit status", function()
return concat(status," ",2)
end)
end
end
collectgarbage("collect")
register("current memory usage", statistics.memused)
register("runtime",statistics.runtime)
for i=1,#statusinfo do
local s = statusinfo[i]
local r = s[2]()
if r then
reporter(s[1],r,n)
end
end
write_nl("") -- final newline
statistics.enable = false
end
end
local template, report_statistics, nn = nil, nil, 0 -- we only calcute it once
function statistics.showjobstat(tag,data,n)
if not logs then
-- sorry
elseif type(data) == "table" then
for i=1,#data do
statistics.showjobstat(tag,data[i],n)
end
else
if not template or n > nn then
template, n = format("%%-%ss - %%s",n), nn
report_statistics = logs.reporter("mkiv lua stats")
end
report_statistics(format(template,tag,data))
end
end
function statistics.memused() -- no math.round yet -)
local round = math.round or math.floor
return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
end
starttiming(statistics)
function statistics.formatruntime(runtime) -- indirect so it can be overloaded and
return format("%s seconds", runtime) -- indeed that happens in cure-uti.lua
end
function statistics.runtime()
stoptiming(statistics)
return statistics.formatruntime(elapsedtime(statistics))
end
function statistics.timed(action,report)
report = report or logs.reporter("system")
starttiming("run")
action()
stoptiming("run")
report("total runtime: %s",elapsedtime("run"))
end
-- where, not really the best spot for this:
commands = commands or { }
function commands.resettimer(name)
resettiming(name or "whatever")
starttiming(name or "whatever")
end
function commands.elapsedtime(name)
stoptiming(name or "whatever")
context(elapsedtime(name or "whatever"))
end
|