Моя 32-битная головная боль теперь является 64-битной мигренью?!? (или 64-битные проблемы .NET CLR Runtime) - PullRequest
9 голосов
/ 11 марта 2009

Какие необычные, неожиданные последствия произошли с точки зрения производительности, памяти и т. Д. При переходе от запуска приложений .NET под 64-битным JIT по сравнению с 32-битным JIT? Меня интересуют хорошие, но больше интересуют удивительно плохие проблемы, с которыми сталкиваются люди.

Я нахожусь в процессе написания нового приложения .NET, которое будет развернуто как в 32-битной, так и в 64-битной среде. Было много вопросов, связанных с портированием приложения - меня не беспокоит "ловушка" с точки зрения программирования / переноса . (т.е.: правильная обработка собственного взаимодействия / COM, ссылочные типы, встроенные в структуры, изменение размера структуры и т. д.)

Однако, этот вопрос и его ответ заставили меня задуматься - Какие еще вопросы я пропускаю?

Было много вопросов и сообщений в блоге, которые касаются этой проблемы или затрагивают один ее аспект, но я не видел ничего, что составило бы достойный список проблем.

В частности - мое приложение сильно связано с процессором и имеет огромные шаблоны использования памяти (отсюда и необходимость в 64-битной среде), а также графическое изображение. Я обеспокоен тем, какие другие скрытые проблемы могут существовать в CLR или JIT, работающем в 64-битной Windows (с использованием .NET 3.5sp1).

Вот несколько вопросов, о которых я знаю в данный момент:

Хотелось бы узнать, какие другие, специфические проблемы обнаружены в JIT в 64-битной Windows, а также есть ли какие-либо обходные пути для повышения производительности.

Спасибо всем!

---- EDIT -----

Просто чтобы уточнить -

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

Однако мое приложение не является типичным бизнес-приложением. Это научное приложение. У нас есть много процессов, которые используют 100% ЦП на всех ядрах (это очень многопоточно) по несколько часов подряд.

Я трачу МНОГО времени на профилирование приложения, и это имеет огромное значение. Однако большинство профилировщиков отключают многие функции JIT, поэтому мелкие детали в таких вещах, как распределение памяти, встраивание в JIT и т. Д., Могут быть очень трудно определить, когда вы работаете под профилировщиком. Отсюда моя потребность в вопросе.

Ответы [ 8 ]

4 голосов
/ 25 февраля 2010

Особенно проблемная проблема производительности в .NET связана с плохим JIT:

https://connect.microsoft.com/VisualStudio/feedback/details/93858/struct-methods-should-be-inlined?wa=wsignin1.0

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

В любом случае, после достаточно долгой борьбы с .NET мое решение состоит в том, чтобы использовать C ++ для чего-либо численного. Даже в «хороших» случаях для .NET, где вы не имеете дело со структурами и используете массивы, в которых оптимизирована проверка границ, C ++ превосходит .NET , опуская руки .

Если вы делаете что-то более сложное, чем точечные продукты, картина очень быстро ухудшается; код .NET одновременно длиннее + менее читабелен (потому что вам нужно встроить что-то вручную и / или не может использовать дженерики) и намного медленнее.

Я перешел на использование Eigen в C ++: это великолепно, что приводит к читабельности кода и высокой производительности; тонкая оболочка C ++ / CLI обеспечивает связь между вычислительным движком и миром .NET.

Собственные работы по шаблонному метапрограммированию; компилирует векторные выражения во внутренние инструкции SSE и выполняет для вас множество самых отвратительных циклов, связанных с кэшем, которые вы можете развернуть и перегруппировать; и хотя он сфокусирован на линейной алгебре, он будет работать и с целыми числами, и с выражениями нематричных массивов.

Так, например, если P является матрицей, это просто работает:

1.0 /  (P.transpose() * P).diagonal().sum();

... который не выделяет временно транспонированный вариант P и не вычисляет весь матричный продукт, а только необходимые ему поля.

Итак, если вы можете работать в режиме полного доверия - просто используйте C ++ через C ++ / CLI, это работает намного лучше.

3 голосов
/ 11 марта 2009

Я помню, как часто слышал проблему с IRC-канала. Это оптимизирует временную копию в этом случае:

EventHandler temp = SomeEvent;
if(temp != null)
{
    temp(this, EventArgs.Empty);
}

Восстановление состояния гонки и создание возможных исключений нулевых ссылок.

1 голос
/ 12 декабря 2009

Об ответе Quibblesome:

Я попытался запустить следующий код в моей Windows 7 x64 в режиме выпуска без отладчика, и NullReferenceException никогда не выдавалось .

using System;
using System.Threading;

namespace EventsMultithreadingTest
{
    public class Program
    {
        private static Action<object> _delegate = new Action<object>(Program_Event);
        public static event Action<object> Event;

        public static void Main(string[] args)
        {
            Thread thread = new Thread(delegate()
                {
                    while (true)
                    {
                        Action<object> ev = Event;

                        if (ev != null)
                        {
                            ev.Invoke(null);
                        }
                    }
                });
            thread.Start();

            while (true)
            {
                Event += _delegate;
                Event -= _delegate;
            }
        }

        static void Program_Event(object obj)
        {
            object.Equals(null, null);
        }
    }
}
1 голос
/ 11 марта 2009

Вы упомянули проблемы с портированием, это те, о которых нужно беспокоиться. Я (очевидно) не знаю ваше приложение, но попытка угадать JIT часто является пустой тратой времени. Люди, которые пишут JIT, хорошо разбираются в архитектуре чипа x86 / x64 и, по всей вероятности, знают, что работает лучше, а что хуже, чем кто-либо другой на планете.

Да, возможно, у вас есть угловой случай, который отличается и уникален, но если вы «в процессе написания нового приложения», то я не буду беспокоиться о компиляторе JIT , Скорее всего, где-то можно избежать глупой петли, которая даст вам 100-кратное улучшение производительности, которое вы получите от попытки угадать JIT. Напоминает мне о проблемах, с которыми мы столкнулись при написании нашего ORM, мы смотрели на код и думали, что могли бы извлечь из него пару машинных инструкций ... конечно, код затем отключился и подключился к серверу базы данных по сети Таким образом, мы обрезали микросекунды от процесса, который был ограничен миллисекундами где-то еще.

Универсальное правило настройки производительности ... Если вы не измерили свою производительность, вы не не знаете , где ваши узкие места, вы просто думаете вы знаете ... и вы, вероятно, ошибаетесь.

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

Большую часть времени Visual Studio и компилятор довольно хорошо скрывают проблемы от вас. Однако я знаю об одной серьезной проблеме, которая может возникнуть, если вы настроите свое приложение на автоматическое определение платформы (x86 против x64) , а также у есть какие-либо зависимости от 32-битных сторонних библиотек. В этом случае на 64-битных платформах он будет пытаться вызывать dll, используя 64-битные соглашения и структуры, и он просто не будет работать.

0 голосов
/ 06 февраля 2010

Профилировщик не должен существенно влиять на ваши результаты синхронизации. Если накладные расходы профилировщика действительно"значительны", то вы, вероятно, не сможете выжать гораздо большую скорость из своего кода, и вам следует подумать о поиске узких мест вашего оборудования (диска, ОЗУ или ЦП?) И модернизация. (Звучит так, как будто вы привязаны к процессору, вот с чего начать)

В целом .net и JIT освобождают вас от большинства проблем переноса 64-битных систем. Как вы знаете, существуют эффекты, относящиеся к размеру регистра (изменения использования памяти, маршалинг для собственного кода, необходимость для всех частей программы иметь собственные 64-битные сборки) и некоторые различия в производительности (большая карта памяти, больше регистров, более широкие шины и т.д.), поэтому я не могу сказать вам больше, чем вы уже знаете об этом. Другие проблемы, с которыми я сталкивался, связаны с ОС, а не с C # - теперь существуют разные кусты реестра для 64-битных приложений и приложений WOW64, например, поэтому некоторые обращения к реестру должны быть написаны аккуратно.

Обычно плохая идея беспокоиться о том, что JIT будет делать с вашим кодом, и пытаться настроить его так, чтобы он работал лучше, потому что JIT, вероятно, изменится с .net 4, 5 или 6, и ваши «оптимизации» могут обернуться в неэффективность или, что еще хуже, ошибки. Также имейте в виду, что JIT компилирует код специально для процессора, на котором он работает, поэтому потенциально улучшение вашего ПК для разработки может не быть улучшением на другом ПК. То, что вам не нравится с использованием сегодняшнего JIT на сегодняшнем процессоре, может укусить вас через годы, когда вы что-то обновите.

В частности, вы цитируете «свойства не встроены в x64». К тому времени, как вы пройдете всю свою кодовую базу, превратив все свои свойства в поля, вполне может появиться новый JIT для 64-битных, который имеет встроенные свойства. Действительно, он может работать лучше, чем ваш «обходной» код. Позвольте Microsoft оптимизировать это для вас.

Вы справедливо указываете, что ваш профиль памяти может измениться. Таким образом, вам может понадобиться больше оперативной памяти, более быстрые диски для виртуальной памяти и больший кэш-память процессора. Все проблемы с оборудованием. Вы можете уменьшить эффект, используя (например) Int32, а не int, но это может не иметь большого значения и может потенциально снизить производительность (поскольку ваш ЦП может обрабатывать собственные 64-разрядные значения более эффективно, чем 32-разрядные значения половинного размера). ).

Вы говорите, что «время запуска может быть больше», но это кажется довольно неуместным в приложении, которое, по вашему мнению, работает в течение часов при 100% ЦП.

Так о чем вы действительно беспокоитесь? Может быть, время вашего кода на 32-разрядном компьютере, а затем время выполнения той же задачи на 64-разрядном компьютере. Есть ли разница в получасе за 4 часа? Или разница всего 3 секунды? Или 64-битный ПК на самом деле быстрее? Может быть, вы ищете решения проблем, которые не существуют.

Итак, вернемся к обычному, более общему совету. Профиль и время для выявления узких мест. Посмотрите на алгоритмы и математические процессы, которые вы применяете, и попробуйте улучшить / заменить их более эффективными. Убедитесь, что ваш многопоточный подход помогает, а не наносит ущерб вашей производительности (то есть избегаются блокировки и ожидания). Попробуйте уменьшить выделение / освобождение памяти - например, повторно использовать объекты, а не заменять их новыми. Попробуйте сократить использование частых вызовов функций и виртуальных функций. Переключитесь на C ++ и избавьтесь от накладных расходов на сборку мусора, проверку границ и т. Д., Которые навязывает .net. Хммм. Ничто из этого не имеет ничего общего с 64-битным, не так ли?

0 голосов
/ 06 февраля 2010

Я считаю, что 64 JIT не полностью разработан / перенесен, чтобы использовать преимущества таких процессоров 64-битной архитектуры, поэтому у него есть проблемы, возможно, вы получаете «эмулированное» поведение ваших сборок, которое может вызвать проблемы и непредвиденное поведение. Я хотел бы изучить случаи, когда этого можно избежать, и / или, возможно, посмотреть, есть ли хороший быстрый компилятор 64 c ++ для написания критичных ко времени вычислений и алгоритмов. Но даже если у вас возникают трудности с поиском информации или у вас нет времени на чтение разобранного кода, я вполне уверен, что выполнение сложных вычислений вне управляемого кода уменьшит любые проблемы, которые могут у вас возникнуть, и повысит производительность [в некоторой степени уверен, что вы уже делаете это но просто упомянуть :)]

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

Я не настолько знаком с 64-битными проблемами, но у меня есть один комментарий:

Мы должны забыть о маленьких эффективность, скажем, около 97% время: преждевременная оптимизация корень всех зол. - Дональд Кнут

...