4.1.4 Compiler 2 Beta code size comparsion

I compared the old compiler (4.1.4) with the new compiler (4.1.4 Compiler 2 Beta - https://forums.garmin.com/developer/connect-iq/b/news-announcements/posts/optimal-monkey-c)
                                    curr,peak,global,code,data,entry,settings,
old compiler, old sim:   26.0,27.2,1926,10960,4597,4094,1152
old compiler, new sim: 26.2,27.4,1614,10960,4597,4094,1023
new without params:   26.1,27.3,1614,10932,4600,3998,1023
new with -O 0:             26.2,27.4,1614,10960,4597,4094,1023
new with -O 1:             26.1,27.3,1614,10932,4600,3998,1023
new with -O 2:             24.8,26.1,1553,9988,4384,3963,1023

Some things to note:
- I was using -l 3 in all cases
- I had to "fix" or maybe "hack" some errors that appeared with the new compiler
- I'm not sure about the differences between old compiler old sim, new compiler new sim (it was probably a mistake, it happened because I tried the new compiler, new sdk, and it opened the sim, but later I switched back to 4.1.4 and forgot to close the sim)
- the default for the new compiler is -O 1 (not -O 0 !!!)
- I can hardly imagine any reason (unless we find some bug in the compiler that happens only in -O 2) why anyone would not use always -O 2
  • No doubt, memory will be increased when moving code to a function. And if you only call that function once, that memory would be saved by inlining. No argument. 

    But, I don't see how you can save memory by inlining a function that is called many times. 

    Can you offer an example of when that might occur with a non-trivial but not OOP (see above) example?

  • (:no_api2, :memory16K, :inline)
    function setConfig(key as PropertyKeyType, val as PropertyValueType) as Void {
      MyApp.setProperty(key, val);
    }
    (:api2, :memory32K, :inline)
    function setConfig(key as PropertyKeyType, val as PropertyValueType) as Void {
      Properties.setValue(key, val);
    }
    these (one of them) are either called twice or 3 times from my code (depending on the device memory and api as you can see from the annotations). I can't inline them manually because that would mean I'd need to copy 3 huge functions to have their 2 different versions just because of this 1 line difference, so that explains why to split them to a function instead of inlining manually. And by using https://marketplace.visualstudio.com/items?itemName=markw65.prettier-extension-monkeyc I can still inline them, and with that spare the few 10s of bytes by not declaring the function (because inlining removes it) and not having to call setConfig and pass the parameters also saves some more. All this is even more true if you call setConfig from even more places.

  • I hate to be picky, but I really don't think that constitutes a non-trivial example:

    1) The functions are only one-liners with quite  big arguments and

    2) you're using annotations that come from a 3rd party pre-compiler system. However I can see where the :inline annotation is a neat alternative to the more complicated jungles solution of creating multiple source files.

    I was hoping for a more generic case to support the general case that inlining doesn’t increase memory usage.

  • The only annotation that is not monkey c "proper" is the :include, and what I explained above is the exact reason I am using that and the prettier monkey c plugin. You don't have to believe me, that's your choice, but the time you waste on writing in this thread is more than what you need to test it on your own code...

  • Note that that -O 3 is valid, and there's also options to explicitly optimize performance and code space. If you pass in "-h" to the compiler you can see the args help, including:

    -O,--optimization <arg>Optimization level [0=none, 1=basic, 2=fast
                           optimizations, 3=slow optimizations] [p=optimize
                           performance, z=optimize code space]

    e.g. -O3pz is allowed.

    (Idk what actually happens when you specify both "p" and "z", but it's allowed lol.)

  • that's an interesting promo, but it looks like they intentionally didn't include it in the announcement, because I tested: -O2, -O2p -O2z, -O3, -O3p -O3z, and all of them produce the same code/data/... absolutely no difference in what I can see in the  View Memory window. The only difference maybe is that some of the builds are slower but I bet that's just a mistaken subjective time "measurement" of mine. IMHO these are features they are working on and maybe we'll see some of this implemented in the future, maybe not.

  • Would be nice to know what optimizations we can stop doing in the code now.  Are Enums just as efficient as hardcoding now?  

  • 1. this is Beta, with some bugs that we'll have to wait to see fixed.

    2. not sure if they allow code compiled with beta uploaded to the store (haven't try it yet with the new compiler but with the System 5 preview devices you couldn't)

    3. you can easily test any question like that. I know that constants can be used now without problem because I tested it.

    HOWEVER i warn you to wait with it a bit more. Yesterday I tested some things, and then I started to change the code accordingly, but then I found some other bugs, so I'm not sure I'll be able to keep using the new comiler for now, and if not then I'll need to revert the changes to still work with 4.1.4...

  • I feel like an enum use will still consume unnecessary memory, because it's a runtime symbol lookup afaik.

    Having said that I'm usually wrong with all my guesses, so hopefully the opposite is true Fingers crossed

  • Yeah, but really if you have or want to have enums just try it out and compare in view Memory.

    BTW previously (maybe in another thread) Jim wrote that if-s are faster than switch cases. Maybe, I haven't tried it out, but there is at least one place in my code where I was lucky to be able to use the nice feature of the switch that I can decide not to have a break so the flow continues, and that indeed saved some bytes. (Again haven't compare it to if-s, it might be even better if I'd refactor it...)

    switch (x) {

        case "a": do stuff;
        case "b": so some other stuff;
                       break;
        case "c": another code;

    }

    I specifically use that a and be have some common code (actually that b is a subset of a)