| -- A script that compares a set of equivalent cmdstream captures from |
| -- various generations, looking for equivalencies between registers. |
| -- |
| -- This would be run across a group of similar tests for various |
| -- generations, for example: |
| -- |
| -- cffdump --script scripts/analyze.lua a320/quad-flat-*.rd a420/quad-flat-*.rd |
| -- |
| -- This is done by comparing unique register values. Ie. for each |
| -- generation, find the set of registers that have different values |
| -- between equivalent draw calls. |
| |
| local posix = require "posix" |
| |
| io.write("Analyzing Data...\n") |
| |
| -- results - table structure: |
| -- * [gpuname] - gpu |
| -- * tests |
| -- * [testname] - current test |
| -- * draws |
| -- * [1..n] - the draws |
| -- * primtype - the primitive type |
| -- * regs - table of values for draw |
| -- * [regbase] - regval |
| -- * regvals - table of unique values across all draws |
| -- * [regbase] |
| -- * [regval] - list of test names |
| -- * [1..n] - testname "." didx |
| local results = {} |
| |
| local test = nil |
| local gpuname = nil |
| local testname = nil |
| |
| |
| -- srsly, no sparse table size() op? |
| function tblsz(tbl) |
| local n = 0; |
| for k,v in pairs(tbl) do |
| n = n + 1 |
| end |
| return n |
| end |
| |
| |
| function start_cmdstream(name) |
| testname = posix.basename(name) |
| gpuname = posix.basename(posix.dirname(name)) |
| --io.write("START: gpuname=" .. gpuname .. ", testname=" .. testname .. "\n"); |
| local gpu = results[gpuname] |
| if gpu == nil then |
| gpu = {["tests"] = {}, ["regvals"] = {}} |
| results[gpuname] = gpu |
| end |
| test = {["draws"] = {}} |
| gpu["tests"][testname] = test |
| end |
| |
| function draw(primtype, nindx) |
| -- RECTLIST is only used internally.. we want to ignore it for |
| -- now, although it could potentially be interesting to track |
| -- these separately (separating clear/restore/resolve) just to |
| -- figure out which registers are used for which.. |
| if primtype == "DI_PT_RECTLIST" then |
| return |
| end |
| local regtbl = {} |
| local draw = {["primtype"] = primtype, ["regs"] = regtbl} |
| local didx = tblsz(test["draws"]) |
| |
| test["draws"][didx] = draw |
| |
| -- populate current regs. For now just consider ones that have |
| -- been written.. maybe we need to make that configurable in |
| -- case it filters out too many registers. |
| for regbase=0,0xffff do |
| if regs.written(regbase) ~= 0 then |
| local regval = regs.val(regbase) |
| |
| -- track reg vals per draw: |
| regtbl[regbase] = regval |
| |
| -- also track which reg vals appear in which tests: |
| local uniq_regvals = results[gpuname]["regvals"][regbase] |
| if uniq_regvals == nil then |
| uniq_regvals = {} |
| results[gpuname]["regvals"][regbase] = uniq_regvals; |
| end |
| local drawlist = uniq_regvals[regval] |
| if drawlist == nil then |
| drawlist = {} |
| uniq_regvals[regval] = drawlist |
| end |
| table.insert(drawlist, testname .. "." .. didx) |
| end |
| end |
| |
| -- TODO maybe we want to whitelist a few well known regs, for the |
| -- convenience of the code that runs at the end to analyze the data? |
| -- TODO also would be useful to somehow capture CP_SET_BIN.. |
| |
| end |
| |
| function end_cmdstream() |
| test = nil |
| gpuname = nil |
| testname = nil |
| end |
| |
| function print_draws(gpuname, gpu) |
| io.write(" " .. gpuname .. "\n") |
| for testname,test in pairs(gpu["tests"]) do |
| io.write(" " .. testname .. ", draws=" .. #test["draws"] .. "\n") |
| for didx,draw in pairs(test["draws"]) do |
| io.write(" " .. didx .. ": " .. draw["primtype"] .. "\n") |
| end |
| end |
| end |
| |
| -- sort and concat a list of draw names to form a key which can be |
| -- compared to other drawlists to check for equality |
| -- TODO maybe we instead want a scheme that allows for some fuzzyness |
| -- in the matching?? |
| function drawlistname(drawlist) |
| local name = nil |
| for idx,draw in pairs(drawlist) do |
| if name == nil then |
| name = draw |
| else |
| name = name .. ":" .. draw |
| end |
| end |
| return name |
| end |
| |
| local rnntbl = {} |
| |
| function dumpmatches(name) |
| for gpuname,gpu in pairs(results) do |
| local r = rnntbl[gpuname] |
| if r == nil then |
| io.write("loading rnn database: \n" .. gpuname) |
| r = rnn.init(gpuname) |
| rnntbl[gpuname] = r |
| end |
| for regbase,regvals in pairs(gpu["regvals"]) do |
| for regval,drawlist in pairs(regvals) do |
| local name2 = drawlistname(drawlist) |
| if name == name2 then |
| io.write(string.format(" %s:%s:\t%08x %s\n", |
| gpuname, rnn.regname(r, regbase), |
| regval, rnn.regval(r, regbase, regval))) |
| end |
| end |
| end |
| end |
| end |
| |
| function finish() |
| -- drawlistnames that we've already dumped: |
| local dumped = {} |
| |
| for gpuname,gpu in pairs(results) do |
| -- print_draws(gpuname, gpu) |
| for regbase,regvals in pairs(gpu["regvals"]) do |
| for regval,drawlist in pairs(regvals) do |
| local name = drawlistname(drawlist) |
| if dumped[name] == nil then |
| io.write("\n" .. name .. ":\n") |
| dumpmatches(name) |
| dumped[name] = 1 |
| end |
| end |
| end |
| end |
| end |
| |