Welcome to Keen Software House Forums! Log in or Sign up to interact with the KSH community.
  1. You are currently browsing our forum as a guest. Create your own forum account to access all forum functionality.

Understanding what contributes to script complexity

Discussion in 'Programming Questions and Suggestions' started by Tony Hughes, Jan 31, 2015.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. Tony Hughes Junior Engineer

    Messages:
    715
    This is a request for information:

    I've written a fairly lengthy, moderately complex and admittedly not yet very optimised script that under certain conditions (not all) accesses a lot of blocks, does some processing and then hits the code complexity error.

    I'd like to optimise my code effectively, to ensure that it can be used in the maximum number of scenarios, however the error message displayed is not very helpful in pin-pointing what most needs to be improved or by how much I have over-run the limit.

    According to the steam Help file on the in-game editor, the count that determines whether you've reached the limit is based on the number of instructions in the code, as seen below:


    My first question for anyone in the know is, are the instructions mentioned the number of actual statements in the source code or are they the number of MSIL instructions generated once the code has been compiled?

    Do the built in API calls provided by Keen count as just one instruction each or were I to access an API function that returned a thousand blocks in a list would that contribute a thousand instructions (perhaps more?) to my total?

    Is there anyway to tell how much each statement, line or section of my code is contributing to the instruction count for debugging and optimisation purposes?

    Is the instruction limit static or dynamic, as in, will the number of instructions that I'm allowed to run vary if for instance there are too many scripts running or if more resources are needed by the game engine itself?

    If it's static, what are the current limitations?

    I've tried catching the error raised, without much expectation of that really working, and haven't been able to. Is there anyway for me to catch the error, so that I can exit out of a script more gracefully once it has occurred?

    I hope that someone can spare the time to help me, as I'm concerned that any refactoring effort I make may inadvertently cause the problem to get worse as I don't understand the mechanisms that are in play and I am hesitant about releasing code that I don't know or understand the limitations of.
     
  2. Phoera Senior Engineer

    Messages:
    1,713
    IL instruction.
    game count only your IL.
    possible but i don't recomment you, hard way.
    static.
    50000 IL instructions.
    nope.

    i use state machine and limit my loops.
     
  3. Tony Hughes Junior Engineer

    Messages:
    715
    Thanks for responding; that's really useful and I think you have probably answered my questions completely.

    I'd just like to clarify the API point though, if I were to use the following on 100,000 blocks:

    Code:
    var result = GridTerminalSystem.GetBlockWithName("Blah");
    then it would be OK and not cause the code to be too complex, while calling the function below might cause it to fail even though they're probably doing more or less the same thing in the background and generating roughly the same amount of IL instructions?

    Code:
    var result = GetBlockByName(GridTerminalSystem.Blocks, "Blah");
    
    Code:
    public IMyTerminalBlock GetBlockByName(IList<IMyTerminalBlock> searchedBlocks, string searchName)
    {
                    for (var block = 0; block < searchedBlocks.Count; block++)
                    {
                        if (searchedBlocks[block] != null)
                        {
                            if (searchedBlocks[block].CustomName.ToLower().Contains(searchName.ToLower()))
                            {
                                return searchedBlocks[block];
                            }
                        }
                    }
                    return null;
    }
    
    When using the API version, it presumably doesn't matter whether there's one block in the searched grid or 100,000 blocks as it won't contribute proportionally to my own complexity count?

    If so then I guess that means that I really do need to focus on using Keens calls wherever possible instead of my own custom versions.

    I can see the advantage of using a state machine to break apart script execution and will probably go down that route if I can't optimise sufficiently for some reason.

    To that end; do you know if the complexity count is literally based on the number of executed instructions only or the number of instructions that could potentially be executed (i.e. it's doing static analysis of the code up-front rather than basing it on a running total)? In other words, if I were to use a script that had the above GetBlockByName function in it, but broke it apart using a state machine so that a maximum of only 10,000 blocks were processed in the for..next loop on each run of the script it would probably be OK? EDIT: Bad Example. Please ignore it.

    Better example of what I'm trying to find out:

    Assume I have a function that has a condition leading to two very different execution paths contained within it; one path which is very heavy and which will almost certainly cause the complexity error and one which is very light and won't. The path chosen is dependent upon a value that can only be obtained at run-time and so the IL can't be optimised in advance to exclude one branch or the other by the compiler.

    If the light path was the only one that ever ran in reality, due to the run-time conditions never being right to activate the heavy path, then would that function contribute an IL count to the complexity total, based on the total of both paths or just the light one?

    Sorry if I'm being a bit pedantic here, but it does make quite a big difference to how I optimise my code, not just in this project but any others I do in future.
     
    Last edited by a moderator: Feb 1, 2015
  4. Phoera Senior Engineer

    Messages:
    1,713
    as i say upper, counted only your IL, API IL not counted.
     
  5. Tony Hughes Junior Engineer

    Messages:
    715
    Thanks again and it looks like you're right. It doesn't seem to count API IL towards complexity.

    I forgot that I could try it in Creative mode (I normally run survival). So I did a little test and built a stack of 20,000 small cargo containers, before running variations of the above functions on it.

    The API mode version worked fine. The custom one hit the complexity error.

    When I tried using a run-time based condition to choose which method to use, it worked when the execution path used the API version and didn't when it used the custom version execution path.

    So it looks like it keeps a running total of the number IL instructions executed and doesn't just lump everything in the same function together. That's good.
     
  6. hellokeith Apprentice Engineer

    Messages:
    335
    You can also internally count your own loops. Just set a loop limit, test for it, if you reach it then save your state and exit.
     
Thread Status:
This last post in this thread was made more than 31 days old.