-
Notifications
You must be signed in to change notification settings - Fork 7.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(i2c_master): Do not busy wait on sync transactions (IDFGH-12280) #13322
Conversation
This commit introduces a private member `i2c_master_bus_t::in_progress_semphr` which allows `i2c_master_transmit` and related functions to give up their timeslice so other tasks can proceed. Without this commit, one must delay at least one tick via `vTaskDelay(1)` to prevent trigging the idle watchdog, thus limiting the maximum I2C transaction rate to about the speed of `CONFIG_FREERTOS_HZ`. With this commit, over 6600 samples/sec are possible and the tick delay is unnecessary. CPU usage below was measured using `vTaskGetRunTimeStats()`. The FreeRTOS %CPU numbers seem to increase over time and level out after a time, so CPU usage was sampled after 5 seconds across each test for consistency across measurements. Measurements were taken with `CONFIG_FREERTOS_HZ` set to 100Hz and 1000Hz: Before: 100Hz: samples/sec= 99 with 1% CPU ( 99.0 samples/%cpu) 1000Hz: samples/sec= 995 with 10% CPU ( 99.5 samples/%cpu) After: 100Hz: samples/sec=6637 with 23% CPU (288.6 samples/%cpu) 1000Hz: samples/sec=6610 with 24% CPU (275.4 samples/%cpu) Closes: espressif#13137 Signed-off-by: Eric Wheeler <esp-idf@z.ewheeler.org>
👋 Hello KJ7LNW, we appreciate your contribution to this project! 📘 Please review the project's Contributions Guide for key guidelines on code, documentation, testing, and more. 🖊️ Please also make sure you have read and signed the Contributor License Agreement for this project. Click to see more instructions ...
Review and merge process you can expect ...
|
We used this simple project to test the PR change: If you try the test project, be sure to comment the https://github.com/KJ7LNW/esp32-i2c-test/blob/master/main/i2c-test.c#L152 |
65af55e
to
bf62c8a
Compare
The force-push is a minor change: It simply sets This reduces latency and increases the i2c sample rates to 6612 (1000Hz) and 6648 (100Hz). |
I think the original commit was better. If I2C is running on a medium priority task and the interrupt happens on a high priority task, we shouldn't yield it just to complete the I2C transaction - we must respect the priorities chosen. Especially not for a ~0.2% increase in performance. |
bf62c8a
to
65af55e
Compare
@nebkat that makes sense. Reverted and force-pushed. |
Thanks a lot for this contribution. I am going to create an event queue instead of semaphore. Which can be used to store more information. |
@nebkat that does not make sense to me. |
@jrahlf You're right my explanation was inaccurate, it would jump back to the higher priority task anyway. But we would have run the scheduler unnecessarily, so still better this way. I have also learned |
Out of curiosity I wondered how task notifications perform, which FreeRTOS claims to be up to 45% faster than semaphores: Notifications:
Semaphores: (copied from above)
As you can see, notifications are faster and CPU efficiency is much higher with the task notification implementation. I've pushed a commit converting to notifications on this PR so you can see the difference. |
The previous commit uses semaphores, this commit converts semaphores to task notifications because FreeRTOS claims they are faster, and indeed they are: Notifications (this commit): - 100Hz: samples/sec= 6654 with 18% CPU (efficiency: 369.7 samples/%cpu) - 1000Hz: samples/sec= 6636 with 18% CPU (efficiency: 368.7 samples/%cpu) Semaphores (previous commit): - 100Hz: samples/sec= 6637 with 23% CPU (efficiency: 288.6 samples/%cpu) - 1000Hz: samples/sec= 6610 with 24% CPU (efficiency: 275.4 samples/%cpu) Signed-off-by: Eric Wheeler <esp-idf@z.ewheeler.org>
d5e513c
to
d132c79
Compare
This commit introduces a private member
i2c_master_bus_t::in_progress_semphr
which allowsi2c_master_transmit
and related functions to give up their timeslice so other tasks can proceed.Without this commit, one must delay at least one tick via
vTaskDelay(1)
to prevent trigging the idle watchdog, thus limiting the maximum I2C transaction rate to about the speed ofCONFIG_FREERTOS_HZ
.With this commit, over 6600 samples/sec are possible and the tick delay is unnecessary.
CPU usage below was measured using
vTaskGetRunTimeStats()
. The FreeRTOS %CPU numbers seem to increase over time and level out after a time, so CPU usage was sampled after 5 seconds across each test for consistency across measurements. Measurements were taken withCONFIG_FREERTOS_HZ
set to 100Hz and 1000Hz:Before:
After:
Closes: #13137