summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--player/lua/stats.lua207
1 files changed, 138 insertions, 69 deletions
diff --git a/player/lua/stats.lua b/player/lua/stats.lua
index 000708c876..1b3a61d739 100644
--- a/player/lua/stats.lua
+++ b/player/lua/stats.lua
@@ -24,9 +24,12 @@ local o = {
debug = false,
-- Graph options and style
- plot_graphs = true,
+ plot_perfdata = true,
+ plot_vsync_ratio = true,
+ plot_vsync_jitter = true,
skip_frames = 5,
global_max = true,
+ flush_graph_data = true, -- clear data buffers when toggling
plot_bg_border_color = "0000FF",
plot_bg_color = "262626",
plot_color = "FFFFFF",
@@ -65,12 +68,7 @@ local o = {
options.read_options(o)
local format = string.format
--- Buffer for the "last" value of performance data for render/present/upload
-local plast = {{0}, {0}, {0}}
--- Position in buffer
-local ppos = 1
--- Length of buffer
-local plen = 50
+local max = math.max
-- Function used to record performance data
local recorder = nil
-- Timer used for toggling
@@ -79,6 +77,18 @@ local timer = nil
local ass_start = mp.get_property_osd("osd-ass-cc/0")
local ass_stop = mp.get_property_osd("osd-ass-cc/1")
+-- Ring buffers for the values used to construct a graph.
+-- .pos denotes the current position, .len the buffer length
+-- .max is the max value in the corresponding buffer as computed in record_data().
+-- `plast_buf` is a table of buffers for the "last" value of performance data
+-- for render/present/upload.
+local plast_buf, vsratio_buf, vsjitter_buf
+local function init_buffers()
+ plast_buf = {{0, max = 0}, {0, max = 0}, {0, max = 0}, pos = 1, len = 50}
+ vsratio_buf = {0, pos = 1, len = 50, max = 0}
+ vsjitter_buf = {0, pos = 1, len = 50, max = 0}
+end
+
local function set_ASS(b)
if not o.ass_formatting then
@@ -138,6 +148,7 @@ local function has_ansi()
return true
end
+
-- Generate a graph from the given values.
-- Returns an ASS formatted vector drawing as string.
--
@@ -149,8 +160,8 @@ end
-- values to a range of 0 to `v_max`.
-- scale : A value that will be multiplied with all data values.
local function generate_graph(values, i, len, v_max, scale)
- -- check if at least one value was recorded yet (we assume lua-style 1-indexing)
- if i < 1 then
+ -- Check if at least one value exists
+ if not values[i] then
return ""
end
@@ -180,6 +191,43 @@ local function generate_graph(values, i, len, v_max, scale)
end
+-- Format and append a property.
+-- A property whose value is either `nil` or empty (hereafter called "invalid")
+-- is skipped and not appended.
+-- Returns `false` in case nothing was appended, otherwise `true`.
+--
+-- s : Table containing strings.
+-- prop : The property to query and format (based on its OSD representation).
+-- attr : Optional table to overwrite certain (formatting) attributes for
+-- this property.
+-- exclude: Optional table containing keys which are considered invalid values
+-- for this property. Specifying this will replace empty string as
+-- default invalid value (nil is always invalid).
+local function append_property(s, prop, attr, excluded)
+ excluded = excluded or {[""] = true}
+ local ret = mp.get_property_osd(prop)
+ if not ret or excluded[ret] then
+ if o.debug then
+ print("No value for property: " .. prop)
+ end
+ return false
+ end
+
+ attr.prefix_sep = attr.prefix_sep or o.prefix_sep
+ attr.indent = attr.indent or o.indent
+ attr.nl = attr.nl or o.nl
+ attr.suffix = attr.suffix or ""
+ attr.prefix = attr.prefix or ""
+ attr.no_prefix_markup = attr.no_prefix_markup or false
+ attr.prefix = attr.no_prefix_markup and attr.prefix or b(attr.prefix)
+ ret = attr.no_value and "" or ret
+
+ s[#s+1] = format("%s%s%s%s%s%s", attr.nl, attr.indent,
+ attr.prefix, attr.prefix_sep, no_ASS(ret), attr.suffix)
+ return true
+end
+
+
local function append_perfdata(s)
local vo_p = mp.get_property_native("vo-performance")
if not vo_p then
@@ -194,7 +242,7 @@ local function append_perfdata(s)
local avg_s = vo_p["render-avg"] + vo_p["present-avg"] + vo_p["upload-avg"]
local peak_s = vo_p["render-peak"] + vo_p["present-peak"] + vo_p["upload-peak"]
- -- highlight i with a red border when t exceeds the time for one frame
+ -- Highlight i with a red border when t exceeds the time for one frame
-- or yellow when it exceeds a given threshold
local function hl(i, t)
if o.timing_warning and target_fps > 0 then
@@ -212,21 +260,17 @@ local function append_perfdata(s)
local rsuffix, psuffix, usuffix
- if o.plot_graphs and o.ass_formatting and timer:is_enabled() then
- local max = {1, 1, 1}
- for e = 1, plen do
- if plast[1][e] and plast[1][e] > max[1] then max[1] = plast[1][e] end
- if plast[2][e] and plast[2][e] > max[2] then max[2] = plast[2][e] end
- if plast[3][e] and plast[3][e] > max[3] then max[3] = plast[3][e] end
- end
+ -- Plot graphs when configured and we are toggled
+ if o.plot_perfdata and o.ass_formatting and timer:is_enabled() then
+ local pmax = {plast_buf[1].max, plast_buf[2].max, plast_buf[3].max}
if o.global_max then
- max[1] = math.max(max[1], max[2], max[3])
- max[2], max[3] = max[1], max[1]
+ pmax[1] = max(pmax[1], pmax[2], pmax[3])
+ pmax[2], pmax[3] = pmax[1], pmax[1]
end
- rsuffix = generate_graph(plast[1], ppos, plen, max[1], 0.8)
- psuffix = generate_graph(plast[2], ppos, plen, max[2], 0.8)
- usuffix = generate_graph(plast[3], ppos, plen, max[3], 0.8)
+ rsuffix = generate_graph(plast_buf[1], plast_buf.pos, plast_buf.len, pmax[1], 0.8)
+ psuffix = generate_graph(plast_buf[2], plast_buf.pos, plast_buf.len, pmax[2], 0.8)
+ usuffix = generate_graph(plast_buf[3], plast_buf.pos, plast_buf.len, pmax[3], 0.8)
s[#s+1] = format("%s%s%s%s{\\fs%s}%s%s%s{\\fs%s}", o.nl, o.indent,
b("Frame Timings:"), o.prefix_sep, o.font_size * 0.66,
@@ -260,40 +304,42 @@ local function append_perfdata(s)
end
--- Format and append a property.
--- A property whose value is either `nil` or empty (hereafter called "invalid")
--- is skipped and not appended.
--- Returns `false` in case nothing was appended, otherwise `true`.
---
--- s : Table containing strings.
--- prop : The property to query and format (based on its OSD representation).
--- attr : Optional table to overwrite certain (formatting) attributes for
--- this property.
--- exclude: Optional table containing keys which are considered invalid values
--- for this property. Specifying this will replace empty string as
--- default invalid value (nil is always invalid).
-local function append_property(s, prop, attr, excluded)
- excluded = excluded or {[""] = true}
- local ret = mp.get_property_osd(prop)
- if not ret or excluded[ret] then
- if o.debug then
- print("No value for property: " .. prop)
- end
- return false
+function append_display_sync(s)
+ if not mp.get_property_bool("display-sync-active", false) then
+ return
end
- attr.prefix_sep = attr.prefix_sep or o.prefix_sep
- attr.indent = attr.indent or o.indent
- attr.nl = attr.nl or o.nl
- attr.suffix = attr.suffix or ""
- attr.prefix = attr.prefix or ""
- attr.no_prefix_markup = attr.no_prefix_markup or false
- attr.prefix = attr.no_prefix_markup and attr.prefix or b(attr.prefix)
- ret = attr.no_value and "" or ret
+ local vspeed = append_property(s, "video-speed-correction", {prefix="DS:"})
+ if vspeed then
+ append_property(s, "audio-speed-correction",
+ {prefix="/", nl="", indent=" ", prefix_sep=" ", no_prefix_markup=true})
+ else
+ append_property(s, "audio-speed-correction",
+ {prefix="DS:" .. o.prefix_sep .. " - / ", prefix_sep=""})
+ end
- s[#s+1] = format("%s%s%s%s%s%s", attr.nl, attr.indent,
- attr.prefix, attr.prefix_sep, no_ASS(ret), attr.suffix)
- return true
+ -- Since no graph is needed we can print ratio/jitter on the same line and save some space
+ if not (o.plot_vsync_ratio or o.plot_vsync_jitter) then
+ local vratio = append_property(s, "vsync-ratio", {prefix="VSync Ratio:"})
+ append_property(s, "vsync-jitter", {prefix="VSync Jitter:", nl=vratio and "" or o.nl})
+ return
+ end
+
+ -- As we potentially need to plot some graphs we print jitter and ratio on
+ -- their own lines so we have the same layout when toggled (= drawing graphs)
+ local ratio_graph = ""
+ local jitter_graph = ""
+ if o.ass_formatting and timer:is_enabled() then
+ if o.plot_vsync_ratio then
+ ratio_graph = generate_graph(vsratio_buf, vsratio_buf.pos, vsratio_buf.len, vsratio_buf.max, 0.8)
+ end
+ if o.plot_vsync_jitter then
+ jitter_graph = generate_graph(vsjitter_buf, vsjitter_buf.pos, vsjitter_buf.len, vsjitter_buf.max, 0.8)
+ end
+ end
+
+ append_property(s, "vsync-ratio", {prefix="VSync Ratio:", suffix=o.prefix_sep .. ratio_graph})
+ append_property(s, "vsync-jitter", {prefix="VSync Jitter:", suffix=o.prefix_sep .. jitter_graph})
end
@@ -351,11 +397,8 @@ local function add_video(s)
append_property(s, "estimated-vf-fps",
{prefix="FPS:", suffix=" (estimated)"})
end
- if append_property(s, "video-speed-correction", {prefix="DS:"}, {["+0.00000%"]=true}) then
- append_property(s, "audio-speed-correction",
- {prefix="/", nl="", indent=" ", prefix_sep=" ", no_prefix_markup=true})
- end
+ append_display_sync(s)
append_perfdata(s)
if append_property(s, "video-params/w", {prefix="Native Resolution:"}) then
@@ -429,8 +472,9 @@ local function print_stats(duration)
end
-local function record_perfdata(skip)
- skip = math.max(skip, 0)
+local function record_data(skip)
+ init_buffers()
+ skip = max(skip, 0)
local i = skip
return function()
if i < skip then
@@ -440,28 +484,53 @@ local function record_perfdata(skip)
i = 0
end
- local vo_p = mp.get_property_native("vo-performance")
- if not vo_p then
- return
+ if o.plot_perfdata then
+ local vo_p = mp.get_property_native("vo-performance")
+ if vo_p then
+ plast_buf.pos = (plast_buf.pos % plast_buf.len) + 1
+ plast_buf[1][plast_buf.pos] = vo_p["render-last"]
+ plast_buf[1].max = max(plast_buf[1].max, plast_buf[1][plast_buf.pos])
+ plast_buf[2][plast_buf.pos] = vo_p["present-last"]
+ plast_buf[2].max = max(plast_buf[2].max, plast_buf[2][plast_buf.pos])
+ plast_buf[3][plast_buf.pos] = vo_p["upload-last"]
+ plast_buf[3].max = max(plast_buf[3].max, plast_buf[3][plast_buf.pos])
+ end
+ end
+
+ if o.plot_vsync_jitter then
+ local r = mp.get_property_number("vsync-jitter", nil)
+ if r then
+ vsjitter_buf.pos = (vsjitter_buf.pos % vsjitter_buf.len) + 1
+ vsjitter_buf[vsjitter_buf.pos] = r
+ vsjitter_buf.max = max(vsjitter_buf.max, r)
+ end
+ end
+
+ if o.plot_vsync_ratio then
+ local r = mp.get_property_number("vsync-ratio", nil)
+ if r then
+ vsratio_buf.pos = (vsratio_buf.pos % vsratio_buf.len) + 1
+ vsratio_buf[vsratio_buf.pos] = r
+ vsratio_buf.max = max(vsratio_buf.max, r)
+ end
end
- ppos = (ppos % plen) + 1
- plast[1][ppos] = vo_p["render-last"]
- plast[2][ppos] = vo_p["present-last"]
- plast[3][ppos] = vo_p["upload-last"]
end
end
local function toggle_stats()
+ -- Disable
if timer:is_enabled() then
- if o.plot_graphs then
+ if recorder then
mp.unregister_event(recorder)
+ recorder = nil
end
timer:kill()
mp.osd_message("", 0)
+ -- Enable
else
- if o.plot_graphs then
- recorder = record_perfdata(o.skip_frames)
+ if o.plot_perfdata or o.plot_vsync_jitter or o.plot_vsync_ratio then
+ recorder = record_data(o.skip_frames)
mp.register_event("tick", recorder)
end
timer:resume()