ARM Cortex M* — сколько «весит» примитив? +3


Видимые преимущества языка "C" сопровождается издержками, скрытыми расходами вычислительных ресурсов на указатели, пересылку данных "память <=> регистр", согласование разрядности, выравнивание и т. п.

Разница ожидаемого и реального времени выполнения критических участков кода чувствительна для промышленного программирования бюджетных микроконтроллеров, где главное — низкая цена.
Низкая цена — ключевое преимущество в массовом производстве.
Низкая цена естественно балансируется скромными вычислительными возможностями бюджетных микроконтроллеров.

Все сложные вычисления состоят из конечного ряда простых.
Представление о реальном времени выполнения примитивных операторов языка "C" открывает возможность для экспресс-оценки продуктивности критических участков кода на этапе проектирования через простой подсчёт числа примитивных операторов.

Замеры времени выполнения примитивных операторов языка "C" произведены на двух аппаратных платформах в равных условиях.
Сразу отметим, производительность Cortex M4 выше, чем Cortex M0, что естественно.

Общие наблюдения в результате замеров:

  • - операции int32 на ~20% быстрее, чем int16;

  • - double в 2 раза медленнее, чем float на Cortex M0;

  • - double в 27 раз медленнее, чем float на Cortex M4;

  • - арифметика float на Cortex M4 конкурентна int16 там же;

  • - деление - самая медленная операция всегда, что ожидаемо.

Результаты замеров далее в таблицах, где:

  • - fn: - формула оператора на языке "C";

  • - cc: - скорость выполнения оператора в тактах CPU;

  • - us: - скорость выполнения оператора в микросекундах (1E-6).

+=========================================
+-------------- #  1 ---------------------
+-- RELEASE at 12:26:28
+-- CPU:48 MHz, STM32 ARM Cortex M0
+-----------------------------------------
+-- cpu time of simple int16 "C"
fn:    i3 = i1 + i2,	cc:    7, us:    0
fn:    i3 = i1 - i2,	cc:    9, us:    0
fn:    i3 = i1 * i2,	cc:    8, us:    0
fn:    i3 = i1 / i2,	cc:   67, us:    1
fn:    i3 = i1 % i2,	cc:   70, us:    1
--- is:715826417 ---
+-----------------------------------------
+-- cpu time of simple int32 "C"
fn:    l3 = l1 + l2,	cc:    5, us:    0
fn:    l3 = l1 - l2,	cc:    6, us:    0
fn:    l3 = l1 * l2,	cc:    5, us:    0
fn:    l3 = l1 / l2,	cc:   61, us:    1
fn:    l3 = l1 % l2,	cc:   68, us:    1
--- ls:223077021 ---
+-----------------------------------------
+-- cpu time of simple float32 "C"
fn:    f3 = f1 + f2,	cc:  139, us:    2
fn:    f3 = f1 - f2,	cc:  182, us:    4
fn:    f3 = f1 * f2,	cc:  181, us:    3
fn:    f3 = f1 / f2,	cc:  568, us:   11
fn:    f = (float)l,	cc:  110, us:    1
fn:    l = (int32)f,	cc:   35, us:    1
--- fs:613566756 ---
+-----------------------------------------
+-- cpu time of simple float64 "C"
fn:    d3 = d1 + d2,	cc:  211, us:    4
fn:    d3 = d1 - d2,	cc:  235, us:    4
fn:    d3 = d1 * d2,	cc:  397, us:    7
fn:    d3 = d1 / d2,	cc:  877, us:   18
fn:    d = (doubl)l,	cc:  105, us:    1
fn:    l = (int32)d,	cc:   59, us:    0
--- ds:613566756 ---
+=========================================
+-------------- #  1 ---------------------
+-- RELEASE at 12:32:47
+-- CPU:48 MHz, STM32 ARM Cortex M4
+-----------------------------------------
+-- cpu time of simple int16 "C"
fn:    i3 = i1 + i2,	cc:    7, us:    0
fn:    i3 = i1 - i2,	cc:    6, us:    0
fn:    i3 = i1 * i2,	cc:    7, us:    0
fn:    i3 = i1 / i2,	cc:   12, us:    0
fn:    i3 = i1 % i2,	cc:   14, us:    0
--- is:715826417 ---
+-----------------------------------------
+-- cpu time of simple int32 "C"
fn:    l3 = l1 + l2,	cc:    5, us:    0
fn:    l3 = l1 - l2,	cc:    4, us:    0
fn:    l3 = l1 * l2,	cc:    4, us:    0
fn:    l3 = l1 / l2,	cc:    8, us:    0
fn:    l3 = l1 % l2,	cc:    9, us:    0
--- ls:223077021 ---
+-----------------------------------------
+-- cpu time of simple float32 "C"
fn:    f3 = f1 + f2,	cc:    6, us:    0
fn:    f3 = f1 - f2,	cc:    7, us:    0
fn:    f3 = f1 * f2,	cc:    5, us:    0
fn:    f3 = f1 / f2,	cc:   19, us:    0
fn:    f = (float)l,	cc:    4, us:    0
fn:    l = (int32)f,	cc:    3, us:    0
--- fs:613566756 ---
+-----------------------------------------
+-- cpu time of simple float64 "C"
fn:    d3 = d1 + d2,	cc:  120, us:    2
fn:    d3 = d1 - d2,	cc:  122, us:    2
fn:    d3 = d1 * d2,	cc:   84, us:    1
fn:    d3 = d1 / d2,	cc:  688, us:   13
fn:    d = (doubl)l,	cc:   59, us:    0
fn:    l = (int32)d,	cc:   31, us:    0
--- ds:613566756 ---

Использованное оборудование:

  • - ARM Cortex M0 — STM32F030R8T6;

  • - ARM Cortex M4 — STM32F303VCT6.

Погрешность измерения +/- 1 такт.

Сравнительная таблица результатов.

Простой отказ от int16 в пользу int32 повышает производительность участка программы приблизительно на 20%.

Есть риск свести "на нет" все преимущества FPU на Cortex M4, используя без должной осмотрительности double.




К сожалению, не доступен сервер mySQL