F # производительность в научных вычислениях - PullRequest
71 голосов
/ 02 мая 2010

Мне интересно, как производительность F # сравнивается с производительностью C ++? Я задал аналогичный вопрос в отношении Java, и у меня сложилось впечатление, что Java не подходит для обработки больших чисел.

Я читал, что F # должен быть более масштабируемым и более производительным, но как эта реальная производительность сравнивается с C ++? конкретные вопросы о текущей реализации:

  • Насколько хорошо это работает с плавающей запятой?
  • Позволяет ли векторная инструкция
  • насколько дружелюбно это к оптимизации Составители?
  • Насколько большой у него отпечаток памяти? Позволяет ли это детально контролировать локальность памяти?
  • есть ли у него емкость для распределенной процессоры памяти, например Cray?
  • какие функции он может представлять интерес для вычислительной науки, где используется обработка больших чисел?
  • Существуют ли реальные научные вычисления реализации, которые его используют?

Спасибо

Ответы [ 10 ]

62 голосов
/ 10 мая 2010

Мне интересно, как производительность F # сравнивается с производительностью C ++?

Дико меняется в зависимости от приложения. Если вы интенсивно используете сложные структуры данных в многопоточной программе, то F #, вероятно, будет большой победой. Если большая часть вашего времени тратится на сжатие числовых циклов, мутирующих массивов, то C ++ может быть в 2-3 раза быстрее.

Пример: трассировщик лучей Мой тест здесь использует дерево для иерархической выборки и числовой код пересечения лучевой сферы для генерации выходного изображения. Этому бенчмарку уже несколько лет, и код C ++ совершенствовался десятки раз за эти годы и читался сотнями тысяч людей. Дон Сайм из Microsoft сумел написать реализацию F #, которая немного быстрее , чем самый быстрый код C ++ при компиляции с MSVC и распараллеливании с использованием OpenMP.

Я читал, что F # должен быть более масштабируемым и более производительным, но как эта реальная производительность сравнивается с C ++?

Разработка кода намного проще и быстрее с F #, чем C ++, и это относится как к оптимизации, так и к обслуживанию. Следовательно, когда вы начнете оптимизировать программу, тот же объем усилий даст гораздо больший прирост производительности, если вы будете использовать F # вместо C ++. Тем не менее, F # является языком более высокого уровня и, следовательно, устанавливает более низкий потолок производительности. Поэтому, если у вас есть бесконечное время на оптимизацию, вы, теоретически, должны всегда иметь возможность создавать более быстрый код на C ++.

Это точно то же преимущество, которое C ++ имел по сравнению с Fortran, а Fortran, конечно, по сравнению с рукописным ассемблером.

Пример: QR-декомпозиция Это базовый численный метод линейной алгебры, предоставляемый такими библиотеками, как LAPACK. Эталонная реализация LAPACK - 2077 строк Fortran. Я написал реализацию F # в менее чем 80 строках кода, которая обеспечивает тот же уровень производительности. Но эталонная реализация не быстрая: настроенные производителем реализации, такие как Math Kernel Library (MKL) от Intel, часто бывают в 10 раз быстрее. Примечательно, что мне удалось оптимизировать мой код F # на 1027 * больше, чем производительность реализации Intel, работающей на аппаратном обеспечении Intel, при этом мой код не превышал 150 строк кода и полностью универсален (он может обрабатывать одинарную и двойную точность, а также сложный и четные символьные матрицы!): для высоких тонких матриц мой код F # в 3 раза быстрее, чем Intel MKL.

Обратите внимание, что мораль этого примера не в том, что вы ожидаете, что ваш F # будет быстрее, чем в библиотеках, настроенных вендором, а в том, что даже такие эксперты, как Intel, упустят продуктивные высокоуровневые оптимизации, если они будут использовать только низкоуровневые языки. Я подозреваю, что эксперты Intel по численной оптимизации не смогли полностью использовать параллелизм, потому что их инструменты делают его чрезвычайно громоздким, тогда как F # делает его легким.

Насколько хорошо он работает с плавающей запятой?

Производительность аналогична ANSI C, но некоторые функции (например, режимы округления) недоступны в .NET.

Позволяет ли векторная инструкция

номер

Насколько дружественна оптимизация компиляторов?

Этот вопрос не имеет смысла: F # является проприетарным языком .NET от Microsoft с одним компилятором.

Насколько большой отпечаток памяти у него есть?

Пустое приложение использует 1,3 Мбайт здесь.

Позволяет ли он детально контролировать локальность памяти?

Лучше, чем большинство языков, безопасных для памяти, но не так хорошо, как C. Например, вы можете распаковать произвольные структуры данных в F #, представив их как «структуры».

имеет ли он емкость для процессоров с распределенной памятью, например Cray?

Зависит от того, что вы подразумеваете под «способностью к». Если вы можете запустить .NET на этом Cray, тогда вы можете использовать передачу сообщений в F # (как и в следующем языке), но F # предназначен главным образом для настольных многоядерных машин x86.

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

Безопасность памяти означает, что вы не получаете ошибок сегментации и нарушений доступа. Поддержка параллелизма в .NET 4 хороша. Возможность выполнять код на лету через интерактивный сеанс F # в Visual Studio 2010 чрезвычайно полезна для интерактивных технических вычислений.

Существуют ли реальные научные вычислительные реализации, которые его используют?

Наши коммерческие продукты для научных вычислений на F # уже имеют сотни пользователей.

Однако ваша линия вопросов указывает на то, что вы думаете о научных вычислениях как о высокопроизводительных вычислениях (например, Cray), а не о интерактивных технических вычислениях (например, MATLAB, Mathematica). F # предназначен для последнего.

42 голосов
/ 02 мая 2010

В дополнение к тому, что говорили другие, в F # есть еще один важный момент: параллелизм . Производительность обычного кода F # определяется CLR, хотя вы можете использовать LAPACK из F # или выполнять собственные вызовы, используя C ++ / CLI как часть вашего проекта.

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

Что касается распределенных вычислений, вы можете использовать любую среду распределенных вычислений, доступную для платформы .NET. Есть проект MPI.NET, который хорошо работает с F #, но вы также можете использовать DryadLINQ, который является проектом MSR.

40 голосов
/ 05 мая 2010
  • F # выполняет вычисления с плавающей запятой настолько быстро, насколько это позволяет .NET CLR. Не так много отличий от C # или других языков .NET.
  • F # не разрешает векторные инструкции самостоятельно, но если в вашем CLR есть API для них, у F # не должно быть проблем с его использованием. Например, Mono .
  • Насколько я знаю, на данный момент существует только один компилятор F #, поэтому, возможно, вопрос должен звучать так: «Насколько хорош компилятор F #, когда дело доходит до оптимизации?». В любом случае, ответ «потенциально такой же хороший, как и у компилятора C #, возможно, чуть хуже». Обратите внимание, что F # отличается от, например, C # поддерживает вставку во время компиляции, что потенциально позволяет создавать более эффективный код, основанный на обобщениях.
  • Отпечатки в памяти программ F # аналогичны другим языкам .NET. Уровень контроля над распределением и сборкой мусора такой же, как и в других языках .NET.
  • Я не знаю о поддержке распределенной памяти.
  • F # имеет очень хорошие примитивы для работы с плоскими структурами данных, например массивы и списки. Посмотрите, например, на содержимое модуля Array: map, map2, mapi, iter, fold, zip ... Массивы популярны в научных вычислениях, я полагаю, из-за их хороших свойств локальности памяти.
  • Для пакетов научных вычислений, использующих F #, вы можете посмотреть, что делает Джон Харроп.
16 голосов
/ 02 мая 2010

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

F # является производной OCaml. Я был удивлен, узнав, что OCaml часто используется в финансовом мире, где очень важна эффективность анализа чисел. Кроме того, я был удивлен, узнав, что OCaml - один из самых быстрых языков, с производительностью на уровне самых быстрых компиляторов C и C ++.

F # построен на CLR . В CLR код выражается в форме байт-кода, называемого Common Intermediate Language. Как таковой, он извлекает выгоду из возможностей оптимизации JIT и имеет производительность, сравнимую с C # (но не обязательно C ++), если код написан хорошо.

CIL-код может быть скомпилирован в собственный код на отдельном этапе перед выполнением с помощью Native Image Generator (NGEN). Это ускоряет все последующие запуски программного обеспечения, поскольку компиляция CIL-to-native больше не требуется.

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

9 голосов
/ 03 мая 2010

Это зависит от того, какие научные вычисления вы делаете.

Если вы делаете traditional heavy computing, например, линейная алгебра, различные оптимизации, то вам не следует помещать свой код в .Net Framework, по крайней мере, не подходит в F #. Поскольку это на уровне алгоритма, большинство алгоритмов должны быть написаны на императивных языках, чтобы иметь хорошую производительность во время выполнения и использовании памяти. Другие упоминали параллель, я должен сказать, что, вероятно, бесполезно, когда вы делаете низкоуровневые вещи, такие как параллельная реализация SVD. Потому что, когда вы знаете, как подключать SVD, вы просто не будете использовать языки высокого уровня, Fortran, C или модифицированный C (например, cilk ) ваши друзья.

Однако сегодня многие научные вычисления не относятся к этому типу, а являются приложениями высокого уровня, например статистические вычисления и интеллектуальный анализ данных. В этих задачах, кроме какой-то линейной алгебры или оптимизации, также есть много потоков данных, операций ввода-вывода, предварительного выделения, выполнения графики и т. Д. Для этих задач F # действительно мощный, для своей краткости, функциональности, безопасности, легко параллельно и т. д.

Как уже упоминалось, .Net хорошо поддерживает Platform Invoke, на самом деле довольно много проектов внутри MS используют .Net и P / Invoke вместе, чтобы улучшить производительность на узком месте.

7 голосов
/ 02 мая 2010

Я не думаю, что вы найдете много надежной информации, к сожалению. F # - все еще очень новый язык, поэтому, даже если бы он идеально подходил для рабочих нагрузок с высокой производительностью, все равно не было бы так много людей, обладающих значительным опытом работы. Кроме того, производительность очень трудно точно измерить, а микробенчмарки сложно обобщить. Даже в C ++ вы можете увидеть существенные различия между компиляторами - вам интересно, конкурирует ли F # с любым C ++ компилятором или с гипотетическим «наилучшим возможным» исполняемым C ++?

Что касается конкретных тестов по сравнению с C ++, вот несколько возможных ссылок: O'Caml против F #: декомпозиция QR ; F # против неуправляемого C ++ для параллельных чисел . Обратите внимание, что как автор материала, связанного с F #, и как поставщик инструментов F # автор очень заинтересован в успехе F #, поэтому отнеситесь к этим утверждениям с большой долей соли.

Я думаю, можно с уверенностью сказать, что будут некоторые приложения, где F # конкурентоспособен по времени выполнения, и, вероятно, некоторые другие, где это не так. F #, вероятно, потребует больше памяти в большинстве случаев. Конечно, конечная производительность также будет сильно зависеть от навыков программиста - я думаю, что F # почти наверняка будет более продуктивным языком для программирования для умеренно компетентного программиста. Кроме того, я думаю, что в настоящее время CLR в Windows работает лучше, чем Mono в большинстве ОС, для большинства задач, что также может повлиять на ваши решения. Конечно, поскольку F #, вероятно, легче распараллелить, чем C ++, это также будет зависеть от типа оборудования, на котором вы планируете работать.

В конечном счете, я думаю, что единственный способ действительно ответить на этот вопрос - написать код на F # и C ++, представляющий тип вычислений, которые вы хотите выполнить, и сравнить их.

4 голосов
/ 05 мая 2010

Вот два примера, которыми я могу поделиться:

  1. Умножение матриц: У меня есть запись в блоге , в которой сравниваются различные реализации умножения матриц .

  2. LBFGS

У меня есть крупномасштабный решатель логистической регрессии, использующий оптимизацию LBFGS, которая написана на C ++. Реализация хорошо настроена. Я изменил некоторый код для кода в C ++ / CLI, то есть я скомпилировал код в .Net. Версия .Net в 3–5 раз медленнее, чем скомпилированная наивная в разных наборах данных. Если вы кодируете LBFGS на F #, производительность не может быть лучше, чем в C ++ / CLI или C # (но это будет очень близко).

У меня есть еще один пост на Почему F # является языком для интеллектуального анализа данных , хотя он не совсем связан с проблемой производительности, о которой вы здесь говорите, он довольно тесно связан с научными вычислениями в F #.

3 голосов
/ 13 октября 2010

Если я скажу «спросите еще раз через 2-3 года», я думаю, что это полностью ответит на ваш вопрос :-)

Во-первых, не ожидайте, что F # будет отличаться от C #, если только вы не намеренно выполняете некоторые запутанные рекурсии, и я полагаю, что это не так, поскольку вы спрашивали о числах.

С плавающей точкой он обязательно будет лучше, чем Java, поскольку CLR не стремится к кросс-платформенному единообразию, а это означает, что JIT будет переходить на 80-бит, когда это возможно. С другой стороны, вы не контролируете это, не наблюдая за количеством переменных, чтобы убедиться, что регистров FP достаточно.

По вектору, если вы кричите достаточно громко, возможно, что-то произойдет через 2-3 года, поскольку Direct3D все равно входит в .NET как общий API, а код C #, выполненный в XNA, работает на Xbox, который настолько близок к голому металлу, насколько это возможно. получить с CLR. Это по-прежнему означает, что вам понадобится сделать некоторый посреднический код самостоятельно.

Так что не ожидайте, что CUDA или даже способность просто связать библиотеки NVIDIA и начать работу. Вам бы гораздо больше повезло, если бы вы попробовали этот подход с Haskell, если по какой-то причине вам действительно нужен «функциональный» язык, поскольку Haskell был разработан так, чтобы он был дружественным по отношению к ссылкам из чистой необходимости.

Mono.Simd уже упоминался, и хотя он должен быть обратно переносимым в CLR, для его выполнения может потребоваться определенная работа.

В social.msdn содержится довольно много кода о том, как использовать SSE3 в .NET, с C ++ / CLI и C #, происходит разбиение массива, вводится код SSE3 для перфорации и т. Д.

Были разговоры о запуске CECIL на скомпилированном C # для извлечения деталей в HLSL, компиляции в шейдеры и связывания связующего кода для его планирования (CUDA в любом случае делает эквивалент), но я не думаю, что что из этого выйдет что-нибудь пригодное для работы.

Если вы захотите попробовать что-то еще, возможно, стоит больше: PhysX.Net на codeplex . Не ожидайте, что это просто распаковать и сделать магию. Тем не менее, ih в настоящее время является активным автором, и код является как обычным C ++, так и C ++ / CLI, и yopu, возможно, может получить некоторую помощь от автора, если вы хотите углубиться в детали и, возможно, использовать аналогичный подход для CUDA. Для полной скорости CUDA вам все равно нужно скомпилировать свои собственные ядра, а затем просто подключиться к .NET, так что чем проще эта часть, тем счастливее вы будете.

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

Да, и если у вас есть бюджет, вы можете взглянуть на Psi Lambda (KappaCUDAnet - это часть .NET). Очевидно, они собираются поднять цены в ноябре (если это не уловка продаж: -)

1 голос
/ 18 июня 2010

Во-первых, C значительно быстрее, чем C ++. Поэтому, если вам нужна такая большая скорость, вы должны сделать lib и т.д. в c.

Что касается F #, то большинство тестов используют Mono, который на 2 * медленнее, чем MS CLR, частично благодаря использованию GC Boehm (у них есть новые GC и LVVM, но они все еще незрелые, не поддерживают дженерики и т.д.) ,

.NEt сами языки компилируются в IR (CIL), который компилируется в нативный код так же эффективно, как C ++. Существует одна проблема, от которой страдает большинство языков GC, и это большое количество изменяемых записей (включая C ++ .NET, как упомянуто выше). И есть определенный научный набор проблем, который требует этого, эти при необходимости, вероятно, должны использовать собственную библиотеку или использовать шаблон Flyweight для повторного использования объектов из пула (что уменьшает количество записей). Причина в том, что в .NET CLR существует барьер записи, при котором при обновлении ссылочного поля (включая поле) он устанавливает бит в таблице, говоря, что эта таблица изменена. Если ваш код состоит из множества таких записей, он пострадает.

Тем не менее, приложение .NET, такое как C #, использующее много статического кода, структур и ref / out на структурах, может производить C-подобную производительность, но очень трудно кодировать подобное или поддерживать код (например, C).

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

Что касается плавающей запятой, вам следует использовать альтернативную библиотеку (т.е. .Net) для oCaml из-за ее медленной работы. C / C ++ позволяет быстрее для более низкой точности, что oCaml не делает по умолчанию.

Наконец, я утверждаю, что язык высокого уровня, такой как C #, F # и правильное профилирование, даст вам лучшую производительность, чем c и C ++ в то же время для разработчика. Если вы измените горлышко бутылки на вызов c lib pinvoke, вы также получите производительность, подобную C, для критических областей. Тем не менее, если у вас неограниченный бюджет и вы больше заботитесь о скорости, то обслуживание, а не C, - это путь (не C ++).

1 голос
/ 02 мая 2010

Последнее, что я знал, большинство научных вычислений все еще делалось на Фортране. Это все еще быстрее, чем что-либо еще для задач линейной алгебры - не Java, не C, не C ++, не C #, не F #. LINPACK хорошо оптимизирован.

Но замечание о «вашем пробеге может отличаться» верно для всех тестов. Общие заявления (кроме моего) редко бывают правдой.

...