Определение версии JIT в рантайме



Иногда мне в моих маленьких C#-экспериментах нужно определять версию используемого JIT-компилятора. Понятно, что её можно определить заранее исходя из окружения. Но порой мне хочется знать её в рантайме, чтобы выполнять специфичный код для текущего JIT-компилятора. Строго говоря, я хочу получать значение из следующего перечисления:

public enum JitVersion
{
    Mono, MsX86, MsX64, RyuJit
}

Я могу легко определить, что работаю под Mono, по наличию класса Mono.Runtime. Если это не так, то можно считать, что мы работаем с JIT от Microsoft. JIT-x86 легко узнать с помощью IntPtr.Size == 4. А вот чтобы отличить старый JIT-x64 от нового RyuJIT необходимо немного призадуматься. Далее я покажу, как это можно сделать с помощью бага JIT-x64, который я описывал в предыдущем посте.

Сначала приведу тривиальный код, который поможет нам опознать версии JitVersion.Mono и JitVersion.MsX86:

public static bool IsMono()
{
    return Type.GetType("Mono.Runtime") != null;
}

public static bool IsMsX86()
{
    return !IsMono() && IntPtr.Size == 4;
}

Теперь научимся определять JitVersion.MsX64. Для этого проверим наличие JIT-x64 sub-expression elimination optimizer bug. Обратите внимание, что программа должна быть скомпилирована с включёнными оптимизациями.

private int bar;

private bool IsMsX64(int step = 1)
{
    var value = 0;
    for (int i = 0; i < step; i++)
    {
        bar = i + 10;
        for (int j = 0; j < 2 * step; j += step)
            value = j + 10;
    }
    return value == 20 + step;
}

В рамках данной задачи мы работаем с ограниченным набором JIT-компиляторов. Поэтому RyuJIT можно опознать методом исключения:

public JitVersion GetJitVersion()
{
    if (IsMono())
        return JitVersion.Mono;
    if (IsMsX86())
        return JitVersion.MsX86;
    if (IsMsX64())
        return JitVersion.MsX64;
    return JitVersion.RyuJit;
}

Всё готово! Напишем простую программу, в которой определим версию JIT:

using System;

class Program
{
    public enum JitVersion
    {
        Mono, MsX86, MsX64, RyuJit
    }

    public class JitVersionInfo
    {
        public JitVersion GetJitVersion()
        {
            if (IsMono())
                return JitVersion.Mono;
            if (IsMsX86())
                return JitVersion.MsX86;
            if (IsMsX64())
                return JitVersion.MsX64;
            return JitVersion.RyuJit;
        }

        private int bar;

        private bool IsMsX64(int step = 1)
        {
            var value = 0;
            for (int i = 0; i < step; i++)
            {
                bar = i + 10;
                for (int j = 0; j < 2 * step; j += step)
                    value = j + 10;
            }
            return value == 20 + step;
        }

        public static bool IsMono()
        {
            return Type.GetType("Mono.Runtime") != null;
        }

        public static bool IsMsX86()
        {
            return !IsMono() && IntPtr.Size == 4;
        }
    }

    static void Main()
    {
        Console.WriteLine("Current JIT version: " + new JitVersionInfo().GetJitVersion());
    }
}

Отлично, класс готов к использованию! Полный код также доступен на Gist: JitVersionInfo.cs.

Замечания

  • Метод определения MsX64 vs RyuJIT работает только с включёнными оптимизациями.
  • Данная программа работает с ограниченными набором версий JIT, могут быть проблемы на нестандартных версиях .NET.
  • Мигель обещал, что Mono 4 будет работать на CoreCLR, что означает использование RyuJIT.

Ссылки

Поделиться:
Исходный код поста находится на GitHub:
https://github.com/AndreyAkinshin/aakinshin.net/blob/master/web/_posts/ru/2015/jit-version-determining-in-runtime.md