оптимизация трассировки стека

#c# #.net #wpf #64-bit #stack-trace

#c# #.net #wpf #64-разрядный #трассировка стека

Вопрос:

В моем приложении на C # я использовал stacktrace для записи имени метода и файла в случае сбоя.

Существует некоторая разница в трассировке стека между платформами x86 и x64.

 public string ErrorMessage
    {
      set
        {
         _strErrorMessage = "Error : "   value;
         //Call the method to log error.
         LogError(value);
        }
    }
  

В приведенном выше фрагменте кода при установке свойства ErrorMessage я вызываю метод LogError, который захватывает трассировку стека и записывает ее в файл журнала.

 MethodA()
 {
   Logger obj=new Logger();
   obj.ErrorMessage="Failure";
 }
  

В этом случае на платформе x86 трассировка стека содержит два стековых фрейма. Один для methodaи другой для установщика свойства ErrorMessage.

На платформе x64 трассировка стека содержит только один stackframe для methodA и отсутствует stackframe для установщика свойства ErrorMessage.

Кто-нибудь может мне объяснить, как происходит оптимизация при получении трассировки стека?

Комментарии:

1. Где MethodA происходит вызов? Этот код не завершен.

2. Перекрестная публикация: social.msdn.microsoft.com/Forums/en/csharplanguage/thread /…

Ответ №1:

Я не вижу никакой разницы между выводами x64 и x86, когда я пытаюсь получить вывод трассировки стека в тестовом жгуте. (Я не ожидал этого, но я всегда хочу оспорить свои предположения!).

Единственный раз, когда я ожидаю увидеть разницу в стеке вызовов, — это когда вы компилируете код в режиме выпуска. Когда вы делаете это, дрожание часто приводит к встроенным вызовам простых методов, например, установщика вашего свойства. (Да, если вы поразмыслите над своим кодом в режиме выпуска, вы будете по-прежнему видеть отдельные методы; вы увидите это различие только тогда, когда метод JITted)

Для вас это означает, что при отладке установщик появится в стеке вызовов:

    at ConsoleApplication5.Program.set_ErrorMessage(String value)
   at ConsoleApplication5.Program.MethodA()
   at ConsoleApplication5.Program.Main(String[] args)
  

Но когда вы скомпилируете его в режиме выпуска, код внутри set_ErrorMessage будет встроен в methodA, что означает, что вы увидите только это:

    at ConsoleApplication5.Program.MethodA()
   at ConsoleApplication5.Program.Main(String[] args)
  

Эта оптимизация настраивается в свойствах проекта на вкладке Сборка. При переключении между отладкой и выпуском в раскрывающемся списке конфигурации вы увидите разницу в флажке «Оптимизировать код». Да, вы могли бы отключить оптимизацию компилятора для релизных сборок, но тогда вы потенциально снизили бы производительность вашего приложения, чего я бы не рекомендовал.

Ответ №2:

Я подозреваю, что на x64 JIT встраивается (оптимизируется) более агрессивно. Попробуйте выполнить следующее, чтобы убедиться, что это так, или просто запустите в режиме отладки, где оптимизации, влияющие на отладку, должны быть отключены:

     public string ErrorMessage
    {
      [MethodImplAttribute(MethodImplOptions.NoInlining)]
      set
        {
         _strErrorMessage = "Error : "   value;
         //Call the method to log error.
         LogError(value);
        }
    }
  

Комментарии:

1. Да, это кажется разумной теорией. 64-разрядный джиттер часто работает иначе, чем 32-разрядный джиттер, вплоть до принимаемых им решений о том, следует ли выполнять встроенные вызовы методов.