summaryrefslogtreecommitdiff
path: root/src/freedreno/decode/scripts/analyze.lua
blob: 27e97ecd4a53be8038033788d52796aab1fa7e93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
-- 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