ГлавнаяБлогМакросы likely и unlikely в Linux: магия ветвления
Алгоритмы

Макросы likely и unlikely в Linux: магия ветвления

Разбираем макросы likely и unlikely из ядра Linux: как они влияют на производительность, ветвление и оптимизацию кода на C. Практические примеры и советы.

Al
Редакция Algolitalgolit.ru
5 мин чтения23 августа 2026 г.

Что такое макросы likely и unlikely в ядре Linux?

В исходном коде ядра Linux часто встречаются конструкции с макросами likely и unlikely. Они выглядят как обычные условия, но на самом деле дают компилятору подсказку о том, какая ветка кода выполняется чаще. Это позволяет оптимизировать код и повысить производительность. В этой статье мы разберём, как они работают, и как вы можете применить этот приём в своих проектах.

Как работают likely и unlikely?

Макрос unlikely определён в ядре Linux следующим образом:

#define unlikely(e) __builtin_expect(!!(e), 0)

Он передаёт выражение e в специальную встроенную функцию компилятора __builtin_expect вместе с ожидаемым значением 0. Аналогично likely передаёт ожидаемое значение 1. Эта функция сообщает компилятору, какое значение выражения наиболее вероятно. Компилятор использует эту информацию для оптимизации порядка инструкций в машинном коде, чтобы улучшить предсказание ветвлений процессором.

Пример: влияние на производительность

Рассмотрим два практически одинаковых цикла, отличающихся только использованием макросов likely и unlikely:

long unlikely_simple(long num_runs) {
    long total = 0;
    for (long i = 0; i < num_runs; i++) {
        if (unlikely(i % 1000 == 0)) {
            total += 2;
        } else {
            total += i + 1;
        }
    }
    return total;
}

long likely_simple(long num_runs) {
    long total = 0;
    for (long i = 0; i < num_runs; i++) {
        if (likely(i % 1000 == 0)) {
            total += 2;
        } else {
            total += i + 1;
        }
    }
    return total;
}

В этих циклах первая ветка (if) выполняется в 0,1% случаев, а вторая (else) — в 99,9%. Мы можем изменить процент, варьируя делитель. Замеры времени выполнения для разных процентов показывают, что likely даёт выигрыш, когда предсказание совпадает с реальностью, но проигрывает, если реальность противоположна.

Таблица производительности (в микросекундах) для двух функций при разной вероятности попадания в первую ветку:

  • unlikely_simple: 50% — 48,899; 10% — 51,736; 1% — 58,496; 0,1% — 53,637
  • likely_simple: 50% — 48,643; 10% — 75,979; 1% — 79,594; 0,1% — 72,342

Видно, что при уменьшении вероятности первой ветки likely_simple деградирует, потому что мы подсказали компилятору оптимизировать под редкую ветку, а реальное выполнение идёт часто по другой.

Почему это работает? Ассемблерный анализ

Чтобы понять причину, посмотрим на сгенерированный ассемблерный код для обеих функций (компиляция с флагом -O2). Ключевое различие — порядок инструкций: в likely ветка if размещена сразу после проверки условия, а в unlikely — наоборот, сначала идёт else. Это связано с конвейеризацией процессора: он предзагружает инструкции, следующие по порядку в памяти. Если предзагруженная ветка не выполняется, конвейер сбрасывается, и происходит потеря производительности.

Практический вывод: как использовать likely и unlikely

Макросы likely и unlikely полезны в горячих путях выполнения, где ветвление происходит миллионы раз. В обычном прикладном коде их эффект может быть незаметен, но в низкоуровневых системах, драйверах или высоконагруженных сервисах они способны дать ощутимый прирост. Используйте их осознанно: только когда вы точно знаете, какая ветка выполняется чаще. Неправильная подсказка может ухудшить производительность. Экспериментируйте и профилируйте свой код.

#likely#unlikely#оптимизация#ветвление#ядро Linux
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →