0

'io.run()' taking way too long on ESP8266
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

'io.run()' taking way too long on ESP8266

by smalg on Fri Sep 27, 2019 11:09 pm

Hi,

I've been tinkering with Adafruit IO on a ESP8266.
Everything seems to work well except one thing: a single 'io.run()' call takes more than 100ms to execute.
That seems HUGE to me, considering I'm only updating 3 feeds with a single number every 15 seconds.
Is this expected behavior?
I used to be able to run thousands of loop iterations per second, using Adafruit IO I'm now stuck to 9...

Any help would be appreciated :-)
Thanks!

smalg
 
Posts: 2
Joined: Fri Sep 27, 2019 10:56 pm

Re: 'io.run()' taking way too long on ESP8266

by brubell on Mon Sep 30, 2019 9:37 am

I used to be able to run thousands of loop iterations per second, using Adafruit IO I'm now stuck to 9...


io.run() performs a ping/response to the Adafruit IO server, it also waits for a connection to establish/re-establish (https://github.com/adafruit/Adafruit_IO ... O.cpp#L171).

The Adafruit MQTT library (https://github.com/adafruit/Adafruit_MQTT_Library) is lighter than Adafruit IO Arduino and may be quicker.

brubell
 
Posts: 528
Joined: Fri Jul 17, 2015 10:33 pm

Re: 'io.run()' taking way too long on ESP8266

by abachman on Mon Sep 30, 2019 12:42 pm

.run() is where your sketch checks for new MQTT subscription messages and like brubell said, it's where your device pings the MQTT broker once every 60s to keep the connection alive.

You've got a few options!

1. If you have no MQTT subscriptions you can skip calling it on every loop and only call it once per minute. That will make sure the PING happens on time and avoid the 100ms-ish delays.

2. If you're already publishing every 15 or so seconds and not subscribing to anything, you can leave it out entirely and the PUBLISH events happening when you call .save() will keep the connection alive. PING is the default, "I am active, but I have no new data to publish", but all the broker cares about is activity.

3. If you're expecting data but don't need it instantly, you can call it on a longer interval than "once every loop()". Maybe just call it on loops where you publish?

4. Finally, the run() method in Adafruit IO Arduino takes an optional "busywait_timeout" argument which is the amount of time in ms to wait for new MQTT packets to come in. I'll let you guess what the default timeout is :D Sending a low value (e.g, 5) will make io.run() spend less time waiting, but might cause your sketch to miss some MQTT subscription messages.

If you peek under the hood, Adafruit IO Arduino's .run() method is pretty much only calling Adafruit MQTT's processPackets method, so if you change libraries you'll end up with a similar problem but be a little closer to the truth of what's happening.


- ab.

abachman
 
Posts: 338
Joined: Mon Feb 01, 2010 12:48 pm

Re: 'io.run()' taking way too long on ESP8266

by smalg on Mon Sep 30, 2019 4:13 pm

Thanks for your answers! :-)

So if I understand correctly, the main "issue" (at least, in my opinion) is that AdafruitIO::run() does a blocking read on the MQTT client, with a 100ms timeout.
I honestly find that quite surprising, as all other Arduino libraries I've used to date do non-blocking reads without issues (my own libraries included) and for good reasons (no busy-waiting).
I guess I could just use the smallest allowed timeout (1ms) and hope for the best.
That's still a 4.5x slowdown for my loop(), which would basically spend most of its time waiting, but it's manageable.

But IMO the underlying question is: why would AdafruitIO::run() use a blocking read?
Even doing it this way, there's still no guarantee that incoming packets would arrive during the blocking read, so the client would still have to behave properly (i.e.: buffering) when packets arrive outside of a blocking read.
Given that assumption, why do blocking reads at all? They only seem to slow down the main loop (by more than 350x in my case) without any real advantage.
Also the ESP8266 is definitely not a platform where you can afford to waste 100ms every loop iteration "just because" - the watchdog will reset the MCU should the loop take too long to execute. AdafruitIO::run() doesn't seem to yield(), and 100ms is a very long time...
Honestly, I don't get it :-/

Anyway, many thanks for your answers.
I guess I'll now have to decide whether Adafruit IO is suitable for my use case...
Which is a bummer, because apart from this 350x slowdown, I really like it!

smalg
 
Posts: 2
Joined: Fri Sep 27, 2019 10:56 pm

Re: 'io.run()' taking way too long on ESP8266

by abachman on Tue Oct 01, 2019 11:56 am

why would AdafruitIO::run() use a blocking read?


I couldn't tell you for sure, but if I had to guess why https://github.com/adafruit/Adafruit_MQTT_Library does a blocking read, it'd be because it has to support just about every hardware platform Arduino supports including things like the ATmega328p. I'm not a firmware expert, not even close, but at the low end features get real constrained. If you have recommendations or pointers to non-blocking network libraries for arbitrary Arduino-core devices, pull requests are open. I will say that right now our focus is on CircuitPython, so that's where new work on network code is happening.

In the meantime, if https://github.com/knolleary/pubsubclient or any other MQTT client is better suited to your projects, the Adafruit IO Arduino library is only a convenience wrapper around Adafruit MQTT and our MQTT API, any MQTT client library should work fine.


- adam b.

abachman
 
Posts: 338
Joined: Mon Feb 01, 2010 12:48 pm

Please be positive and constructive with your questions and comments.