Критический по скорости раздел в gcc? - PullRequest
1 голос
/ 10 октября 2019

Я уже использую -O3, поэтому я не думаю, что смогу добиться большего успеха в целом, но сгенерированная сборка все еще не соответствует требованиям времени. Есть ли способ, например, сказать avr-gcc, чтобы не критичный к скорости код не попадал в секцию, критичную для скорости?

if (READY)
{
    ACKNOWLEDGE();

    SETUP_PART1();
    SETUP_PART2();

    //start speed-critical section
    SYNC_TO_TIMER();
    MINIMAL_SPEED_CRITICAL_CODE();
    //end speed-critical section

    CLEANUP();
}

Утомительное чтение списка оптимизированных -O3 сборок(.lss файл) показывает, что SETUP_PART2(); был переупорядочен, чтобы быть между SYNC_TO_TIMER(); и MINIMAL_SPEED_CRITICAL_CODE();. Это проблема, потому что это добавляет время, потраченное в критической для скорости секции, которая не должна существовать.

Я не хочу делать критическую секцию самой дольше, чем она должна быть, поэтому я 'Я не решаюсь оптимизировать. (то же самое действие, которое вызывает эту проблему, может также заключаться в том, что делает окончательную версию подходящей в пределах доступного времени). Так как я могу сказать ему, что «это поведение» должно оставаться чистым и беспорядочным, но все же оптимизировать его полностью?


Я уже использовал встроенную сборку, так что я уверен, что смогу еще раз выяснить, как обмениваться данными между этим и C, не полностью связывая или заглатывая регистры и т. Д. Но я бы предпочел придерживаться 100%C, если я могу, и пусть компилятор выяснит, как не работать над собой.

1 Ответ

0 голосов
/ 13 октября 2019

Не совсем прямой ответ, который я искал, но нашел то, что работает. Так что технически это проблема XY, но я все равно приму прямой ответ на поставленный вопрос.


Вот что я в итоге сделал:

1. Разделяем скорость-критическая секция в свою собственную функцию, и предотвращает ее встраивание:

void __attribute__((noinline)) _fast_function(uint8_t arg1, uint8_t arg2)
{
    //start speed-critical section
    SYNC_TO_TIMER();
    MINIMAL_SPEED_CRITICAL_CODE(arg1, arg2);
    //end speed-critical section
}

void normal_function(void)
{
    if (READY)
    {
        ACKNOWLEDGE();

        SETUP_PART1();
        SETUP_PART2();  //determines arg1, arg2

        _fast_function(arg1, arg2);

        CLEANUP();
    }
}

Это удерживает критичные по скорости вещи вместе и само по себе. Это также добавляет некоторые накладные расходы, но это происходит вне быстрой части, где я могу себе это позволить.

2. Вручную разверните несколько циклов:

Исходный код был примерно таким:

uint8_t data[3];

uint8_t byte_num = 3;
while(byte_num)
{
    byte_num--;

    uint8_t bit_mask = 0b10000000;
    while(bit_mask)
    {
        if(data[byte_num] & bit_mask)   WEIRD_OUTPUT_1();
        else                            WEIRD_OUTPUT_0();

        bit_mask >>= 1;
    }
}

Новый код выглядит следующим образом:

#define WEIRD_OUTPUT(byte,bit)                  \
    do                                          \
    {                                           \
        if((byte) & (bit))  WEIRD_OUTPUT_1();   \
        else                WEIRD_OUTPUT_0();   \
    } while(0)

uint8_t data[3];

WEIRD_OUTPUT(data[2],0b10000000);
WEIRD_OUTPUT(data[2],0b01000000);
WEIRD_OUTPUT(data[2],0b00100000);
WEIRD_OUTPUT(data[2],0b00010000);
WEIRD_OUTPUT(data[2],0b00001000);
WEIRD_OUTPUT(data[2],0b00000100);
WEIRD_OUTPUT(data[2],0b00000010);
WEIRD_OUTPUT(data[2],0b00000001);

WEIRD_OUTPUT(data[1],0b10000000);
WEIRD_OUTPUT(data[1],0b01000000);
WEIRD_OUTPUT(data[1],0b00100000);
WEIRD_OUTPUT(data[1],0b00010000);
WEIRD_OUTPUT(data[1],0b00001000);
WEIRD_OUTPUT(data[1],0b00000100);
WEIRD_OUTPUT(data[1],0b00000010);
WEIRD_OUTPUT(data[1],0b00000001);

WEIRD_OUTPUT(data[0],0b10000000);
WEIRD_OUTPUT(data[0],0b01000000);
WEIRD_OUTPUT(data[0],0b00100000);
WEIRD_OUTPUT(data[0],0b00010000);
WEIRD_OUTPUT(data[0],0b00001000);
WEIRD_OUTPUT(data[0],0b00000100);
WEIRD_OUTPUT(data[0],0b00000010);
WEIRD_OUTPUT(data[0],0b00000001);

Помимо удаления самого кода цикла, он также заменяет индекс массива прямым доступом, а переменную - константой, каждыйиз которых предлагает свое собственное ускорение.

И это все еще едва вписывается в доступное время. Но это подходит! :)

...