-- 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