Author Topic: Execution chains  (Read 413 times)

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Execution chains
« on: November 23, 2012, 06:11:41 pm »


                <seeking...>

TMI. Too Many Instructions. *sigh*

Ok, I'm trying to compartmentalize my scripts so I don't hit the TMI. Luckily, I've structured the Regional Mod system in a somewhat hierarchal fashion.  

The thing is, there's a (conceptual) limit of 10,000 nodes. Each node might reference any one of (hundreds) of template areas, which each might have (dozens) of WPs. Just storing the Node Biomass (one per node) and the WP biomass adjustments (one per WP in template area per node) is probably looking at about a milllllllllion integers. I'd also like to cache the area tag, name and handle (object) for each node.

With my first, rough, script assigning biomass adjustments to WPs I got to Node 8 before hitting TMI. Eight out of a potential ten thousand. Ouch.

Now I've divided up the scripting somewhat and I manage to handle 25 nodes using 5 areas with a couple hundred WPs without hitting TMI... But I know I won't reach 10,000. And there's something bugging me... When I hit TMI before, it gave the offending script (reg_node_setup), but then it listed the script run on the Housekeeper that called reg_node_setup and gave the same TMI warning.

I'm hoping that was just the return value of the ExecuteScript coming back to roost, but here's the question (which I will sooner or later discover the hard way); Do the instructions executed by child scripts count toward the parent script's TMI limit? Is all my divvying up a waste of time?

Currently the Mod onLoad executes a script on the Housekeeper who loops through all the nodes and executes scripts on them one at a time that loops through executing a script on areas,. Mod->Housekeeper->node->area.
All so I can setup the variables on WPs in Areas.

Note: This is not a deal-breaker, as I fully intend to incorporate NwNx db in the system, but I'd really like to get it working with vanilla NwN first.

<...too much information>
               
               

               


                     Modifié par Rolo Kipp, 23 novembre 2012 - 06:24 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Execution chains
« Reply #1 on: November 23, 2012, 06:40:41 pm »


               when you call script B from script A via ExecuteScript("B", oObject);

The instruction count does not get reset. You are still running in the same execution block.

Once script A finishes the instruction count will be the count of all the instructions executed by both script A and B.

Keep in mind the the VM also has a "return" array, that if memory servers has a limit of 128 'return values" that will limit the depth of Functions/Scripts calls.

Your solution is to not run the script within the script but to run it on its own.

i.e.
Delaycommand( 0.1, ExecuteScript("B", oObject));
               
               

               


                     Modifié par Lightfoot8, 23 novembre 2012 - 06:41 .
                     
                  


            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Execution chains
« Reply #2 on: November 23, 2012, 07:19:03 pm »


               

Lightfoot8 wrote...
...
Your solution is to not run the script within the script but to run it on its own.

i.e.
Delaycommand( 0.1, ExecuteScript("B", oObject));


  In a case where commands are delayed, and not necessarily being called by the object that will be executing them, do you think it would be better to assign them to the object in question or module instead?

  For instance:
    AssignCommand (GetModule(), DelayCommand (0.1, ExecuteScript ("B", oObject))); 
  or:
   
AssignCommand (oObject, DelayCommand (0.1, ExecuteScript ("B", oObject)));

  I know in cases where the calling object is destroyed it clears any delayed scripts that would have run on it, and in those cases specifically it's the better way, but procedurally would there be any real benefit to handling it that way all the time?
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Execution chains
« Reply #3 on: November 23, 2012, 10:46:42 pm »


               <thinking about cloning...>

@ LF: That makes a lot of sense to me. And if I need to put a DelayCommand or AssignCommand wrapper around my scripts, I'll do that.

Might actually work out all right...

Hmmm...

@ FB:  I can not say from any kind of profiling research, but there are quite a few functions that do not work correctly on module or area objects. Using a housekeeping creature object seems to me to allow for more control of the object, not least-wise setting the AI level so the housekeeper can allow at least a little ingame resource management, if that makes sense.

Also, creature/placeable/item objects seem quite a bit easier to export/import, which may become important script-wise with richer inter-server communication.

I'll put the Reg Mod POC WIP up sometime this weekend for the Amethyst Tapestry group to pick over (going to rethink the Db setup in light of this little discussion).  

If nothing else, you guys can have a good laugh :-)

<...things that clone things>
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Execution chains
« Reply #4 on: November 24, 2012, 12:27:01 am »


               Im trying to find the time to dig into this a little bit more,  I just have not fount that much time yet.  

@Rolo what  functions don't work correctly on module or area objects?
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Execution chains
« Reply #5 on: November 24, 2012, 12:55:23 am »


               <caught with a "borrowed" spellbook...>

Uggh. Trust you to ask that when I'm visiting, away from my goodies :-P
Every once in a while I come across a function that warns "Do not use this on module or areas" or "gives an OBJECT_INVALID response when used on modules or areas".

The only one that comes to mind is rather trivial - SetName. You can't change the name of an area. Would have been mighty handy for the Reg Mod since one area represents so many different nodes. :-P

The other thing, and the reason I mentioned that here, is that we have no native function for saving areas, but we can save creatures/items/placeables... Which means deconstructing an area, saving the pieces and retrieving the pieces and reconstructing it on the other end.

Where this comes into play for the Reg Mod is that each WP in a template area will have variables stored on it for every node it services (but only put *on* it if the node wakes up (is visited or activated by the plot system)).

For the potential test case of a 50x200 node region (my target for the Walking Woods) - some ten thousand nodes represented by about a 100 templates - each WP will average about a hundred sets of variables. Figure a median of around 75 WPs per template and you have 3/4 of a million *sets* of variables.

NwScript won't even let you loop through that many, let alone *do* anything with them.  But if the Housekeeper DelayCommands each area to DelayCommand each WP into finding which node references it. Or if a keeper object generated for each node sorts through the WPs it references...

As FB mentioned elsewhere, how we segment the data is going to be very... interesting :-)

And I like the idea of putting a convo on the oKeeper that lets DMs/PCs with DM privileges talk to her and give her suggestions (you *don't* order a goddess, right?) ;-)
Can you picture the Green Lady surrounded by drifting Will-o-wisps that are managing active nodes and asking Her to stir in a bit of excitement somewhere... ?

<...and his hands full of sweet potato pie>
               
               

               
            

Legacy_Zarathustra217

  • Sr. Member
  • ****
  • Posts: 322
  • Karma: +0/-0
Execution chains
« Reply #6 on: November 24, 2012, 08:04:29 am »


               I'm a bit unsure exactly how to understand the system you are building, so bear with me if this isn't relevant. But for storing large amounts of data you want to quickly search through, I wonder if it would pay off to compile it into a large string variable that you then search through with the native NWscript commands for that - under the reasoning that the build in commands often seem quite performance effective.

Also, I figure you are probably aware, but putting it out anyway:

To overcome the TMI limit with wrapping it into an ExecuteScript and DelayCommand, you don't need any actual delay for it to work - 0.0 is fine. Keep in mind though that ExecuteScript isn't the fastest function, so if you need to run this often and in very large scale, it might be worth looking into having each instance of the script call in your loop run through a number of instances of whatever function you want to process. E.g. on our PW's initialization phase, we in this way run through batches of 50 waypoints, setting them up.

And using AssignCommand on the module works fine, though if you are making a loop, simply assigning the first script call to the module saves you from all the consecutive assigning.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Execution chains
« Reply #7 on: November 24, 2012, 06:10:59 pm »


               <turning the tables...>

There are two reasons I didn't want to use a string array to hold all those ints.
The first is I simply hate the overhead in manipulating ints to string, fiddling with strings then converting to ints again.
The second (and the primary reason for the first) is that I plan for adoption of NwNx and a real MySQL db. I'll want to deal with ints then and disentangling them from the string arrays would be another hoop I don't want to jump through.
A third, trivial reason is ints don't bloat the BDb, strings & objects do.

<...on the moneychangers>
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Execution chains
« Reply #8 on: November 24, 2012, 08:02:46 pm »


                 I have to agree on the string arrays instead of ints.  Building and parsing string arrays can be done faster than a local int can be retrieved when there's thousands of them on a single object.

  The conversion can be quite simple as well.  Though this is from a different use, here's an example of setting them up, when you only need 0-999 support in it.

string sTemp;
// Body parts.
for (i = 0; i <= 20; i++)
   {
    nTemp = GetCreatureBodyPart (i, oCopy);
    if (nTemp < 100) sTemp += "0";
    if (nTemp < 10)  sTemp += "0";
    sTemp += IntToString (nTemp) + "_";
   }
SetLocalString (oItem, sNumber + "APPEARANCE", sTemp);

And retrieving by:

int i, nPos, nVal;
 
// Set Body Parts.
for (i = 0; i <= 20; i++)
   {
    nPos = i * 4;
    nVal = StringToInt (GetSubString (sApp, nPos, 3));
    SetCreatureBodyPart(i, nVal, oPC);
   } 

Likely you'd need to make it store the growth chain as well as the chain to be used itself, and the only tricky part there is that it's 0-10, so you'd need to use either an if to manually convert to/from "A" for the 10, or a hex substring parser for the whole conversion.

Still, the reduction in variable count on the object itself would be well worth it performance wise, even if you store them as ints in the bioware database itself.