Okay.. so I'll admit 100% that I'm retarded, but I'm working on a rewrite of AceHook. This version has the following cleanup:
When hooking a function, creates ONE table per self (i.e. one table per addon)
When hooking a method, creates ONE table per self (i.e. one table per addon) and ONE table per method
In contrast the current AceHook creates:
ONE table for every single function being hooked
ONE table for every different OBJECT that we hook a method in
ONE table for every different METHOD that we hook within an object
Some examples, in the current AceHook if you hook 2 methods (we'll say show and hide) in in 3 different addons it will create:
self.hooks = {}
self.hooks[PlayerFrame] = {}
self.hooks[PlayerFrame] = {}
self.hooks[TargetTargetFrame] = {}
self.hooks[PlayerFrame].Show = {}
self.hooks[PlayerFrame].Hide = {}
self.hooks[TargetFrame].Show = {}
self.hooks[TargetFrame].Hide = {}
self.hooks[TargetTargetFrame].Show = {}
self.hooks[TargetTargetFrame].Hide = {}
With my new version, we create the following instead:
original[self][src] = {}
registry[self] = {}
To be fair, my version still has to store some of the same information, but whereas EACH of the tables in the current AceHook stores four values, in the new scheme we store the following references:
original[self][src] gets keyed by the method (a string) and has a value of the ORIGINAL function symbol we're replacing
registry[self] gets keyed by the ORIGINAL function symbol we replaced and has a value of the ANONYMOUS HANDLER function symbol we generate
inactive gets keyed by the ANONYMOUS HANDLER function symbol and holds a value of true (if inactive), otherwise its never set.
If we wanted to we could still provide self.hooks as a reference to original[self], since I'm storing things in such a specific fashion, but we would have to play some metatable tricks, since we currently use:
self.hooks.FunctionName.orig()
and its not longer a table, so we could use self.hooks.FunctionName() natively. As a result of this, I suggest we re-institute self:CallHook(). Its more consistent with the rest of the Ace API (although a change from current operation, we could probably write some compat stuff) and in this operation is a bit cleaner to say the least. The reason I moved away from CallHook was because we couldn't think of a good way to store the data without the tables.
I'm done profiling the current code (added CallHook on my side, and an OnInitInstance that provides an interface to original[self]):
As always, the base is the control test. This tests AceHook 2.0, with AceHook 3.0 using CallHook, and AceHook 3.0 using self.hooks. Here are the results:
=== Function Hooking ===
PROFILE: Timing for Base function took 4.392 seconds (0.02928 average)
PROFILE: Memory for Base function took 26250 KiB (175 average)
PROFILE: Timing for Function by AceHook-2.0 took 7.686 seconds (0.05124 average)
PROFILE: Memory for Function by AceHook-2.0 took 26250 KiB (175 average)
PROFILE: Timing for Function by AceHook-3.0 took 8.61 seconds (0.0574 average)
PROFILE: Memory for Function by AceHook-3.0 took 26250 KiB (175 average)
PROFILE: Timing for Function by AceHook-3.0[Table] took 7.751 seconds (0.051673333333333 average)
PROFILE: Memory for Function by AceHook-3.0[Table] took 26400 KiB (176 average)
=== Method Hooking ===
PROFILE: Timing for Base method took 4.293 seconds (0.02862 average)
PROFILE: Memory for Base method took 26400 KiB (176 average)
PROFILE: Timing for Method by AceHook-2.0 took 8.234 seconds (0.054893333333333 average)
PROFILE: Memory for Method by AceHook-2.0 took 26400 KiB (176 average)
PROFILE: Timing for Method by AceHook-3.0 took 9.108 seconds (0.06072 average)
PROFILE: Memory for Method by AceHook-3.0 took 26400 KiB (176 average)
PROFILE: Timing for Method by AceHook-3.0[Table] took 7.748 seconds (0.051653333333333 average)
PROFILE: Memory for Method by AceHook-3.0[Table] took 26400 KiB (176 average)
=== Function Hooking ===
PROFILE: Timing for Base function took 1.485 seconds (0.0297 average)
PROFILE: Memory for Base function took 8750 KiB (175 average)
PROFILE: Timing for Function by AceHook-2.0 took 2.655 seconds (0.0531 average)
PROFILE: Memory for Function by AceHook-2.0 took 8750 KiB (175 average)
PROFILE: Timing for Function by AceHook-3.0 took 3.032 seconds (0.06064 average)
PROFILE: Memory for Function by AceHook-3.0 took 8750 KiB (175 average)
PROFILE: Timing for Function by AceHook-3.0[Table] took 2.626 seconds (0.05252 average)
PROFILE: Memory for Function by AceHook-3.0[Table] took 8800 KiB (176 average)
=== Method Hooking ===
PROFILE: Timing for Base method took 1.485 seconds (0.0297 average)
PROFILE: Memory for Base method took 8750 KiB (175 average)
PROFILE: Timing for Method by AceHook-2.0 took 2.874 seconds (0.05748 average)
PROFILE: Memory for Method by AceHook-2.0 took 8800 KiB (176 average)
PROFILE: Timing for Method by AceHook-3.0 took 3.202 seconds (0.06404 average)
PROFILE: Memory for Method by AceHook-3.0 took 8800 KiB (176 average)
PROFILE: Timing for Method by AceHook-3.0[Table] took 2.688 seconds (0.05376 average)
PROFILE: Memory for Method by AceHook-3.0[Table] took 8800 KiB (176 average)
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
In contrast the current AceHook creates:
Some examples, in the current AceHook if you hook 2 methods (we'll say show and hide) in in 3 different addons it will create:
self.hooks = {}
self.hooks[PlayerFrame] = {}
self.hooks[PlayerFrame] = {}
self.hooks[TargetTargetFrame] = {}
self.hooks[PlayerFrame].Show = {}
self.hooks[PlayerFrame].Hide = {}
self.hooks[TargetFrame].Show = {}
self.hooks[TargetFrame].Hide = {}
self.hooks[TargetTargetFrame].Show = {}
self.hooks[TargetTargetFrame].Hide = {}
With my new version, we create the following instead:
original[self][src] = {}
registry[self] = {}
To be fair, my version still has to store some of the same information, but whereas EACH of the tables in the current AceHook stores four values, in the new scheme we store the following references:
original[self][src] gets keyed by the method (a string) and has a value of the ORIGINAL function symbol we're replacing
registry[self] gets keyed by the ORIGINAL function symbol we replaced and has a value of the ANONYMOUS HANDLER function symbol we generate
inactive gets keyed by the ANONYMOUS HANDLER function symbol and holds a value of true (if inactive), otherwise its never set.
If we wanted to we could still provide self.hooks as a reference to original[self], since I'm storing things in such a specific fashion, but we would have to play some metatable tricks, since we currently use:
self.hooks.FunctionName.orig()
and its not longer a table, so we could use self.hooks.FunctionName() natively. As a result of this, I suggest we re-institute self:CallHook(). Its more consistent with the rest of the Ace API (although a change from current operation, we could probably write some compat stuff) and in this operation is a bit cleaner to say the least. The reason I moved away from CallHook was because we couldn't think of a good way to store the data without the tables.
I've found the way =)
AceHook-2.0: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.0/AceHook-2.0.lua
AceHook-3.0?: http://ace.pastey.net/97
UnitTesting: http://ace.pastey.net/98 (Will require some sort of compat environment if running outside WoW)
Compat: http://ace.pastey.net/99 I use this to fix the missing debugstack and setglobal/getglobal
I haven't profiled the code yet.. but I expect it to be at least as fast as AceHook 2.0, but we'll see where that ends up =)
As always, the base is the control test. This tests AceHook 2.0, with AceHook 3.0 using CallHook, and AceHook 3.0 using self.hooks. Here are the results: