output buffering and character device performance

Posted on
  • I'm hitting more than one issue trying to make "large" output work on the esp8266. For example, I can't get trace() to work if there is some real stuff loaded in memory. The problems I'm encountering are two-fold: output is not event driven, and character devices are too slow.

    When trace() produces its output, it expects to be able to sit in a loop and just keep writing without ever yielding to let some other code actually send what it's writing. Because trace() will often produce many KB of text, this can't be buffered and either large portions of output have to be dropped on the floor or the system deadlocks. The net result is that I can't figure out what consumes my memory on my esp8266. Similar problems can be seen with other functions that output lots of stuff as well as with Espruino code that sits in a loop writing stuff.

    Even when dropping output, trace() still crashes the esp8266 because the character devices (such as the console) are very slow. Looking at the code, there are many, many nested function calls for each character. If trace() outputs 10KB of text and each character takes a good number of microseconds to output (or drop), then the net result is still a loop that keeps the processor busy for >10ms with the result that the watchdog timer resets everything.

    I'm not sure what to think about all the above. trace() could be refactored to be event-driven and suspend in the middle of its execution to let output drain. But this affects other things as well. Basically any piece of code that outputs more than the size of the output buffer (e.g. network buffer) will face this issue. An option for addressing the first issue would be to use an RTOS with suspendable threads.

    Other ideas?

  • Hmm, it's a difficult one - the whole queue was built around the interrupt-based comms.

    To be honest on ESP8266 we still have the problem of any function that takes too long to execute causing a reset... Refactoring every function that outputs a lot of text to avoid it seems like it'd be amazingly painful, and still doesn't solve that problem.

    I think at some point we'd talked about buffering to JsVars, but especially in jsvTrace that won't work, because it's expecting that the variables it's looking at won't be changing!

    At one point there was talk of suspendable threads - @Kolban posted up some code (maybe for FreeRTOS?) that seemed like it would be pretty easy to integrate, and that would basically solve everything?

    The only problem would be the RAM usage required to keep a separate stack for Espruino. I don't know whether it's realistic from that point of view?

  • The performance of character I/O remains a problem even if we solve the multitasking issue. Also, the multitasking implies that a number of parts of espruino need to be reentrant. Imagine using the loopback devices. Where would you put the yield() call in the case of the trace() function?

  • Performance of the character devices only really matters if we've got the watchdog nipping at our heels - otherwise, it's only "nice" not "critical". I think we somehow need to be able to yield() while JS is running - pause the interpreter and run and "feed the dog" - with the overhead of the js interpreter, I think triggering the WDT reset will be a major problem.

  • Well, yield would happen in the character IO function, when it realised the buffer was getting full? Potentially the interpreter could also check elapsed time when it executed loops as well - which would help to fix the WDT issue.

    Things like Loopback overflows will always be a problem I think - even if re-entrant I imagine you could shoot yourself in the foot pretty easily...

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

output buffering and character device performance

Posted by Avatar for tve @tve

Actions