Hello there. I am several days into esp32 and C/C++. So my knowledge regarding advanced techniques is limited.
But in a different thread, we were talking about tight loops that counts and displays the result every second. Performance was not really the focus, but something else.
I make a new thread, because the original problem was solved, and this is a new problem.
My code:
#include "esp_log.h"
#include <esp_task_wdt.h>
#include <Arduino.h>
static const char *TAG = "Main";
void setup() {
Serial.begin(115200);
}
void loop() {
setCpuFrequencyMhz(240);
int32_t lastResetTime = xTaskGetTickCount() * portTICK_PERIOD_MS;
int32_t performanceCounter = 0;
while (true) {
performanceCounter++;
if ((xTaskGetTickCount()* portTICK_PERIOD_MS - lastResetTime) >= 1000) {
printf("Performance score2: %lu\n", performanceCounter);
performanceCounter = 0;
lastResetTime = xTaskGetTickCount()* portTICK_PERIOD_MS;
}
}
}
Just normal stuff, basically I replaced millis() by RTOS func.
But now AI gave me this...I was just curious:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "soc/soc.h"
#define TAG "PERF"
volatile uint32_t performanceCounter = 0;
volatile uint32_t lastPerformanceCount = 0;
void IRAM_ATTR onTimer(void* arg) {
uint32_t count = performanceCounter;
lastPerformanceCount = count;
performanceCounter = 0;
printf("Performance score: %lu\n", count);
}
void setup() {
esp_timer_create_args_t timerArgs;
timerArgs.callback = &onTimer;
timerArgs.name = "PerformanceTimer";
timerArgs.arg = NULL;
timerArgs.dispatch_method = ESP_TIMER_TASK;
timerArgs.skip_unhandled_events = false;
esp_timer_handle_t periodicTimer;
ESP_ERROR_CHECK(esp_timer_create(&timerArgs, &periodicTimer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodicTimer, 1000000)); // 1 second interval
}
void loop() {
uint32_t localCounter = 0;
while (true) {
localCounter++;
if ((localCounter & 0xFFF) == 0) { // Every 4096 iterations
uint32_t current = performanceCounter;
uint32_t newValue;
do {
newValue = current + 0xFFF;
} while (!__sync_bool_compare_and_swap(&performanceCounter, current, newValue));
localCounter = 0;
}
}
}
This was one-shot by the AI, and it said, it could be improved further.
Then one user said:
.
This is maybe a bit over my head, and I am not sure how to debug this, but I tried:
if (localCounter > 4000) { // Every 4096 iterations
printf("%lu / %lu\n", localCounter, performanceCounter);
}
I checked first by simple print(localcounter) that it counts correctly to 4096.
I think folowing is the critical spot.
So I removed first print, and put this in:
if (localCounter > 4000) { // Every 4096 iterations
printf("%lu / %lu\n", localCounter, performanceCounter);
}
Result:
...
4002 / 4095
4003 / 4095
...
4093 / 4095
4094 / 4095
4095 / 4095
4096 / 4095
...
4001 / 8190
4002 / 8190
4003 / 8190
4004 / 8190
...
4094 / 8190
4095 / 8190
4096 / 8190
...
4001 / 12285
4002 / 12285
4003 / 12285
...
4094 / 12285
4095 / 12285
4096 / 12285
...
4001 / 16380
4002 / 16380
4003 / 16380
...
4095 / 16380
4096 / 16380
...
4001 / 20475
4002 / 20475
4003 / 20475
So from my basic understanding, the AI is correct. Is it?
Where else could it cheat?
And one second seems to be one second.
The AI used:
- a hardware timer and interrupt for precise timing
- local counter to reduce atomic operations
- atomic operations for thread-safe counting
If correct, what could be learned from that?
Can our superloops with a lot of time checks be optimized?
I mean is that not "THE" most basic tool / principle of arduino?