Ниже приведен код некоей математической обработки данных. В дебри вдаваться не буду, так как для вопроса, который я хочу задать, математическая часть кода не играет роли и приведена только с одной целью - чтобы не было претензии что код неполный. Итак, код приведен полностью, он компилируется и может быть запущен любым желающим.
Code
#define BUF_SIZE 8192
#define pin 11
uint32_t buffer1[BUF_SIZE] = {0};
uint32_t buffer2[BUF_SIZE] = {0};
void setup() {
pinMode(pin, OUTPUT);
for (auto i = 0; i < BUF_SIZE; i++) {
buffer1[i] = (random(255) << 16) | (random(255) << 8) | random(255);
//buffer1[i] |= (i % 2) << 24;
}
}
// transpose 64 x 64 bit matrix
// Based on: https://web.archive.org/web/20190108225554/http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt
void matrix_transform(uint32_t* buffer1, uint32_t* buffer2) {
uint8_t* B = (uint8_t*)buffer2;
const int n = BUF_SIZE / 2;
for (auto k = 0; k < BUF_SIZE / 2 ; k++) {
uint32_t A = buffer1[k];
uint32_t A1 = buffer1[k + BUF_SIZE / 2];
// Copy input values into x and y.
// Test upper nible
if ((A >> 24) & (A1 >> 24)) {
unsigned x, y, t;
x = A;
y = A1 << 8;
t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
t = (x ^ (x >> 14)) & 0x0000CCCC; x = x ^ t ^ (t << 14);
t = (y ^ (y >> 14)) & 0x0000CCCC; y = y ^ t ^ (t << 14);
t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
x = t;
// with next two lines the loop duration 350us
B[0] = x>>24; B[n] = x>>16; B[2*n] = x>>8; B[3*n] = x;
B[4*n] = y>>24; B[5*n] = y>>16; B[6*n] = y>>8; B[7*n] = y;
// but with these lines = 310us
//*B = x;
//*(++B) = y;
}
B++;
}
}
void loop() {
gpio_put(pin, HIGH);
matrix_transform(buffer1, buffer2);
gpio_put(pin, LOW);
delay(25);
}
В чем суть - в коде есть буфер данных (8К 32битных значений) и есть цикл, который берет по два значения (uint32) из входного буфера, применяет к ним алгоритм и кладет в выходной буфер.
В какой-то момент, анализируя скорость исполнения, я захотел понять, сколько же времени занимает сама обработка, а сколько - накладные расходы на цикл и на копирование данных. Поэтому я вставил в цикл условие строка 26, которое всегда ложно. То есть теперь программа вообще не заходит в блок обработки (стр 26-49) и просто крутит цикл впустую. Время исполнения составило 350мкс, что на мой взгляд как-то много. В цикле всего 4096 практически пустых итераций, что при частоте процессора 150 МГц составляет примерно 17 контроллерных тиков на итерацию
Вопрос 1 - Можно ли это время как-то уменьшить? Может у меня цикл организован не оптимально?
Но погодите, вопрос 2 интереснее.
Если в этом тесте с пустыми итерациями изменить код внутри блока, в который программа не заходит - время исполнения цикла меняется! Вот этого я вообще не понимаю. Конкретно, если строчки 43-44 заменить на строчки 47-48, полный цикл станет занимать 310 мкс вместо 350.
Как так? Ведь строки НЕ ИСПОЛНЯЮТСЯ!
Надеюсь наши гуру легко обьяснят, в чем тут дело.
Технические детали
плата Расбери Пико 2040, FPU 150MHz, аддон Филхофера 5.4.3
Пробовал разные режимы оптимизации - время меняется, общий принцип нет.
На всякий случай, чтобы проверить что программа действительно не заходит в блок строк 26-49 - добавлял внутрь блока вывод импульса на внешний пин и смотрел его анализатором. Не мигает.