vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 
2 --[[
3  
4 Main.lua
5  
6 This module does all the work. It hooks every OnEvent and OnUpdate function in existance.
7  
8 ]]
9  
10 -- table setup
11 local mod = thismod
12 local me = { }
13 mod.main = me
14  
15 me.ishooking = false
16  
17 --[[
18 me.hookall()
19 Hooks all the OnUpdate() and OnEvent() methods running.
20  
21 First thing is to gather all frames. We make a table, key = the frame itself, value = {onevent = <true or nil>, onupdate = <true or nil>}
22 ]]
23 me.hookall = function()
24  
25 -- this method can only be run once - check!
26 if me.ishooking == true then
27 mod.out.print("The monitor has already been loaded, and is actively recording data.")
28 return
29 end
30  
31 local frame, script
32 local numonevents = 0
33 local numonupdates = 0
34 local numframes = 0
35 local numemptyframes = 0
36  
37 -- first let's find all the frames
38 local allframes = { }
39 local hasonupdate, hasonevent
40  
41 while true do
42  
43 -- get next frame
44 frame = EnumerateFrames(frame)
45 if frame == nil then
46 break
47 end
48  
49 numframes = numframes + 1
50 allframes[frame] = {me = frame, numchildren = 0, children = { }}
51  
52 -- Determine whether the frame has onupdates or onevents
53 hasonupdate = frame:GetScript("OnUpdate")
54 hasonevent = frame:GetScript("OnEvent")
55  
56 if hasonevent then
57 numonevents = numonevents + 1
58 allframes[frame].onevent = true
59 end
60  
61 if hasonupdate then
62 numonupdates = numonupdates + 1
63 allframes[frame].onupdate = true
64 end
65  
66 -- add the name property
67 allframes[frame].name = frame:GetName()
68  
69 end
70  
71 -- print
72 mod.out.print(string.format("Found %s frames, %s onupdates, %s onevents.", numframes, numonupdates, numonevents))
73  
74 -- Now, find anonymous frames whose parents have known parents (not uiparent)
75 local numanonymous, numnamed, parent
76 local key, value, parentvalue
77  
78 -- for loop as a safety limit, for now
79 for x = 1, 10 do
80 numanonymous = 0
81 numnamed = 0
82  
83 for key, value in allframes do
84 if value.name == nil then
85 numanonymous = numanonymous + 1
86  
87 -- check for parent
88 parent = key:GetParent()
89 parentvalue = allframes[parent]
90  
91 if parentvalue and parentvalue.name and parentvalue.name ~= "UIParent" then
92 -- we've found a good parent
93 parentvalue.numchildren = parentvalue.numchildren + 1
94 numnamed = numnamed + 1
95 value.name = parentvalue.name .. "$child" .. parentvalue.numchildren
96 table.insert(parentvalue.children, value)
97  
98 elseif x == 10 then
99 -- we just can't find the name for this frame's parents, no matter what. Better scrap it
100 allframes[key] = nil
101 end
102 end
103 end
104  
105 --mod.out.print(string.format("x = %d, found %d anonymous, named %d.", x, numanonymous, numnamed))
106  
107 if numnamed == 0 then
108 break
109 end
110 end
111  
112 local totalframes, framesdropped
113  
114 for x = 1, 10 do
115 totalframes = 0
116 framesdropped = 0
117  
118 for key, value in allframes do
119  
120 totalframes = totalframes + 1
121  
122 -- 1) check 0 children
123 if value.numchildren == 0 then
124  
125 -- check no event on onupdate
126 if value.onupdate == nil and value.onevent == nil then
127 framesdropped = framesdropped + 1
128  
129 -- check for anonymous frame
130 if key:GetName() == nil then
131 -- remove name from parent's list
132 parentvalue = allframes[key:GetParent()]
133  
134 -- parentvalue might not exist now
135 if parentvalue then
136 for y = 1, parentvalue.numchildren do
137 if parentvalue.children[y] == value then
138 table.remove(parentvalue.children, y)
139 break
140 end
141 end
142  
143 parentvalue.numchildren = parentvalue.numchildren - 1
144 end
145 end
146  
147 allframes[key] = nil
148 end
149 end
150 end
151  
152 -- print
153 --mod.out.print(string.format("stage %s, found %s frames, dropped %s.", x, totalframes, framesdropped))
154  
155 if framesdropped == 0 then
156 break
157 end
158  
159 end
160  
161 -- Group related holdings into families
162 local headers = { }
163 local header
164 local numfamilies = 0
165 local framesleft = 0
166  
167 for key, value in allframes do
168  
169 framesleft = framesleft + 1
170  
171 -- somehow, value.name can be nil here
172 if value.name then
173 local header = me.getnameheader(value.name)
174  
175 -- does this family already exist?
176 if headers[header] == nil then
177  
178 -- create new
179 headers[header] = { value }
180 numfamilies = numfamilies + 1
181  
182 else
183 -- add
184 table.insert(headers[header], value)
185 end
186  
187 -- set my family ref
188 value.family = headers[header]
189 end
190 end
191  
192 -- make a file level variable
193 me.families = headers
194 me.frames = allframes
195  
196 -- print
197 mod.out.print(string.format("Combined the %s active frames into %s groups.", framesleft, numfamilies))
198  
199 -- now let's hook them!
200 numonevents = 0
201 numonupdates = 0
202  
203 for key, value in allframes do
204  
205 -- some unknowable frames are left in - don't hook them.
206 if value.name then
207  
208 if value.onevent then
209 me.overridescript(key, "OnEvent", value)
210 numonevents = numonevents + 1
211 end
212  
213 if value.onupdate then
214 me.overridescript(key, "OnUpdate", value)
215 numonupdates = numonupdates + 1
216 end
217 end
218 end
219  
220 -- set as loaded
221 me.ishooking = true
222  
223 -- print
224 --mod.out.print(string.format("Found %s onevent, %s onupdate.", numonevents, numonupdates))
225  
226 end
227  
228 me.getnameheader = function(name)
229  
230 -- still nil? return nil
231 if name == nil then
232 return "<nil>"
233 end
234  
235 local length = string.len(name)
236  
237 -- really short stuff, to stop annoying cases
238 if length < 6 then
239 return name
240 end
241  
242 -- check 4th char
243 local current, previous, next_
244 local position = 3
245  
246 previous = string.sub(name, position - 1, position - 1)
247 current = string.sub(name, position, position)
248 next_ = string.sub(name, position + 1, position + 1)
249  
250 local x = 0
251 while true do
252  
253 x = x + 1
254 if x > 20 then
255 mod.out.print("emergency stop!")
256 return name
257 end
258  
259 -- iterate
260 position = position + 1
261 previous = current
262 current = next_
263 next_ = string.sub(name, position + 1, position + 1)
264  
265 -- check for end of string
266 if next_ == "" then
267 return name
268 end
269  
270 -- check for underscore
271 if current == "_" then
272 return string.sub(name, 1, position)
273 end
274  
275 -- check for UUl
276 if string.find(previous, "[A-Z]") and string.find(current, "[A-Z]") then
277 -- if the string is 5 or longer, that's enough
278 if position >= 5 then
279 return string.sub(name, 1, position)
280 end
281  
282  
283 end
284  
285 -- check for lU
286 if string.find(current, "[a-z]") and string.find(next_, "[A-Z]") then
287 return string.sub(name, 1, position)
288 end
289  
290 end
291  
292 end
293  
294 me.print2 = function(datatype, property)
295  
296 if me.ishooking == false then
297 mod.out.print(string.format("The monitor is not loaded, so there's no data to print. Run the command |cffffff00%s load|r to start the monitor.", mod.string.get("print", "console", "short")))
298 return
299 end
300  
301 -- default values
302 if datatype == nil then
303 datatype = "time" -- or "memory"
304 end
305  
306 if property == nil then
307 property = "total" -- or recent
308 end
309  
310 -- let's just get the total values for all the families, and print off a random few
311  
312 local header, family, index, framedata
313 local total, prints
314 prints = 0
315 local values = { }
316  
317 for header, family in me.families do
318 total = 0
319 if family == nil then
320 mod.out.print("Nil family for header = " .. header)
321 end
322  
323 for index = 1, table.getn(family) do
324 framedata = family[index]
325 if framedata.onupdate then
326 total = total + framedata.onupdate[datatype][property]
327 end
328 if framedata.onevent then
329 total = total + framedata.onevent[datatype][property]
330 end
331 end
332  
333 -- add to values
334 table.insert(values, {header, total})
335 end
336  
337 -- sort
338 table.sort(values, function(a, b) return a[2] > b[2] end)
339  
340 for index = 1, 10 do
341 --[[ the values are
342 1) The rank, from 1 to 10
343 2) The header / name of the family
344 3) An example of a frame name in that family
345 4) The actual value
346 ]]
347 mod.out.print(string.format("%d %s (%s): %s", index, values[index][1],
348 me.families[values[index][1]][1].name, math.floor(0.5 + values[index][2])))
349 end
350  
351 end
352  
353  
354 -- script = "OnUpdate" or "OnEvent"
355 me.overridescript = function(frame, script, value)
356  
357 local framename = value.name
358 local varname = string.lower(script)
359 local original = frame:GetScript(script)
360  
361 if original == nil then
362 mod.out.print("There's no " .. script .. " script for the frame " .. frame)
363 return
364 end
365  
366 me.nexthook = function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
367 me.hookproc(frame, varname, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
368 end
369  
370 me.frames[frame][varname] = { }
371 me.frames[frame][varname].original = original
372 me.frames[frame][varname].replacement = me.nexthook
373 me.frames[frame][varname].memory = mod.dataset.createnewdataset(5.0, 6)
374 me.frames[frame][varname].time = mod.dataset.createnewdataset(5.0, 6)
375  
376 -- set the new script
377 frame:SetScript(script, me.nexthook)
378  
379 end
380  
381 -- frame is the name of a frame. script = "onupdate" or "onevent"
382 me.hookproc = function(frame, script, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
383  
384 local gcbefore = gcinfo()
385 local timebefore = GetTime()
386  
387 me.frames[frame][script].original(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
388  
389 local timetaken = 1000 * (GetTime() - timebefore)
390 local memory = gcinfo() - gcbefore
391 if memory < 0 then
392 memory = 0
393 end
394  
395 mod.dataset.adddatapoint(me.frames[frame][script].memory, memory)
396 mod.dataset.adddatapoint(me.frames[frame][script].time, timetaken)
397 end
398