• I'm trying to compile a watch face that includes the following code to change the background colour as a simple low battery warning:

    g.setBgColor((bngl && E.getBattery()<10)?63488:(g.theme.bg))

    When compiled this gives:

    WARNING: Function marked with "compiled" uploaded in source form
    [ COMPILER MESSAGE ] : Error: Infer(unforced) kept changing stuff

    If the line is commented out the warning doesn't appear and the compiled version runs.

    What causes the error and is there a way around it? Thanks in advance.

  • Nowadays using new "jit" feature may be good enough to speed things up, can you try replace "compiled" by "jit" and see if speed is good enough? "compiled" makes sense mainly for pure data processing like many math operations in a loop, also it is a bit buggy and the js code should be relatively simple for it to work correctly. Also it produces quite bloated native code. I'd say it is last resort when every other optimization fails.

    BTW it is just a warning, does it not work?

    you can try replacing the ? : operator by simple if else construct

  • BTW did you check https://www.espruino.com/Compilation sections "Caveats" and "Doesn't Work"? Also the "How do I use it?" shows type of code that makes sense to use with "compiled" - tight computational loops, hardware access. it is not worth it for random generic js code. Also beware that you cannot distribute your app in sane way, it probably won't work at all with the bangleApps loader. There is workaround for small bits of Inline C, see
    https://github.com/espruino/BangleApps/s­earch?q=%22compiled%22 however "compiled" JS has more issues than inline C and the binary won't work like this across different firmware versions due to value of process.env.EXPTR being different in each firmware build. I have solution for this but it is not pretty and in most cases not worth it.

  • Thanks @fanoush.

    The error from "compiled" stops it working and the code is just uploaded as source.

    I have other problems with "jit": it seems not to like '&&' both on the line in question and elsewhere in my code:

    JIT SyntaxError: Got && expected EOF
     at line 3 col 28
            g.setBgColor((bngl && E.getBattery()<10)?63488:(g.th...

    The following test gives me the same error:

    function test() {
      print((true && false)?'y':'n');

    I do have many maths options in a loop: I'm making a version of https://www.youtube.com/watch?v=IA4UsV04­bnM
    and am rotating 128 lines - there's a couple of screenshots below. I've tried to optimise the code anyway by precomputing the rotated lines, using Int8Arrays and Float32Arrays etc. What's left in the loop is therefore pretty simple arithmetic, indexing into the arrays and comparisons but quite a lot of them. Without compiling I get roughly 1 loop per sec, with I get between two and three per sec so a really good improvement.

    2 Attachments

    • p1.jpg
    • p2.jpg
  • OK, can you show whole method you are trying to compile? it is worth to restructuring it so only the computational part is inside "compiled" and the code mostly looks like pure C. You may also consider Inline C which produces much smaller and faster code and is easier to distribute.

    InlineC is not easy when you need to call into JS methods or use JS variables but for passing data in/out there are workarounds with passing flat array pointers. Recently I tried to use "compiled" code and basically I only took the result of the compiler as inspiration and used it directly inside Inline C. Also I needed to hack the compiler to not to hardcode value of EXPTR inside the binary so it can work across different build versions.

  • Sorry, I meant to say that I had looked at the page on compilation and noted the warnings although I hadn't realised that the loader wouldn't work. I'm still some way off being able to distribute the code, though!

  • I think the best way is to use "jit", if && does not work then maybe @Gordon can look into it?

    If the performance in not good enough I'd use Inline C by doing the math inside native method with just data passed in/out.

    "compiled" is a dead end IMO, only if you cannot easily restructure the code and really need to call into other js methods or access js variables then it makes sense looking into it.

    In my case I wanted to code SWD protocol in pure JS. After prototype which is available here https://github.com/fanoush/EspruinoBoard­s/blob/master/STLINKV2/swd.js I tried to use "compiled" for some parts to speed it up but quickly hit some limitations and also noticed that the native binary code crashes in other device due to EXPTR being different. My current WIP code snapshot is here https://gist.github.com/fanoush/4a5dcf77­7503461297cedf7e21e3c6b3 lines 44-139 contain bits inspired from JS compiler output. I wanted to use Pin objects so the native code works both on STM32 and nrf52 platforms without coding native GPIO HW stuff for each platform.

  • Many thanks for your help and I'm happy to follow your guidance about "compiled". I'll have a further look at jit and see if I can get that working.

  • Hi,

    That clock face looks amazing!

    As @fanoush said, I think probably the best thing is to look at using jit if possible, but...

    If you change:

    g.setBgColor((bngl && (E.getBattery()<10))?63488:(g.theme.bg))­
    // to
    g.setBgColor((bngl==true && (E.getBattery()<10))?63488:(g.theme.bg))­

    Then it looks like that'll fix it. It'll be some issue with the compiler having trouble figuring out the type of bngl - but as @fanoush says the focus is really on trying to get jit good now, so that may not end up getting fixed unless someone else wants to jump in and look at it (https://github.com/gfwilliams/EspruinoCo­mpiler)

    Right now as you mention jit doesn't handle &&. It got left out because it's non-trivial to do it right. I'm super busy this week so don't have time for it but I filed an issue for it at https://github.com/espruino/Espruino/iss­ues/2313 - in the mean time you may just be able to use & instead.

    Definitely just try and pull out only the bit of code that needs to run fast and jit/compile that, and don't do anything that doesn't need it. I know the temptation is just to slap jit/compile/ram on everything, but in reality that will use a bunch of RAM and can actually make things slower (especially first startup) if it works at all! It's best to be as targeted as you can be with it.

  • Thanks, @Gordon. i'm afraid I'm still struggling: another line in my program contains:

    if (dest==2 && y>1 && y<5) {...

    which gives the same error. I've tried adding parentheses as in your suggestion, eventually ending up with abominations like

    if (((dest==2)==true) && (((y>1)==true) && ((y<5))==true)) {...

    but all these variants gave the same error. Frustratingly, just including the offending line in a simple test program works perfectly so the problem must be due to something elsewhere in the code. I will try to sort it out.

    I'm afraid I've been doing exactly what you and @fanoush warn against, sticking "compiled" on the entire draw loop. This runs at 5 frames per second versus about 1.5 for raw or vanilla. So while I don't want ignore your advice , I'm loathe to give up the extra speed - it will be interesting to see what JIT delivers when I can get that working.

    My use of the watch is entirely focused on interesting watch faces - I have very few other apps installed so RAM usage and startup speed aren't really issues. I would like to contribute something to the community, however, so when I have this face working properly I hope to publish it.

  • but all these variants gave the same error

    There are two issues

    • "compiled" sometimes cannot determine right data type of variable, for that bngl==true instead of just bngl helps as this forces type to bool while bngl can be anything. Same trick for forcing integer type would be something|0

    • "jit" has operator && not implemented so you need to replace that. & is "bitwise and" which results in number instead of bool but otherwise works

      >true && false
      >true & true
      >true & false
      >null & false
      >undefined & 1
      >false & 5
  • Thanks @fanoush, shows how well I know Javascript! Much appreciated, I hope I can now fight it to a standstill.

  • maybe with numbers beware that bitwise and may not behave exactly as &&, see true & 4 below (true is conveted to value 1 and 1&4=0) so it makes sense to convert numbers into bool expression like you did with E.getBattery()<10 so if (width & whatever) should better be if (width>0 & whatever)

    >false & 5
    >true & 5
    >true & 4
    >true & 4!=0
  • I'm loathe to give up the extra speed

    I think you may find that you don't actually end up losing much speed at all. Espruino's not that much slower than compiled/JIT when it comes to simple function calls - it's more when you get to loops and calling the same stuff over and over that it's not so great.

    Also while doing everything might be marginally faster, it's likely to be a lot slower at boot time when the compiled code has to be loaded into RAM from flash...

    So you're likely to make life a lot easier for yourself if you can figure out which bits are taking time and optimise just those :)

    One thing to add which might really help you - I guess you're using g.drawLine a lot? If you do: var dl = g.drawLine.bind(g); ... dl(x1,y1,x2,y2) then you'll allow Espruino to skip looking up drawLine on g for each draw call - which should save you a bunch of time for all code - JIT/compiled or even normal.

  • Thanks, both. The comparisons are working in line with @fanoush's guidance and I'd already bound calls to Math.xxx, I will bind g.xxx as well - I will get there eventually!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

[ COMPILER MESSAGE ] : Error: Infer(unforced) kept changing stuff

Posted by Avatar for BillV @BillV