Thread Tools Display Modes
07-06-05, 07:36 PM   #21
Littlejohn
A Warpwood Thunder Caller
AddOn Author - Click to view addons
Join Date: Jun 2005
Posts: 90
Yep, it does seem to report increments of 1 millisecond. (If you run GetTime() in a loop just printing it to chat, the values are precisely increments of 1 millisecond.) I'm not sure the time is accurate to the millisecond though -- are all milliseconds created equal?

The other problem is that a lot of functions run much quicker than a millisecond. Lua is running about 1,000+ OnEvent/OnUpdate functions per second. That probably fans out to 5,000+ functions per second.

I'll show timing data in v1.4 though. You've helped me convince myself that it's not that big of a problem. I should just try simple timing and see what happens.
  Reply With Quote
07-14-05, 06:03 PM   #22
Legorol
A Cliff Giant
AddOn Author - Click to view addons
Join Date: Jul 2005
Posts: 79
A very nice AddOn

I have just noticed this AddOn thanks to the publicity it received on the official forums. Good job, Iriel :-) It does look very nice and very useful. However, I would like to make a couple of small comments:

1) In make_hook, you create a function that has ellipsis (...) as argument, so that it can receive multiple arguments. You then use unpack(arg) to pass these onto the hooked function. While this is very nice style-wise, the use of the ellipsis itself generates garbage, and therefore might bias your statistics. Consider replacing it with something like say 20 static arguments, such as: "return function(a1, a2, a3, a4, etc.)", and then pass a1, a2 etc. to the hooked function. It will look ugly but eliminates garbage generation.

2) You are using the Class:Method syntax to enter functions to watch that are elements of a table. I suggest (and hope) that you use the Class.Method syntax instead. Although the choice is arbitrary from the entry point of view, it ties in better with the Lua concepts of elements of a table (Also see point 3). I know that usually the way to call most methods of XML objects is via the Class:Method syntax (e.g. GameTooltip:Show()), but in Lua, the colon is really nothing special, it's just a shorthand for Class.Method(Class, ...). In otherwords, "GameTooltip:Show() = GameTooltip.Show(GameTooltip)". Also, if you are trying to hook a function, you would specify GameTooltip.Show as the function to hook and not GameTooltip:Show.

3) Do you think you will support functions that are more than one layer deep in a table? For example Class.Subclass.Function? I don't know if you are familiar with the Sea library, but if you need some inspiration on how to do something like this, Sea has two functions Sea.util.getValue and Sea.util.setValue. Those work like getglobal/setglobal, but allow table elements as their arguments too. Their code might be a useful starting point.

4) I don't know if you noticed this, but unfortunately due to the way Blizzard coded things, you can't enumerate the native methods of tables that are representing XML-defined objects. You only have access to methods if you know their name exactly. In other words the following code snippet,
Code:
 for k, v in GameTooltip do
  -- do something with k and v
 end
only returns those elements of the GameTooltip table that have been added from Lua. So if you are using it to iterate over the methods of GameTooltip, you only see those methods that have been modified from Lua, for example hooked into by some AddOn. This means that regular expressions don't work reliably with methods of XML-defined objects. You can see this for yourself: typing "GameTooltip:.+" into TraceEvent results in very few methods being traced. As far as I know, there is no way at the moment to enumerate the native methods.

Apart from the above comments, let me again say that you have a great AddOn here that I am going to be using from now on!
  Reply With Quote
07-16-05, 07:15 AM   #23
Littlejohn
A Warpwood Thunder Caller
AddOn Author - Click to view addons
Join Date: Jun 2005
Posts: 90
Originally Posted by Legorol
I have just noticed this AddOn thanks to the publicity it received on the official forums. Good job, Iriel :-) It does look very nice and very useful. However, I would like to make a couple of small comments:
Thanks! I appreciate the feedback. I haven't read the WoW forums in a week or so, but the last I saw, Iriel was rather luke-warm on profiling. Can you point me to the post you saw?

1) In make_hook, you create a function that has ellipsis (...) as argument, so that it can receive multiple arguments. You then use unpack(arg) to pass these onto the hooked function. While this is very nice style-wise, the use of the ellipsis itself generates garbage, and therefore might bias your statistics.
I've already abandoned style for efficiency to handle return values. I originally used

local r = { info.orig_f(unpack(arg)) }

to pick up a dynamic number of function return values. This severely skewed the GC results though so I used the ugly and semi-unreliable code

local a,b,c,d,e = info.orig_f(unpack(arg))

to reduce garbage generation.

You really think it's a good idea to limit the number of arguments a function takes? I convinced myself that 5 return results is unlikely to break things, but I'm not sure what to use as the upper limit to the number of arguments. You think 20 is ok?

2) You are using the Class:Method syntax to enter functions to watch that are elements of a table. I suggest (and hope) that you use the Class.Method syntax instead. Although the choice is arbitrary from the entry point of view, it ties in better with the Lua concepts of elements of a table (Also see point 3). I know that usually the way to call most methods of XML objects is via the Class:Method syntax (e.g. GameTooltip:Show()), but in Lua, the colon is really nothing special, it's just a shorthand for Class.Method(Class, ...). In otherwords, "GameTooltip:Show() = GameTooltip.Show(GameTooltip)". Also, if you are trying to hook a function, you would specify GameTooltip.Show as the function to hook and not GameTooltip:Show.
There is another thread http://www.wowinterface.com/forums/s...5&page=2&pp=10
where Kaelten asked for method call tracing on particular instances. After I thought about that, I realized I made the mistake you point out. I've decided to use "class.method" syntax to trace functions in a table (works for class methods and package namespaces) and "object:method" syntax to trace method calls on specific objects.

3) Do you think you will support functions that are more than one layer deep in a table? For example Class.Subclass.Function?
Honestly I didn't know people used that style. It's no big deal to add arbitrary nesting. I should also change the table search code to allow name patterns for tables. (In v1.3 only method names allow patterns; tables must be named precisely.)

4) I don't know if you noticed this, but unfortunately due to the way Blizzard coded things, you can't enumerate the native methods of tables that are representing XML-defined objects. You only have access to methods if you know their name exactly.
Thanks, I definitely wasn't aware of that.

Are you sure Bliz isn't using Lua metatables? I could automatically search __index if it's a table. If __index is a function or if Bliz is using non-Lua method dispatch then I'm pretty much hosed. I'm past the Lua-newbie phase, but I'm not an expert yet... If you have any advice on OO and/or metatables I'd love to hear it.

One of the things that I've sketched out for v1.4 is a more robust way of entering the functions to trace. People (especially gamers without Lua experience) are making mistakes entering the function name patterns. I'm planning on having a GUI to build the table and function patterns with check boxes to turn them on and off.

I could probably solve the "secret" method problem by including a built-in list of method names. (I'd rather follow __index up to the superclass if I can do that reliably though.)
  Reply With Quote
07-17-05, 08:18 PM   #24
Legorol
A Cliff Giant
AddOn Author - Click to view addons
Join Date: Jul 2005
Posts: 79
Originally Posted by Littlejohn
You really think it's a good idea to limit the number of arguments a function takes? I convinced myself that 5 return results is unlikely to break things, but I'm not sure what to use as the upper limit to the number of arguments. You think 20 is ok?
I think 20 arguments should be more than sufficient. I don't know if the ellipsis argument is skewing results or not, if it isn't you could just leave it as it is. I am certain that it's generating garbage though.

There is another thread http://www.wowinterface.com/forums/s...5&page=2&pp=10
where Kaelten asked for method call tracing on particular instances. After I thought about that, I realized I made the mistake you point out. I've decided to use "class.method" syntax to trace functions in a table (works for class methods and package namespaces) and "object:method" syntax to trace method calls on specific objects.
If you have been asked already, then there is not much to add. To be honest, I don't see the difference between "object", "table" or "class", since in Lua they are the same thing, they are all just tables. GameTooltip is just as much a Lua-table as say MyAddOnClass.

Honestly I didn't know people used that style. It's no big deal to add arbitrary nesting. I should also change the table search code to allow name patterns for tables. (In v1.3 only method names allow patterns; tables must be named precisely.)
They do, although not very often. One prime example is the Sea function library which has tables such as Sea.io, Sea.util etc. with functions in each such as Sea.io.print and Sea.util.hook.

Thanks, I definitely wasn't aware of that.

Are you sure Bliz isn't using Lua metatables? I could automatically search __index if it's a table. If __index is a function or if Bliz is using non-Lua method dispatch then I'm pretty much hosed. I'm past the Lua-newbie phase, but I'm not an expert yet... If you have any advice on OO and/or metatables I'd love to hear it.
As you have guessed, Blizzard uses a natively (read, in C) implemented __index function in a metatable attached to every XML-generated object that's using a non-Lua method to dispatch calls, so you are hosed, in principle. In practice however, complete lists of methods for all known XML-generated object types are available, e.g. at
http://www.wowwiki.com/Widget_API
So as you have suggested (and as Iriel has suggested to me in a thread on the WoW forums), you can build a list of these functions, and match any regexp patterns against such a list. The difficulty unfortunately lies in determining what type of UI object a particular Lua table corresponds to, in other words what set of methods it has. There is no good way that I know of to do this For example, given the name SomeRandomFrame, there is no known way to tell that the global Lua table called "SomeRandomFrame" is attached to a UI element of type Frame, Button or something else.

One of the things that I've sketched out for v1.4 is a more robust way of entering the functions to trace. People (especially gamers without Lua experience) are making mistakes entering the function name patterns. I'm planning on having a GUI to build the table and function patterns with check boxes to turn them on and off.
This sounds like a great idea!
  Reply With Quote
07-17-05, 08:37 PM   #25
Littlejohn
A Warpwood Thunder Caller
AddOn Author - Click to view addons
Join Date: Jun 2005
Posts: 90
Originally Posted by Legorol
I don't see the difference between "object", "table" or "class", since in Lua they are the same thing, they are all just tables. GameTooltip is just as much a Lua-table as say MyAddOnClass.
Right, the "foo.bar" syntax uses "foo" as the name of a table and "bar" as an entry in the table. That works for tables and classes (since classes are just fancy tables).

The "foo:bar" syntax uses "foo" as the name of an object, then fetches the metatable info to find the object class. The trace function is inserted into the class table, but stats are only collected if the object instance matches "foo" at call time. I'm not sure I'm explaining it well. (And maybe I misinterpreted Kaelten's original request...)

As you have guessed, Blizzard uses a natively (read, in C) implemented __index function in a metatable attached to every XML-generated object that's using a non-Lua method to dispatch calls, so you are hosed, in principle. In practice however, complete lists of methods for all known XML-generated object types are available
Did you ever try replacing __index? Hooking that would yield all sorts of interesting information about frame methods. I'll poke around a bit in the metatable info and see what I can do.

(BTW, cedar's half up! woot! gonna be nice to trade the hammer for a keyboard and get back to coding...
  Reply With Quote
07-17-05, 10:09 PM   #26
Kaelten
Jack's raging bile duct
 
Kaelten's Avatar
Featured
Join Date: May 2005
Posts: 782
no littlejohn it sounds like you got me right.

It would be nice if I Could track just x instance of whatever class.

And it is kinda odd that in Lua OO is basically a very nasty table hack. (Scary in fact)

This does allow for some things that other OO languages would just choke on though.
__________________
WowAce.com & CurseForge.com Adminstrator
Developer of Ace3, OneBag3, and many other addons and libraries
Project lead and Mac developer for the Curse Client

Anyone that needs what they want
And doesn't want what they need
I want nothing to do with
  Reply With Quote
07-17-05, 10:13 PM   #27
Kaelten
Jack's raging bile duct
 
Kaelten's Avatar
Featured
Join Date: May 2005
Posts: 782
if you did support nesting, watch out for circular references. They probably aren't extremely common but they do happen.
__________________
WowAce.com & CurseForge.com Adminstrator
Developer of Ace3, OneBag3, and many other addons and libraries
Project lead and Mac developer for the Curse Client

Anyone that needs what they want
And doesn't want what they need
I want nothing to do with
  Reply With Quote
07-18-05, 12:03 PM   #28
Littlejohn
A Warpwood Thunder Caller
AddOn Author - Click to view addons
Join Date: Jun 2005
Posts: 90
ha ha! It is possible to hook getmetatable(foo)[__index] and trace built-in (and inherited) WoW routines on any frame object.

I tried using a proxy table with __index and __newindex methods that just forward to the original table, but that kept crashing WoW for some reason. Maybe lua doesn't like recursive metatable lookup? Anyways, WoW uses the same metatable (and therefore the same __index) on many (all?) XML frame objects. I hooked __index and collected trace history on DEFAULT_CHAT_FRAME. It's possible to dynamically trace an object -- using __index you can see when a new function is called and then it can be dynamically added to the trace.

This is probably not that useful to mod authors though. The only thing that seems really cool is automatic generation of the frame XML APIs. (Where did the WoW wiki docs come from anyways?)

Legorol: What did you have in mind for this feature? Do you really want to be able to trace, for example, DEFAULT_CHAT_FRAME:* and have all the built-in methods show up?

Kaelten: I was hoping I understood you right. I don't think of OO in Lua as a nasty table hack -- I'd call it an elegant table hack. It's like a Python+Scheme love child. Or an alternate universe version of Perl created by a computer scientist instead of a linguist.
  Reply With Quote
07-18-05, 06:43 PM   #29
Legorol
A Cliff Giant
AddOn Author - Click to view addons
Join Date: Jul 2005
Posts: 79
I agree that hooking into the __index function is a good way to see method calls at run time, and can make tracing based on patterns work. I presume what you had in mind is that if the user has specified a regexp, then you don't hook there and then, but if you notice a method call that matches the regexp, then you hook it. That would work and in fact sounds like a good idea for being able to use regexp patterns with XML-generated tables. The particular example I was thinking of is specifying a trace pattern such as GameTooltip%.Set.+ (i mean to indicate that the first '.' is not special but the second one is, i don't know what's the best way for you to handle this).

Unfortunately hooking __index will not help with scanning for the API, because it would require you to actually run WoW and wait for all sorts of method calls to actually happen for you to be able to see that they exist. There are some methods that are in fact never called from any of the default Blizzard UI files, and therefore would be missed, even if you made use of every UI element. One such example is the FontString:SetJustifyV method.

The list on the Wiki is generated by a very crude and simple method: scan WoW.exe for all strings and make a list out if, which forms the list of candidates. Then test each object type and see if it has a method that is named any of those candidates. The key here is that testing for a superset that includes stuff other than valid method names is not a problem as long as your set is guaranteed to include all actual methods.

OO

Supporting OO concepts in TraceEvent is going to be tricky in my opinion. Although there are one or two 'standard' text-book ways of doing OO (classes and instances) in Lua using tables, there are actually a number of possible ways of implementing OO or semi-OO concepts. I have seen different AddOns use very different means to implement OO concepts such as classes and instanciation. Catering for all these scenarios will be difficult, because you won't know in what particular way is an AddOn making use of metatables for example.

This is just my opinion, but I beleive that you should drop the ':' syntax alltogether and not try to cater for OO concepts at all. Instead, make sure you have a firm method of tracing table elements, using the '.' syntax. That should be sufficient for those using OO concepts, because they can either specify the table representing the class, or the table representing an instance if they wish. This is just my personal opinion though.

Last edited by Legorol : 07-18-05 at 06:45 PM.
  Reply With Quote
08-29-06, 10:34 AM   #30
sarf
A Cyclonian
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 47
Hmm... sorry for putting this here, but I simply can't get your TraceEvent thingy to work. It shows up fine and spiffy, I just can not seem to add stuff to trace (input field seems to be disabled - it's not accepting any input anyhow, nor can I use direct calls to TraceEvent_AddTrace to get around it).

I have tried to do TraceEventAddName:SetText("A") and nothing whatsoever happens.

Is there any way I can easily detect if an addon (I run numerous) can interfere with it?

( <honks at Legorol> )

Sarf
  Reply With Quote
09-05-06, 09:56 PM   #31
Kinesia
A Kobold Labourer
Join Date: May 2006
Posts: 1
I have exactly the same issue as Sarf.
I suspect we are both using Cosmos though have no idea whether that is the issue or not.
  Reply With Quote

WoWInterface » Developer Discussions » Dev Tools » TraceEvent - Dynamic Lua code profiling

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off