1-- A script that compares a set of equivalent cmdstream captures from 2-- various generations, looking for equivalencies between registers. 3-- 4-- This would be run across a group of similar tests for various 5-- generations, for example: 6-- 7-- cffdump --script scripts/analyze.lua a320/quad-flat-*.rd a420/quad-flat-*.rd 8-- 9-- This is done by comparing unique register values. Ie. for each 10-- generation, find the set of registers that have different values 11-- between equivalent draw calls. 12 13local posix = require "posix" 14 15io.write("Analyzing Data...\n") 16 17-- results - table structure: 18-- * [gpuname] - gpu 19-- * tests 20-- * [testname] - current test 21-- * draws 22-- * [1..n] - the draws 23-- * primtype - the primitive type 24-- * regs - table of values for draw 25-- * [regbase] - regval 26-- * regvals - table of unique values across all draws 27-- * [regbase] 28-- * [regval] - list of test names 29-- * [1..n] - testname "." didx 30local results = {} 31 32local test = nil 33local gpuname = nil 34local testname = nil 35 36 37-- srsly, no sparse table size() op? 38function tblsz(tbl) 39 local n = 0; 40 for k,v in pairs(tbl) do 41 n = n + 1 42 end 43 return n 44end 45 46 47function start_cmdstream(name) 48 testname = posix.basename(name) 49 gpuname = posix.basename(posix.dirname(name)) 50 --io.write("START: gpuname=" .. gpuname .. ", testname=" .. testname .. "\n"); 51 local gpu = results[gpuname] 52 if gpu == nil then 53 gpu = {["tests"] = {}, ["regvals"] = {}} 54 results[gpuname] = gpu 55 end 56 test = {["draws"] = {}} 57 gpu["tests"][testname] = test 58end 59 60function draw(primtype, nindx) 61 -- RECTLIST is only used internally.. we want to ignore it for 62 -- now, although it could potentially be interesting to track 63 -- these separately (separating clear/restore/resolve) just to 64 -- figure out which registers are used for which.. 65 if primtype == "DI_PT_RECTLIST" then 66 return 67 end 68 local regtbl = {} 69 local draw = {["primtype"] = primtype, ["regs"] = regtbl} 70 local didx = tblsz(test["draws"]) 71 72 test["draws"][didx] = draw 73 74 -- populate current regs. For now just consider ones that have 75 -- been written.. maybe we need to make that configurable in 76 -- case it filters out too many registers. 77 for regbase=0,0xffff do 78 if regs.written(regbase) ~= 0 then 79 local regval = regs.val(regbase) 80 81 -- track reg vals per draw: 82 regtbl[regbase] = regval 83 84 -- also track which reg vals appear in which tests: 85 local uniq_regvals = results[gpuname]["regvals"][regbase] 86 if uniq_regvals == nil then 87 uniq_regvals = {} 88 results[gpuname]["regvals"][regbase] = uniq_regvals; 89 end 90 local drawlist = uniq_regvals[regval] 91 if drawlist == nil then 92 drawlist = {} 93 uniq_regvals[regval] = drawlist 94 end 95 table.insert(drawlist, testname .. "." .. didx) 96 end 97 end 98 99 -- TODO maybe we want to whitelist a few well known regs, for the 100 -- convenience of the code that runs at the end to analyze the data? 101 -- TODO also would be useful to somehow capture CP_SET_BIN.. 102 103end 104 105function end_cmdstream() 106 test = nil 107 gpuname = nil 108 testname = nil 109end 110 111function print_draws(gpuname, gpu) 112 io.write(" " .. gpuname .. "\n") 113 for testname,test in pairs(gpu["tests"]) do 114 io.write(" " .. testname .. ", draws=" .. #test["draws"] .. "\n") 115 for didx,draw in pairs(test["draws"]) do 116 io.write(" " .. didx .. ": " .. draw["primtype"] .. "\n") 117 end 118 end 119end 120 121-- sort and concat a list of draw names to form a key which can be 122-- compared to other drawlists to check for equality 123-- TODO maybe we instead want a scheme that allows for some fuzzyness 124-- in the matching?? 125function drawlistname(drawlist) 126 local name = nil 127 for idx,draw in pairs(drawlist) do 128 if name == nil then 129 name = draw 130 else 131 name = name .. ":" .. draw 132 end 133 end 134 return name 135end 136 137local rnntbl = {} 138 139function dumpmatches(name) 140 for gpuname,gpu in pairs(results) do 141 local r = rnntbl[gpuname] 142 if r == nil then 143 io.write("loading rnn database: \n" .. gpuname) 144 r = rnn.init(gpuname) 145 rnntbl[gpuname] = r 146 end 147 for regbase,regvals in pairs(gpu["regvals"]) do 148 for regval,drawlist in pairs(regvals) do 149 local name2 = drawlistname(drawlist) 150 if name == name2 then 151 io.write(string.format(" %s:%s:\t%08x %s\n", 152 gpuname, rnn.regname(r, regbase), 153 regval, rnn.regval(r, regbase, regval))) 154 end 155 end 156 end 157 end 158end 159 160function finish() 161 -- drawlistnames that we've already dumped: 162 local dumped = {} 163 164 for gpuname,gpu in pairs(results) do 165 -- print_draws(gpuname, gpu) 166 for regbase,regvals in pairs(gpu["regvals"]) do 167 for regval,drawlist in pairs(regvals) do 168 local name = drawlistname(drawlist) 169 if dumped[name] == nil then 170 io.write("\n" .. name .. ":\n") 171 dumpmatches(name) 172 dumped[name] = 1 173 end 174 end 175 end 176 end 177end 178 179