Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Ошибка компилятора JIT .Net?

Автор вопроса: JanОтветов: 1

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

Вот результат:

-> с оптимизацией: 1000 2008 3016 1001 2009 3007 ...

-> без оптимизации (как и ожидалось) 1000 1008 1016 1001 1009 1017 ...

Код:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace OptimizerTest
{
    public class Test
    {
        int dummy;

        public void TestFunction(int stepWidth)
        // stepWidth must be a parameter
        {
            for (int step = 0; step < stepWidth; step++)
            {
                dummy = step + 1000;
                // addition with constant ( same value as later !)
                for (int x = 0; x < 20; x += stepWidth)
                {
                    int index = x + 1000 + step;
                    // constant must be same as above and ?!?!
                    // int index = x + step + 1000; works !!!!!
                    Console.Write("\n\r" + index);
                }
            }
        }

        [MethodImpl(MethodImplOptions.NoOptimization)]
        public void TestFunctionNoOptimization(int stepWidth)
        {
            for (int step = 0; step < stepWidth; step++)
            {
                dummy = step + 1000;
                for (int x = 0; x < 20; x += stepWidth)
                {
                    int index = x + 1000 + step;
                    Console.Write("\n\r" + index);
                }
            }
        }
    }

    class Program
    {
        /// <summary>
        /// Result differs from Start with F5 to Ctrl-F5
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Test test = new Test();
            Console.Write("\n\r---------\n\roptimized result\n\r-------------" );
            test.TestFunction(8);
            Console.Write("\n\r---------\n\rnot optimized result\n\r-------------");
            test.TestFunctionNoOptimization(8);
            Console.Write("\n\r---------\n\rpress any key");
            Console.ReadKey();
        }
    }
}

Поведение ошибки зависит от количества итераций внутреннего цикла (x ‹5 все работает нормально). Очень интересно то, что не происходит, когда я использую

   int index = x + step + 1000;

вместо

   int index = x + 1000 + step;

Я работаю с Visual Studio 2010 SP1 и пробовал его с .NET Framework от 2.0 до 4.0.3. Я всегда видел один и тот же результат.

Кто-нибудь знает об этом баге или может воспроизвести?

  • Я получаю те же результаты, что и ваш пример без оптимизации с VS 2012 для обеих функций, поэтому не могу воспроизвести. Vlad 20.12.2013
  • Попробуйте использовать ILSpy для декомпиляции созданной библиотеки DLL и посмотрите, что у вас получится. (Или поместите свою dll где-нибудь, чтобы мы могли ее посмотреть, мне любопытно: D) Rawling 20.12.2013
  • ILSpy возвращает мне то, что я вложил. Кажется, все в порядке. Jan 20.12.2013
  • @UweKeim Я хочу отличаться: D Rawling 20.12.2013
  • то же самое для не может быть воспроизведено в 2012 году. Также то же самое для размещения exe где-нибудь, чтобы его можно было протестировать на других машинах и / или исследуемой IL. Chris 20.12.2013
  • @UweKeim: Не стесняйтесь указать, какую ошибку совершил Ян, если хотите. ;-) Chris 20.12.2013

visual-studio-2010jit

Ответы

Ответ 1 · рейтинг 20 · Hans Passant

Да, это определенно ошибка оптимизатора джиттера. Причина, по которой у других пользователей SO возникают проблемы с воспроизведением этого, заключается в том, что эта ошибка проявляется только в джиттере x64. Вы должны установить цель платформы проекта на AnyCPU, снимите отметку с опции "Предпочитать 32-битную" на VS2012 и более поздних версиях.

Я недостаточно внимательно изучил основную причину, но, похоже, она не пытается устранить распространенное подвыражение step + 1000. Устранение подвыражений - одна из стандартных оптимизаций джиттера. Но он неправильно включает код выражения внутри цикла вместо того, чтобы держать его вне цикла, как написано. Например, вы увидите, что ошибка исчезла, когда вы напишете:

  dummy = step + 999;

Эта ошибка все еще присутствует в последней версии .NET 4.5.1 (clrjit.dll, v4.0.30319.34003 на моей машине), также присутствует в джиттере v2 (mscorjit.dll, v2.0.50727.7905 на моей машине).

Код слишком синтетичен, чтобы рекомендовать надежный обходной путь, вы все равно его нашли, так что можете продолжать работу над своим проектом. В общем, я бы рекомендовал вам устранить это подвыражение самостоятельно:

  int index = x + dummy;

Об этом следует сообщить в Microsoft, вы можете сделать это, разместив отчет об ошибке на сайте connect.microsoft.com. Если вы не хотите тратить время, дайте мне знать, и я позабочусь об этом.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы