Можно ли использовать подсказку предсказания ветвления в С#?

Например, я знаю, что он определен для gcc и используется в ядре Linux как:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

Если в С# ничего подобного не возможно, это лучшая альтернатива ручному переупорядочиванию if-statement, сначала ставя наиболее вероятный случай? Существуют ли другие способы оптимизации на основе этого типа внешних знаний?

В соответствующей заметке CLR знает, как идентифицировать предложения охраны и предполагает, что будет использоваться альтернативная ветвь, что делает эту оптимизацию неуместной для использования в защитных кланах, правильно?

(Обратите внимание, что я понимаю, что это может быть микро-оптимизация, я интересуюсь только академическими целями.)

Ответы

Ответ 1

Краткий ответ: Нет.

Более длинный ответ: вам не нужно в большинстве случаев. Вы можете давать подсказки, изменяя логику в своих высказываниях. Это проще сделать с помощью инструмента повышения производительности, например, встроенного в более высокие (и более дорогие) версии Visual Studio, поскольку вы можете получить счетчик ошибочно предсказанных ветвей. Я понимаю, что это для академических целей, но приятно знать, что JITer очень хорошо оптимизирует ваш код для вас. Как пример (взято в значительной степени дословно из CLR через С#)

Этот код:

public static void Main() {
    Int32[] a = new Int32[5];
    for(Int32 index = 0; index < a.Length; index++) {
        // Do something with a[index]
    }
}

может показаться неэффективным, поскольку a.Length - это свойство, и, как мы знаем в С#, свойство на самом деле представляет собой набор из одного или двух методов (get_XXX и set_XXX). Однако JIT знает, что это свойство, и либо сохраняет длину в локальной переменной для вас, либо указывает на метод, чтобы избежать накладных расходов.

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

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

Я понимаю, что это не имеет непосредственного отношения к вашему вопросу, но я предполагаю, что я хочу подчеркнуть, что подобные микрооптимизации не очень вам помогают в С#, потому что JIT обычно делает это лучше, так как это было разработано именно для этого. (Забавно, что JIT-компилятор x86 выполняет более агрессивную оптимизацию, чем аналог x64)

В этой статье описываются некоторые оптимизации, которые были добавлены в .NET 3.5 с пакетом обновления 1 (SP1), в том числе улучшения в выпрямлении веток для улучшения прогнозирования и локальности кэша.

При всем этом, если вы хотите прочитать отличную книгу, в которой рассказывается о том, что генерирует компилятор, и о производительности CLR, я рекомендую книгу, процитированную выше, CLR через С#.

РЕДАКТИРОВАТЬ: я должен упомянуть, что если бы это было возможно в настоящее время в .NET, вы могли бы найти информацию либо в стандарте EMCA-335, либо в рабочем проекте. Не существует стандарта, который бы это поддерживал, и просмотр метаданных в чем-то вроде IlDasm или CFF Explorer не показывает никаких признаков каких-либо специальных метаданных, которые могут намекнуть на предсказания ветвлений.