RPTools.net

Discussion and Support

Skip to content

It is currently Sat Aug 19, 2017 3:41 pm 






Reply to topic  [ 99 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7  Next

Previous topic | Next topic 

  Print view

Author Message
User avatar  Offline
Site Admin
 
Joined: Mon Jun 12, 2006 12:20 pm
Posts: 12078
Location: Tampa, FL
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 4:28 pm 
Barrodin wrote:
EDIT: On a side note, some sort of built in timestamp function would be enourmously helpful in tests like this.

You're new here, so I'll forgive you.. ;) :mrgreen:

There is the Wiki: getInfo() function, as well as turning on logging (read the README that's part of the zip file download of MapTool).


Top
 Profile  
 
User avatar  Offline
Demigod
 
Joined: Mon Jun 29, 2009 9:37 am
Posts: 3108
Location: Germany
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 4:44 pm 
I've also build some time measuring functions using Wiki: getInfo() that you can find following the link in my sig. Its a dropin package of macros for benchmarking (big word for little function, but anyway).

_________________
HELP: GETTING STARTED WITH MAPTOOLS - TUTORIALS, DOCS, VIDEOS, TOOLS, ETC.

most complete list of my maptool stuff


Top
 Profile  
 
 Offline
Kobold
 
Joined: Thu Aug 18, 2011 9:51 am
Posts: 16
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 5:42 pm 
Ah! Bless you both. I was starting from the documentation wiki end of things and turning up nothing searching for time, timestamp, etc.

Give me a bit to add in some better logging to my script and I'll post some hard results on how much time the various methods of passing JSON objects take (assuming anyone is interested).


Top
 Profile  
 
 Offline
Kobold
 
Joined: Thu Aug 18, 2011 9:51 am
Posts: 16
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 7:08 pm 
Well, this turned out to be a bit interesting. It turns out that when you really pare everything down to the bare bones, so that you are only testing the time it takes to pass a JSON object in or out of a user defined function, the way you pass it makes a very big difference (at least for large objects). The results are below, and it is just as undeniably clearcut as I could have hoped for.

Passing/returning a JSON Object by name and using eval to copy the value into a variable has essentially the same cost in time regardless of how large the JSON Object becomes. On the other hand, passing/returning the object itself to/from a user defined function slows down tremendously for large objects.

This only really applies for large JSON Objects though, for small JSON Objects it really doesn't seem to matter. For arrays smaller than size 256/512, there really wasn't a meaningful difference in the time it took.

Image


And the raw numbers, if anyone is that curious:
Pass by Value
203, 188, 187, 204, 187, 203, 250, 281, 375, 578, 985, 1813, 3578, 6953, 13750, 27719
187, 187, 188, 187, 203, 219, 234, 297, 391, 578, 953, 1782, 3563, 6921, 13766, 27750
187, 188, 172, 187, 188, 204, 234, 281, 375, 594, 968, 1766, 3547, 6921, 13687, 27547
187, 188, 187, 188, 203, 219, 234, 281, 391, 593, 969, 1782, 3563, 6937, 13750, 27563

Pass by Name
203, 203, 203, 203, 204, 188, 203, 204, 203, 203, 203, 187, 203, 203, 203, 203
203, 203, 203, 188, 203, 203, 204, 203, 187, 187, 187, 203, 203, 203, 203, 203
188, 203, 203, 203, 203, 203, 188, 188, 203, 203, 203, 187, 187, 204, 187, 204
203, 204, 203, 203, 204, 187, 187, 187, 187, 188, 188, 188, 188, 188, 203, 203

Return by Value
297, 297, 297, 297, 297, 297, 328, 375, 438, 609, 922, 1563, 2829, 5390, 10937, 23500
297, 281, 297, 281, 297, 312, 313, 360, 453, 594, 907, 1563, 2828, 5360, 10765, 23641
297, 281, 281, 281, 297, 297, 313, 375, 437, 594, 907, 1563, 2829, 5375, 10766, 23484
296, 282, 282, 281, 297, 312, 313, 360, 453, 594, 922, 1563, 2828, 5390, 10922, 23531

Return by Name
312, 329, 312, 313, 312, 313, 312, 313, 296, 297, 296, 297, 297, 297, 312, 313
297, 312, 313, 312, 313, 297, 312, 313, 297, 312, 313, 297, 312, 312, 312, 297
297, 313, 312, 313, 312, 313, 312, 297, 313, 312, 313, 312, 312, 312, 312, 312
313, 312, 313, 312, 297, 313, 312, 297, 297, 313, 312, 297, 297, 297, 312, 312


Top
 Profile  
 
User avatar  Offline
Deity
 
Joined: Tue Nov 10, 2009 6:11 pm
Posts: 7789
Location: Bay Area
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 8:40 pm 
I'm curious to see the test code you used to run this test. How many keys were in the object and how big was the data?

_________________
Downloads:


Top
 Profile  
 
 Offline
Kobold
 
Joined: Thu Aug 18, 2011 9:51 am
Posts: 16
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 8:44 pm 
aliasmask wrote:
I'm curious to see the test code you used to run this test. How many keys were in the object and how big was the data?


The initial object was a JSON Array with a single entry (0).

On each loop, that JSON Array was merged with itself, doubling the size of the object to be passed (hence the *2^n notation on the object size axis). On the last loop the array would have been 65536 entries long, all of which would be identical. At some point I'll try it with more complex objects to see if it affects the times any, but not for now I think.

Code to follow shortly, just need to load up Maptool.

EDIT: Code. Nothing special right away, just the usual function definitions in onCampaignLoad. The only thing of note here is that test_passvalue() is the only function defined to create a new scope when it is called.
Code:
[h: defineFunction("test_passvalue", "test_passvalue@this", 0, 1)]
[
h: defineFunction("test_passname", "test_passname@this", 0, 0)]
[
h: defineFunction("test_returnvalue", "test_returnvalue@this", 0, 0)]
[
h: defineFunction("test_returnname", "test_returnname@this", 0, 0)] 


Here's the meat of it, not that it's a lot to look at. The inner loop needs to be changed slightly for each test as follows: (since I just wanted a quick test I just edited it by hand each time).

To test pass by value:
Code:
[h, COUNT(testCount): test_passvalue(testObject)] 


To test pass by name:
Code:
[h, COUNT(testCount): test_passname("testObject")] 


To test return by value:
Code:
[h, COUNT(testCount), CODE: {
 [h: tempVal = test_returnvalue("testObject")]
 [h: returnVal = tempVal]
}]
 


To test return by name:
Code:
[h, COUNT(testCount), CODE: {
 [h: tempVal = test_returnname("testObject")]
 [h: returnVal = eval(tempVal)]
}]
 


Code:
[h: testObject = json.append("[]", 0)]
[
h: testMaxSizeExp = 16]
[
h: testCount = 100]
[
h: timeResults = ""]

[
h, COUNT(testMaxSizeExp), CODE: {
  [h: testObject = json.merge(testObject, testObject)]
  [h: preTime = json.get(getInfo("client"), "timeInMs")]
  [h, COUNT(testCount): test_passname("testObject")]
  [h: postTime = json.get(getInfo("client"), "timeInMs")]
  [h: timeResults = listAppend(timeResults, postTime - preTime)]
}]

[
r: timeResults] 


Then the various test functions, which are all very, very simple two line functions that just take a value or return a value.
Code:
... test_passname() ...
[
h: testedObject = eval(arg(0))]
[
h: macro.return = 1]

...
 test_passvalue() ...
[
h: testedObject = arg(0)]
[
h: macro.return = 1]

...
 test_returnname() ...
[
h: testedObject = eval(arg(0))]
[
h: macro.return = "testedObject"]

...
 test_returnvalue() ...
[
h: testedObject = eval(arg(0))]
[
h: macro.return = testedObject]
 


Top
 Profile  
 
User avatar  Offline
Deity
 
Joined: Tue Nov 10, 2009 6:11 pm
Posts: 7789
Location: Bay Area
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 9:11 pm 
Barrodin wrote:
aliasmask wrote:
I'm curious to see the test code you used to run this test. How many keys were in the object and how big was the data?


The initial object was a JSON Array with a single entry (0).

On each loop, that JSON Array was merged with itself, doubling the size of the object to be passed (hence the *2^n notation on the object size axis). On the last loop the array would have been 65536 entries long, all of which would be identical. At some point I'll try it with more complex objects to see if it affects the times any, but not for now I think.

Code to follow shortly, just need to load up Maptool.

Cool. I've done some testing myself here and discovered, but didn't really emphasis it, that passing the large array slowed down my testing.

Something just occurred to me. Since you're just passing the name then evaluating, does that mean you're using a UDF where it doesn't have it's own scope? I suppose if the UDF didn't know which variable to process from the parent then that would be useful, otherwise you could just use the actual variable inside the UDF without having to eval. I'm just trying to think of an instance where this could be useful to me. How did you run across the need to do this?

_________________
Downloads:


Top
 Profile  
 
 Offline
Kobold
 
Joined: Thu Aug 18, 2011 9:51 am
Posts: 16
 Post subject: Re: Macro Best Practices
PostPosted: Mon Aug 29, 2011 9:19 pm 
aliasmask wrote:
Something just occurred to me. Since you're just passing the name then evaluating, does that mean you're using a UDF where it doesn't have it's own scope?


Yep, the trick revolves around keeping the JSON object in the local scope instead of passing it into a new scope (which, because of the way UDF's work, means transforming it into a string and then back again each time).

aliasmask wrote:
I suppose if the UDF didn't know which variable to process from the parent then that would be useful, otherwise you could just use the actual variable inside the UDF without having to eval.


Yeah, the main thing I saw this being used for is moving bits of reusable code out into their own functions without the performance hit for passing JSON objects. I chose to do the whole eval and assign deal because I specifically didn't want it to require me to remember the name of variables -inside- the function when I was writing code that called the function. By passing a variable name and evaluating it inside the function (and vice versa on the return), I can avoid either side having to have "magic names" for the input and output variable.

aliasmask wrote:
I'm just trying to think of an instance where this could be useful to me. How did you run across the need to do this?


Honestly? I'm just a bit of an odd duck. I was working on a dice roller that involves JSON objects, and the idea of it being even a miniscule fraction of a second slower bothered me (after all, I might someday be using that dice roller library for something that needs random rolls on a much larger scale, so I'd rather plan ahead a bit.)


Top
 Profile  
 
User avatar  Offline
Deity
 
Joined: Fri Mar 20, 2009 4:40 am
Posts: 9318
Location: Netherlands
 Post subject: Re: Macro Best Practices
PostPosted: Tue Aug 30, 2011 2:02 am 
you could have saved yourself the time by reading this: Speed_Up_Your_Macros

_________________
GETTING STARTED WITH MAPTOOLS - TUTORIALS, DOCS, VIDEOS, TOOLS, ETC

My stuff
Excel Tools: Table and Light editors
MT Tools: Bag of Tricks: Tools for Maptool, Dungeon Builder I, Dungeon Builder II,onMouseOverEvent and
DPI.
Frameworks: Dark Heresy, Rogue Trader, Deathwatch, Black Crusade, Only War, SET Card Game, RoboRally
Wiki: Debugging Tutorial, Speed Up Your Macros, Working With Two CODE Levels, Shortcut Keys, Avoiding Stack Overflow, READ THIS


Top
 Profile  
 
 Offline
Kobold
 
Joined: Thu Aug 18, 2011 9:51 am
Posts: 16
 Post subject: Re: Macro Best Practices
PostPosted: Tue Aug 30, 2011 2:23 am 
wolph42 wrote:
you could have saved yourself the time by reading this: Speed_Up_Your_Macros


Eh, that doesn't cover what we were fooling with here. While that covers some methods of storing and retrieving a JSON being faster or slower than others (and is part of what made me wonder about this whole subject in the first place), it doesn't cover this name + eval() method of passing a JSON object to a local-scope user defined function.


Top
 Profile  
 
User avatar  Offline
Deity
 
Joined: Fri Mar 20, 2009 4:40 am
Posts: 9318
Location: Netherlands
 Post subject: Re: Macro Best Practices
PostPosted: Tue Aug 30, 2011 2:58 am 
Barrodin wrote:
wolph42 wrote:
you could have saved yourself the time by reading this: Speed_Up_Your_Macros


Eh, that doesn't cover what we were fooling with here. While that covers some methods of storing and retrieving a JSON being faster or slower than others (and is part of what made me wonder about this whole subject in the first place), it doesn't cover this name + eval() method of passing a JSON object to a local-scope user defined function.


*rereads (better this time)*... indeed, my bad, in that case, maybe you want to update that part of the wiki with your findings!!

_________________
GETTING STARTED WITH MAPTOOLS - TUTORIALS, DOCS, VIDEOS, TOOLS, ETC

My stuff
Excel Tools: Table and Light editors
MT Tools: Bag of Tricks: Tools for Maptool, Dungeon Builder I, Dungeon Builder II,onMouseOverEvent and
DPI.
Frameworks: Dark Heresy, Rogue Trader, Deathwatch, Black Crusade, Only War, SET Card Game, RoboRally
Wiki: Debugging Tutorial, Speed Up Your Macros, Working With Two CODE Levels, Shortcut Keys, Avoiding Stack Overflow, READ THIS


Top
 Profile  
 
User avatar  Offline
Cave Troll
 
Joined: Wed Oct 12, 2011 1:28 am
Posts: 78
 Post subject: Re: Macro Best Practices
PostPosted: Sat Oct 15, 2011 8:28 am 
Barrodin wrote:
Keep in mind that any variables in a function will overwrite functions in the macro from which it is called, so be conservative creating new variables and always use a distinctive name (I tend to add the prefix local_ to the variable names inside such functions, as a reminder). If you do decide to use this trick it is probably best to create as few variables inside the fucntion as possible, to avoid the possibility of collisions.


Barrodin,

I'm trying to wrap my head around this. Are you saying that if I had the following code, the output of varX would be 20 and not 10?

Code:
[h: testObject = json.set("{}", "Key 1", value1, "Key 2", value2, ... , "Key N", valueN)]
[h: varX = 10]
[h: test_function("testObject")]
[varX]

... Inside test_function ...
[h: local_testObject = eval(arg(0))]
[h: varX = 20]


Thanks.

_________________
My Stuff:
-- Easy navigation Maptool macro function doc
-- Bracket Checker
-- Notepad++ code completion for maptool macro language


Ramblings of a Dead Marshal: http://louis-davout.blogspot.com/


Top
 Profile  
 
User avatar  Offline
Great Wyrm
 
Joined: Tue Aug 23, 2011 10:41 am
Posts: 1134
Location: Cornwall, UK
 Post subject: Re: Macro Best Practices
PostPosted: Sat Oct 15, 2011 8:32 am 
davout wrote:
Barrodin wrote:
Keep in mind that any variables in a function will overwrite functions in the macro from which it is called, so be conservative creating new variables and always use a distinctive name (I tend to add the prefix local_ to the variable names inside such functions, as a reminder). If you do decide to use this trick it is probably best to create as few variables inside the fucntion as possible, to avoid the possibility of collisions.


Barrodin,

I'm trying to wrap my head around this. Are you saying that if I had the following code, the output of varX would be 20 and not 10?

Code:
[h: testObject = json.set("{}", "Key 1", value1, "Key 2", value2, ... , "Key N", valueN)]
[h: varX = 10]
[h: test_function("testObject")]
[varX]

... Inside test_function ...
[h: local_testObject = eval(arg(0))]
[h: varX = 20]


Thanks.


As far as I understand it, it all depends if you defined test_function with newScope = 1 or newScope = 0. See Wiki: defineFunction()

To further clarify,:
when defining test_function if newScope is set to true(1), then in your example varX will be output as being 10.
when defining test_function if newScope is set to false(0), then in your example varX will be output as 20.

When using newScope as true, you can only return items through macro.return.

corrected to be correct

_________________
How to get around the two code nest limit in MapTool (and MOTE)


Last edited by Bone White on Sat Oct 15, 2011 9:18 am, edited 1 time in total.

Top
 Profile  
 
User avatar  Offline
Cave Troll
 
Joined: Wed Oct 12, 2011 1:28 am
Posts: 78
 Post subject: Re: Macro Best Practices
PostPosted: Sat Oct 15, 2011 8:48 am 
Quote:
newScope - If the defined function should create a new variable scope when executed, defaults to true(1). A new variable scope means that the defined function can only read the variables of the macro that called it; if you do not create a new scope the defined function can read, update, and create variables in its parent's variable scope. Updating variables in the parent's scope includes over-writing any parameters that a parent might have stored within arg(), if a user-defined function that does not create a new scope is called within another user-defined function.

Ok now what aliasmask and Barrodin said makes since.
aliasmask wrote:
Since you're just passing the name then evaluating, does that mean you're using a UDF where it doesn't have it's own scope?

Barrodin wrote:
I chose to do the whole eval and assign deal because I specifically didn't want it to require me to remember the name of variables -inside- the function when I was writing code that called the function. By passing a variable name and evaluating it inside the function (and vice versa on the return), I can avoid either side having to have "magic names" for the input and output variable.


:shock: Oh my that is major mind shift from other languages.

Thanks.

_________________
My Stuff:
-- Easy navigation Maptool macro function doc
-- Bracket Checker
-- Notepad++ code completion for maptool macro language


Ramblings of a Dead Marshal: http://louis-davout.blogspot.com/


Top
 Profile  
 
User avatar  Offline
Deity
 
Joined: Tue Jul 01, 2008 6:48 pm
Posts: 6237
 Post subject: Re: Macro Best Practices
PostPosted: Sat Oct 15, 2011 8:57 am 
Bone White wrote:
davout wrote:
Barrodin wrote:
Keep in mind that any variables in a function will overwrite functions in the macro from which it is called, so be conservative creating new variables and always use a distinctive name (I tend to add the prefix local_ to the variable names inside such functions, as a reminder). If you do decide to use this trick it is probably best to create as few variables inside the fucntion as possible, to avoid the possibility of collisions.


Barrodin,

I'm trying to wrap my head around this. Are you saying that if I had the following code, the output of varX would be 20 and not 10?

Code:
[h: testObject = json.set("{}", "Key 1", value1, "Key 2", value2, ... , "Key N", valueN)]
[h: varX = 10]
[h: test_function("testObject")]
[varX]

... Inside test_function ...
[h: local_testObject = eval(arg(0))]
[h: varX = 20]


Thanks.


As far as I understand it, it all depends if you defined test_function with ignoreOutput = 1 or ignoreOutput = 0. See Wiki: defineFunction()

To further clarify,:
when defining test_function if ignoreOutput is set to true(1), then in your example varX will be output as being 10.
when defining test_function if ignoreOutput is set to false(0), then in your example varX will be output as 20.

When using ignoreOutput as true, you can only return items through macro.return.



Wouldn't it depend on whether it was a new scope, not whether it was ignore output? That is, if you have varX in one macro, and call a new macro with the same scope and assign a new value to varX, then varX will change. If the called macro has a new scope, then varX in the called macro has no affect on varX in the calling macro. Or did I miss something earlier?

_________________

What I'm Working On

MapTool Tutorials:
Introduction to Tokens
Introduction to Properties
Introduction to Macro Writing
Introduction to Light and Sight


Top
 Profile  
 
Display posts from previous:  Sort by  
Reply to topic  [ 99 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7  Next

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:

Who is online

In total there are 2 users online :: 0 registered, 0 hidden and 2 guests (based on users active over the past 5 minutes)
Most users ever online was 243 on Sun Nov 04, 2012 6:14 am

Users browsing this forum: No registered users and 2 guests





Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group

Style based on Andreas08 by Andreas Viklund

Style by Elizabeth Shulman