Могу ли я проверить, встроен ли компилятор C # в вызов метода? - PullRequest
25 голосов
/ 06 марта 2009

Я пишу игру XNA, в которой я делаю проверку столкновений на пиксель. Цикл, который проверяет это, делает это путем сдвига int и побитового ORing и, как правило, его трудно читать и понимать.

Я хотел бы добавить частные методы, такие как private bool IsTransparent(int pixelColorValue), чтобы сделать цикл более читабельным, но я не хочу накладных расходов на вызовы методов, поскольку это очень чувствительный к производительности код.

Есть ли способ заставить компилятор встроить этот вызов, или я просто надеюсь, что компилятор выполнит эту оптимизацию?

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

Редактировать: Я не могу форсировать это, поэтому я могу обнаружить это?

Ответы [ 10 ]

24 голосов
/ 06 марта 2009

Нет, ты не можешь. Более того, тот, кто выбирает встраивание, не VS-компилятор, который берет ваш код и преобразует его в IL, а JIT-компилятор, который принимает IL и преобразует его в машинный код. Это связано с тем, что только JIT-компилятор знает достаточно об архитектуре процессора, чтобы принять решение о целесообразности размещения метода в строке, поскольку это компромисс между конвейеризацией команд и размером кэша.

Так что даже поиск в .NET Reflector вам не поможет.

16 голосов
/ 06 марта 2009

"Вы можете проверить System.Reflection.MethodBase.GetCurrentMethod (). Имя. Если метод встроен, он будет вернуть имя звонящего вместо этого. "

- Джоэл Коухорн

14 голосов
/ 20 марта 2012

Существует новый способ поощрения более агрессивного встраивания в .net 4.5, который описан здесь: http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the-clr-4-5-jit.aspx

По сути, это просто флаг, указывающий компилятору на включение, если это возможно. К сожалению, он не доступен в текущей версии XNA (Game Studio 4.0), но должен быть доступен, когда XNA догонит VS 2012 в этом году. Он уже доступен, если вы как-то работаете на Mono.

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
public static int LargeMethod(int i, int j)
{ 
    if (i + 14 > j) 
    { 
        return i + j; 
    } 
    else if (j * 12 < i) 
    { 
        return 42 + i - j * 7; 
    } 
    else 
    { 
        return i % 14 - j; 
    } 
}
4 голосов
/ 06 марта 2009

Помните, что XBox работает по-другому.

Гугл поднял это:

"Встроенный метод, который уменьшает накладные расходы при вызове метода. JIT образует встроенное, что удовлетворяет следующим условиям.

  • Размер кода IL составляет 16 байтов или менее.
  • Команда ветвления не используется (если предложение и т. д.).
  • Локальная переменная не используется.
  • обработки исключений не было выполнено (попробуйте, поймайте и т. д.).
  • float не используется в качестве аргумента или возвращаемое значение метода (возможно, Xbox 360, не применяется).
  • Когда два или более аргумента находятся в метод, он использует для поворота объявлено.

Однако виртуальная функция не превращается в встроенную. "

http://xnafever.blogspot.com/2008/07/inline-method-by-xna-on-xbox360.html

Понятия не имею, прав ли он. Кто-нибудь?

1 голос
/ 06 марта 2009

Единственный способ проверить это - получить или написать профилировщик и подключиться к событиям JIT. Вы также должны убедиться, что Inlining не отключена, как по умолчанию при профилировании.

1 голос
/ 06 марта 2009

почему бы не использовать небезопасный код (встроенный c, как он известен) и использовать указатели в стиле c / c ++, это безопасно от GC (то есть не зависит от коллекции), но имеет свои собственные последствия для безопасности (не может использоваться для Интернета приложения для зоны), но отлично подходит для тех вещей, которые, по-видимому, вы пытаетесь достичь, особенно с помощью производительности и, тем более, с массивами и побитовыми операциями?

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

РЕДАКТИРОВАТЬ: немного стартера? http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

1 голос
/ 06 марта 2009

Нет, вы не можете.

По сути, этого нельзя сделать в большинстве современных компиляторов C ++. inline это просто предложение для компилятора. Это бесплатно или нет.

Компилятор C # не делает никаких специальных вставок на уровне IL. Оптимизатор JIT это тот, кто это сделает.

0 голосов
/ 03 марта 2019
0 голосов
/ 06 марта 2009

Есть ли способ заставить компилятор встроить этот вызов или я просто надеюсь, что компилятор выполнит эту оптимизацию?

Если встроить функцию дешевле, она будет. Так что не беспокойтесь об этом, если ваш профилировщик не скажет, что это действительно проблема.

Для получения дополнительной информации

Улучшения JIT в .NET 3.5 SP1

0 голосов
/ 06 марта 2009

Вы можете обнаружить его во время выполнения с помощью вышеупомянутого вызова GetCurrentMethod. Но это, похоже, пустая трата [1]. Самое простое, что можно сделать, - это просто ИДАДАСИТЬ MSIL и проверить там.

Обратите внимание, что это специально для компилятора , встроенного в вызов, и рассматривается в различных документах Reflection на MSDN.

Если метод, вызывающий метод GetCallingAssembly, расширяется встроенным компилятором (т. Е. Если компилятор вставляет тело функции в промежуточный язык Microsoft (MSIL), а не в вызов функции), то сборка возвращается методом GetCallingAssembly - это сборка, содержащая встроенный код. Это может отличаться от сборки, содержащей оригинальный метод. Чтобы убедиться, что метод, который вызывает метод GetCallingAssembly, не встроен компилятором, вы можете применить атрибут MethodImplAttribute с MethodImplOptions.NoInlining.

Тем не менее, JITter также свободен для встроенных вызовов - но я думаю, что дизассемблер будет единственным способом проверить, что и что не делается на этом уровне.

Редактировать: просто чтобы устранить некоторую путаницу в этой теме, csc.exe будет встроенными вызовами MSIL - хотя JITter будет (вероятно) более агрессивным в этом. *

[1] И, под отходами - я имею в виду, что (а) он отрицает цель включения (лучшую производительность) из-за поиска в отражении. И (б), это, вероятно, изменит поведение встраивания, так что оно больше не будет встроенным. И, прежде чем думать, что вы можете просто включить его в сборках Debug с Assert или чем-то еще - поймите, что он не будет встроен во время Debug, но может быть в Release.

...