Skip to content

Commit 249c999

Browse files
feat(dev): add profiler to get render time data
## Details Add profiler module that wraps the main `refresh` method where all rendering logic lives. This only tracks info if the `profile` field has been set to true, which should only be the case for myself but I guess others can if they would like, could help debug performance issues in the future. Tracks runtime in milliseconds of the various different kind of possible refreshes, i.e. movement vs full parse at a buffer level. Add an api called stats that processes the runtime data and outputs some basic info (min, max, mean) to `stats.json` in whatever directory I'm currently in. May add a benchmark suite to use this in the future, currently it is to help me get a baseline of where we're at. Other unrelated change to types to define classes directly on tables rather than defining a class and adding it to a table.
1 parent 51eec4e commit 249c999

File tree

15 files changed

+136
-27
lines changed

15 files changed

+136
-27
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
*.cast
22
*.gif
3+
*.json
34
medium.md
45
large.md
56
test.md

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ Some of the more useful fields are discussed further down.
114114
require('render-markdown').setup({
115115
-- Whether Markdown should be rendered by default or not
116116
enabled = true,
117+
-- Whether to track performance metrics, should only be used for development
118+
profile = false,
117119
-- Maximum file size (in MB) that this plugin will attempt to render
118120
-- Any file larger than this will effectively be ignored
119121
max_file_size = 1.5,

doc/render-markdown.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ Full Default Configuration ~
144144
require('render-markdown').setup({
145145
-- Whether Markdown should be rendered by default or not
146146
enabled = true,
147+
-- Whether to track performance metrics, should only be used for development
148+
profile = false,
147149
-- Maximum file size (in MB) that this plugin will attempt to render
148150
-- Any file larger than this will effectively be ignored
149151
max_file_size = 1.5,

lua/render-markdown/api.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local manager = require('render-markdown.manager')
2+
local profiler = require('render-markdown.profiler')
23
local state = require('render-markdown.state')
34

45
---@class render.md.Api
@@ -16,4 +17,8 @@ function M.toggle()
1617
manager.set_all(not state.enabled)
1718
end
1819

20+
function M.stats()
21+
profiler.dump_stats()
22+
end
23+
1924
return M

lua/render-markdown/colors.lua

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
---@class render.md.ColorCache
2-
---@field highlights string[]
3-
4-
---@type render.md.ColorCache
52
local cache = {
3+
---@type string[]
64
highlights = {},
75
}
86

lua/render-markdown/handler/latex.lua

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ local state = require('render-markdown.state')
33
local ts = require('render-markdown.ts')
44

55
---@class render.md.LatexCache
6-
---@field expressions table<string, string[]>
7-
8-
---@type render.md.LatexCache
96
local cache = {
7+
---@type table<string, string[]>
108
expressions = {},
119
}
1210

lua/render-markdown/init.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ local M = {}
107107

108108
---@class render.md.UserConfig
109109
---@field public enabled? boolean
110+
---@field public profile? boolean
110111
---@field public max_file_size? number
111112
---@field public markdown_query? string
112113
---@field public markdown_quote_query? string
@@ -136,6 +137,8 @@ local M = {}
136137
M.default_config = {
137138
-- Whether Markdown should be rendered by default or not
138139
enabled = true,
140+
-- Whether to track performance metrics, should only be used for development
141+
profile = false,
139142
-- Maximum file size (in MB) that this plugin will attempt to render
140143
-- Any file larger than this will effectively be ignored
141144
max_file_size = 1.5,

lua/render-markdown/logger.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ end
2020
---@field message string
2121

2222
---@class render.md.Log
23-
---@field entries render.md.LogEntry[]
2423
local log = {
24+
---@type render.md.LogEntry[]
2525
entries = {},
2626
}
2727

lua/render-markdown/manager.lua

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ local ui = require('render-markdown.ui')
33
local util = require('render-markdown.util')
44

55
---@class render.md.manager.Data
6-
---@field buffers integer[]
7-
8-
---@type render.md.manager.Data
96
local data = {
7+
---@type integer[]
108
buffers = {},
119
}
1210

lua/render-markdown/profiler.lua

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
local util = require('render-markdown.util')
2+
3+
---@class render.md.OutputResultStat
4+
---@field n integer
5+
---@field min number
6+
---@field max number
7+
---@field sum number
8+
---@field mean number
9+
10+
---@class render.md.OutputStat
11+
---@field path string
12+
---@field size number
13+
---@field results table<string, render.md.OutputResultStat>
14+
15+
---buffer -> result_state -> times
16+
---@type table<integer, table<string, number[]>>
17+
local stats = {}
18+
19+
---@class render.md.Profiler
20+
local M = {}
21+
22+
---@param buf integer
23+
---@param f fun(): string
24+
function M.profile(buf, f)
25+
local start_ns = vim.uv.hrtime()
26+
local result = f()
27+
local time = (vim.uv.hrtime() - start_ns) / 1e+6
28+
29+
if stats[buf] == nil then
30+
stats[buf] = {}
31+
end
32+
local buf_stats = stats[buf]
33+
if buf_stats[result] == nil then
34+
buf_stats[result] = {}
35+
end
36+
local times = buf_stats[result]
37+
table.insert(times, time)
38+
end
39+
40+
function M.dump_stats()
41+
local output_stats = {}
42+
for buf, buf_stats in pairs(stats) do
43+
local results = {}
44+
for name, times in pairs(buf_stats) do
45+
results[name] = M.compute_stats(times)
46+
end
47+
---@type render.md.OutputStat
48+
local output_stat = {
49+
path = util.file_path(buf),
50+
size = util.file_size_mb(buf),
51+
results = results,
52+
}
53+
table.insert(output_stats, output_stat)
54+
end
55+
if #output_stats > 0 then
56+
local file = assert(io.open('stats.json', 'w'))
57+
file:write(vim.fn.json_encode(output_stats))
58+
file:close()
59+
end
60+
end
61+
62+
---@private
63+
---@param times number[]
64+
---@return render.md.OutputResultStat
65+
function M.compute_stats(times)
66+
local min = times[1]
67+
local max = 0
68+
local sum = 0
69+
for _, time in ipairs(times) do
70+
min = math.min(min, time)
71+
max = math.max(max, time)
72+
sum = sum + time
73+
end
74+
---@type render.md.OutputResultStat
75+
return {
76+
n = #times,
77+
min = min,
78+
max = max,
79+
sum = sum,
80+
mean = sum / #times,
81+
}
82+
end
83+
84+
return M

0 commit comments

Comments
 (0)