Сравнение производительности программ на некоторых языках (Посвящается тормозам байткода)

Модератор: Модераторы разделов

v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Сравнение производительности программ на некоторых языках

Сообщение v04bvs »

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

Я провёл небольшое тестирование, где сравниваются C, D, Scheme, Pascal, Java
Компиляторы - gcc, dmd, gdc, stalin, sun jde, fpc

В качестве теста на всех языках считается функция Фибоначчи от числа 45.
Функция намеренно реализована неэффективно. Особенность реализации в том, что функция будет вызываться очень часто.
Её текст на C:

Код: Выделить всё

unsigned fibonacci(unsigned n) {
    return n == 0 ? 0 : n == 1 ? 1 : fibonacci(n - 1) + fibonacci(n - 2);
}

На остальных языках код аналогичен, с точностью до синтаксиса.

Каждый тест запускался 3 раза. Время замерялось командой time.
Некоторые характеристики тестовой машины: CPU: Pentium D 3 GHz (dual core); RAM: 2 GiB

Результаты теста:

Код:

c-O0 (1) real 0m25.608s user 0m25.530s sys 0m0.000s c-O0 (2) real 0m26.141s user 0m25.700s sys 0m0.100s c-O0 (3) real 0m25.603s user 0m25.430s sys 0m0.020s c-O3 (1) real 0m8.909s user 0m8.880s sys 0m0.010s c-O3 (2) real 0m8.921s user 0m8.890s sys 0m0.020s c-O3 (3) real 0m9.271s user 0m9.070s sys 0m0.060s d-dmd (1) real 0m23.863s user 0m23.490s sys 0m0.070s d-dmd (2) real 0m24.415s user 0m24.030s sys 0m0.070s d-dmd (3) real 0m23.819s user 0m23.320s sys 0m0.170s d-gdc (1) real 0m9.098s user 0m8.940s sys 0m0.050s d-gdc (2) real 0m9.077s user 0m8.910s sys 0m0.030s d-gdc (3) real 0m9.233s user 0m9.050s sys 0m0.020s scheme (1) real 0m38.923s user 0m38.770s sys 0m0.070s scheme (2) real 0m39.553s user 0m38.630s sys 0m0.390s scheme (3) real 0m39.363s user 0m39.000s sys 0m0.040s java (1) real 0m12.731s user 0m12.680s sys 0m0.010s java (2) real 0m12.828s user 0m12.770s sys 0m0.000s java (3) real 0m12.762s user 0m12.610s sys 0m0.010s pascal (1) real 0m23.176s user 0m22.800s sys 0m0.090s pascal (2) real 0m21.799s user 0m21.790s sys 0m0.010s pascal (3) real 0m21.670s user 0m21.640s sys


Как видно, Java опережает многие компилируемые языки, и вплотную приближается к C. К сожалению протестировать C# нет возможности.
Надеюсь, этот пример развеет миф о том, что байткод == тормоз.
Спасибо сказали:
Аватара пользователя
Shura
Сообщения: 1537
Статус: Оказывается и без KDE есть жизнь
ОС: FreeBSD 8.0-RC2

Re: Сравнение производительности программ на некоторых языках

Сообщение Shura »

не развеет, это частный случай :)
Rock'n'roll мертв © БГ
Спасибо сказали:
Аватара пользователя
dey
Сообщения: 335
ОС: OpenSuse 11.1

Re: Сравнение производительности программ на некоторых языках

Сообщение dey »

Shura писал(а):
16.07.2007 16:12
не развеет, это частный случай :)

Зато рекурсия достаточно наглядный пример(имхо)
В сознательных действиях должен присутствовать существенный неалгоритмический компонент.
Roger Penrose,The Emperor's New Mind
Спасибо сказали:
Аватара пользователя
Liksys
Сообщения: 2910

Re: Сравнение производительности программ на некоторых языках

Сообщение Liksys »

dey писал(а):
16.07.2007 17:15
Shura писал(а):
16.07.2007 16:12
не развеет, это частный случай :)

Зато рекурсия достаточно наглядный пример(имхо)

Наглядный, но частный (Shura, +1). Тест это одно, а вот реальное приложение - это совсем другое. Тем более это банальный вызов функции, надо уж (коли тема навеяна сишарпом) использовать больше возможностей, который применяются в реальном программировании, в том числе и управление памятью. Так же при тестировании следует учитывать алгоритмы и возможности гравицап (сиреч, Garbage Collector, GC) конкретной реализации языка и тд.
Байт-код это хорошо, однако он не везде и уместен. Каким бы не был язык с байт-кодом, по контролируемости и надежности (при малом радиусе кривизны рук программиста) не сможет превзойти "чисто" компилируемые языки. Вероятность нестабильного кода увеличиватеся почти вдвое, поскольку (1) к своим ошибкам добавляются еще и глюки виртуальной машины, (2) как правило, языки с компиляцией в байт-код и с автоматическим распределением памяти тратят еебольше, чем при ручном управлении. Я ничего не имею против GC, но встраивать его во что не попадя тоже не вариант. В T++ (использующийся в T-системах) он например вполне оправдан. Но когда доходит до системного программирования, ничего лучше, чем компиляция и ручное распределение памяти пока не придумали.
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: Сравнение производительности программ на некоторых языках

Сообщение t.t »

Ну, Лексус прошёлся со стороны си и си-шарпа, добавлю-ка я со стороны схемы. Начнём с того, что сталин -- это не самый оптимальный компилятор схемы. Касательно именно схемы конкретно говорить не могу, но наверняка тот же sbcl (Common Lisp) дал бы значительно лучшие результаты. Кроме того, для полного анализа нужен код, который сам по себе может быть на схеме менее оптимален, чем на яве. Ну и последнее: лисп-подобные языки отличаются в первую очередь стилем программирования, точнее -- высоким требованием к стилю. Другими словами, ява не плоха сама по себе, как язык или платформа; ява плоха тем, что даёт низкий порог вхождения, не подталкивая при этом к хорошему стилю даже не столько разработки, сколько проектирования; что и приводит к лавинообразному накоплению "быдлокодеров" -- а следовательно, соответствующему качеству кода.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Slimy
Сообщения: 1689
ОС: openSuSE 11.2 GM (GеMор едишн)

Re: Сравнение производительности программ на некоторых языках

Сообщение Slimy »

Хм соглашусь с тем что это частный случай. Во вторых разница будет разителньовидна при некотором недостатке памяти в системе а на 2х гигах проблем естесвенно нет. К томуже Java приближается а не обгоняет вот оно в чем дело то. И еще работа с указателями массивами и т.д. думаю тоже бы не плохо проверить сам механизм указателей дает выгоду. Так что справедливо проверить и это. Кстати сюдаже добавить кол-во используемой памяти да еще память под интерпретаторы т.к. одновременно.
В любом случае тут колесо изобретается ну даже на первом курсе в универе проходят что интерпретация заведома медленнее + время на запуск программы больше . Для видимых результатов надо проверить на медленном процессоре.
Если уже ничего не помогает - прочти инструкцию.
sysinstall - гадость :)
ASUS A6q00Vm Pentium-M 1.7 GHz, 2Gb RAM, 160Gb HDD,
GeForce Go 7300 64Mb video
Спасибо сказали:
Mellon
Сообщения: 655
Статус: Powered by Gentoo
ОС: Gentoo

Re: Сравнение производительности программ на некоторых языках

Сообщение Mellon »

где же те времена когда для снижения темпа вставляли пустые циклы? :cry:

гыгыгы
Некоммерческий файлообмен не может сравниваться с кражей, так как кража лишает кого-то возможности использовать украденный объект. ©
--------------------
Переворачиватель пингвинов
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Сравнение производительности программ на некоторых языках

Сообщение serzh-z »

dey писал(а):
16.07.2007 17:15
Зато рекурсия достаточно наглядный пример(имхо)
Если сравнить ассемблерный код вышеуказанного примера для -O0 и -O3, то легко заметить, что компилятор развернул лишь один вызов () - все остальные рекурсивные вызовы сохранились. Скажем, один вызов для числа 500 разворачивает в два - вызова fibonacci для чисел 499 и 498... Вот и вся, по большей части, оптимизация рекурсии.
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Сравнение производительности программ на некоторых языках

Сообщение v04bvs »

Во-первых у меня часто возникает ощущение, что люди думают, что байткод то ли интерпретируется, то ли ещё как то долго выполняется. Хотелось показать, что принципиально байткод от native-кода по скорости не отличается. Куда важнее оптимизации, которые умеет делать компилятор. В основном для этого я и написал этот пример.

Тест это одно, а вот реальное приложение - это совсем другое

Не понимаю, там ассемблер другой что ли? Тест - единственное разумное средство объективного сравнения.

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

В C/C++ нет сборщика мусора, соответственно получится не корректное сравнение. Естественно ручное управление памятью эффективнее, чем сборщик мусора. Но в теме речь не идёт о сборке мусора, которая совершенно ортогональна байткоду, хоть и используется практически во всех современных языках.

Вероятность нестабильного кода увеличиватеся почти вдвое, поскольку (1) к своим ошибкам добавляются еще и глюки виртуальной машины, (2) как правило, языки с компиляцией в байт-код и с автоматическим распределением памяти тратят еебольше, чем при ручном управлении.

Неправда. Виртуальная машина одна, и её глюки правятся. Зато она позволяет избавляться от огрномного количества раздражающих ошибок вроде segmentation fault-а. Второй пункт не корректен, я уже писал, что сборка мусора и байткод это разные понятия.

Начнём с того, что сталин -- это не самый оптимальный компилятор схемы. Касательно именно схемы конкретно говорить не могу, но наверняка тот же sbcl (Common Lisp) дал бы значительно лучшие результаты.

Позже я проверю, но я в этом сильно сомневаюсь.

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

Код я хотел прикрепить к сообщению, но тут какой то странный глюк под оперой. Вот он:

Код: Выделить всё

(define (fibonacci n)
  (if (= n 0)
    0
    (if (= n 1)
      1
      (+ (fibonacci (- n 1)) (fibonacci (- n 2))))))

(display (fibonacci 45))

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

Во вторых разница будет разителньовидна при некотором недостатке памяти в системе

Если в системе не хватает памяти на приложение, то его не нужно запускать на этой системе. Надо либо оптимизировать приложение, либо апгрейдить систему.

К томуже Java приближается а не обгоняет вот оно в чем дело то.

Невнимательно смотрите. Java-у обогнали только C и gdc. К тому же я думаю, что разница в значитальной степени обусловлена временем старта виртуальной машины.

И еще работа с указателями массивами и т.д. думаю тоже бы не плохо проверить сам механизм указателей дает выгоду.

Работа с указателями в байт-коде невозможна, насколько мне известно.

Кстати сюдаже добавить кол-во используемой памяти да еще память под интерпретаторы т.к. одновременно.

Если мне покажут утилиту, которая может замерять пик потребления памяти - замерю.

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

При чём здесь интерпретация? Перед выполнением байт-код транслируется в машинный код, который потом выполняется.
Время на запуск программы больше. А кого это интересует?
Медленный процессор будет работать медленнее, что это покажет, я не понимаю.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Сравнение производительности программ на некоторых языках

Сообщение serzh-z »

Mellon писал(а):
17.07.2007 04:38
где же те времена когда для снижения темпа вставляли пустые циклы?
Ничего, в линуксовом ядре есть и такое... Именно для этого и высчитывается BogoMIPS при загрузке ядра.
Спасибо сказали:
Аватара пользователя
Liksys
Сообщения: 2910

Re: Сравнение производительности программ на некоторых языках

Сообщение Liksys »

Во-первых у меня часто возникает ощущение, что люди думают, что байткод то ли интерпретируется, то ли ещё как то долго выполняется. Хотелось показать, что принципиально байткод от native-кода по скорости не отличается. Куда важнее оптимизации, которые умеет делать компилятор. В основном для этого я и написал этот пример.
Байт-код выполняется на виртуальной машине, в этом его отличие от нативного кода.

Не понимаю, там ассемблер другой что ли? Тест - единственное разумное средство объективного сравнения.
Ни один тест не заменит реальные условия и реальные программы. Один язык может обойти другой по поризводительности в тестах, но окажется совсем наоборот на практике (неоднократно мною проверено).

В C/C++ нет сборщика мусора, соответственно получится не корректное сравнение. Естественно ручное управление памятью эффективнее, чем сборщик мусора.
Вот на этом следует остановиться более подробно. Программы, использующие ручное управление памятью будут работать эффективнее, чем программы с gc. А если к этому прибавить то, что язык может быть реализован как байт-код, то мы получим более низкую производительность реального приложения.

Но в теме речь не идёт о сборке мусора, которая совершенно ортогональна байткоду, хоть и используется практически во всех современных языках.
Нигде не было сказано о том, что они коллинеарны. Сказано лишь, что гравицапы часто используются в языках с байт-кодом.

Виртуальная машина одна, и её глюки правятся.
Она самая обыкновенная программа и может содержать самые обыкновенные ошибки.

Зато она позволяет избавляться от огрномного количества раздражающих ошибок вроде segmentation fault-а.
Использование отладчиков и валгриндов + наличие моска тоже позволяет избавиться от этих ошибок. Виртуальные машины - не панацея. Сегфолт же - это не просто программная, а алгоритмическая ошибка. В случае если она появляется с вероятностью 1 к 50, в случае с компилируемыми языками начинается поиск причина и последующее исправление, в случае с байт-кодом и gc на них часто просто кладут. В результате мы видим кучу быдло(кодеров/софта), которые кладут на алгоритмические ошибки и описывают "не вводите такие-то данные, а то вам выдадут мессагу об ошибке".



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

Java-у обогнали только C и gdc. К тому же я думаю, что разница в значитальной степени обусловлена временем старта виртуальной машины.
Не временем старта, а временем исполнения. Одна программа, исполняющая другую, в принципе не может быть быстрее (в идеале лишь примерно равна) непосредственно выполняющегося кода.

Работа с указателями в байт-коде невозможна, насколько мне известно.
Возможна.

Медленный процессор будет работать медленнее, что это покажет, я не понимаю.
Истинную производительность программ. Там уже можно считать точнее. И байт-код на совсем слабых машинах идет попросту лесом.
Спасибо сказали:
vadiml
Сообщения: 446
ОС: fc12.x86_64

Re: Сравнение производительности программ на некоторых языках

Сообщение vadiml »

Надеюсь, этот пример развеет миф о том, что байткод == тормоз

как ранее сказали -- это частный случай. Например на java некоторые расчетные задачи не сильно отстают от С, зато практически все программы с GUI -- тормоз.

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

Например, если сравнить скорость прохода по массиву с цикле for в С и Perl'e, то С будет значительно быстрее.
в тоже время, если в перле for заменить на foreach, то скорость будет равной (сам несколько лет назад проверял в Perl 5.6)
phenom x4 905e, asus m4a79 deluxe, 4 gb, ati x550, ati 4350, 2 x 17" LCD
Спасибо сказали:
a_sergeevich
Сообщения: 95
ОС: Mandriva 2007 PowerPack

Re: Сравнение производительности программ на некоторых языках

Сообщение a_sergeevich »

Liksys
В Java работа с указателями не возможна в ней даже понятия такого как указатели нету.
Спасибо сказали:
Аватара пользователя
Liksys
Сообщения: 2910

Re: Сравнение производительности программ на некоторых языках

Сообщение Liksys »

А в каком месте было сказано про указатели в Java? Там не говорилось о конкретном языке программирования. В C# возможно например использовать указатели при включении специальной опции компилера. Читаем маны :)
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Сравнение производительности программ на некоторых языках

Сообщение v04bvs »

vadiml писал(а):
21.07.2007 18:05
зато практически все программы с GUI -- тормоз.

Здесь, я думаю, основная проблема во взаимодействии Java и внешнего мира - упаковка\распаковка данных и т.д.
Справедливости ради надо отметить, что Azureus у меня не тормозит вообще. Многие KDE-шные приложения тормозят больше.

Например, если сравнить скорость прохода по массиву с цикле for в С и Perl'e, то С будет значительно быстрее.
в тоже время, если в перле for заменить на foreach, то скорость будет равной (сам несколько лет назад проверял в Perl 5.6)

Этот пример показывает только то, что в Perl криво реализован цикл for.
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Сравнение производительности программ на некоторых языках

Сообщение v04bvs »

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

Значит тестовое покрытие не полно.

Вот на этом следует остановиться более подробно. Программы, использующие ручное управление памятью будут работать эффективнее, чем программы с gc.

А ещё в них будет больше проблем с утечкой памяти

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

гравицапы используются практически во всех языках, созданных после 90-х годов.

Она самая обыкновенная программа и может содержать самые обыкновенные ошибки.

Ещё раз. Виртуальная машина одна. Программ, которые её используют - тысячи. Исправление одного бага в виртуальной машине удаляет тысячу багов.

Использование отладчиков и валгриндов + наличие моска тоже позволяет избавиться от этих ошибок.

Виртуальная машина позволяет перевести эти ошибки из класса фатальных в класс исправимых.
Грубо говоря - если кирпич падает на голову человеку без каски, он отправляется в больницу. Если падает на голову человеку в каске - он поднимается наверх и разбирается, в чём дело. А может и дальше пойти, просто проигнорировав этот факт.

Виртуальные машины - не панацея. Сегфолт же - это не просто программная, а алгоритмическая ошибка. В случае если она появляется с вероятностью 1 к 50, в случае с компилируемыми языками начинается поиск причина и последующее исправление, в случае с байт-кодом и gc на них часто просто кладут. В результате мы видим кучу быдло(кодеров/софта), которые кладут на алгоритмические ошибки и описывают "не вводите такие-то данные, а то вам выдадут мессагу об ошибке".

Подобные аргументы мне не интересны. В больших системах всегда есть ошибки, и они проектируются с учётом того, что где то могут возникать ошибки, и последтствия этих ошибок должны быть минимальны.
Простой пример: есть такая компания Ericson, у неё есть мэйнфреймы, которые обслуживают сотни тысяч телефонных звонков одновременно. На этих мэйнфреймах крутится программный комплекс в десятки и сотни миллионов строк кода. Естественно в нём есть ошибки. Если каждая ошибка будет приводить к падению всей системы и разрыву сотни тысяч телефонных соединений - это, мягко говоря, плохо.

Не временем старта, а временем исполнения. Одна программа, исполняющая другую, в принципе не может быть быстрее (в идеале лишь примерно равна) непосредственно выполняющегося кода.

Виртуальная машина Java не выполняет байткод. Она его компилирует в машинный код целевой архитектуры, который потом подаётся на процессор.

Истинную производительность программ. Там уже можно считать точнее. И байт-код на совсем слабых машинах идет попросту лесом.

Т.е. на быстрых процессорах производительность ложная? :)
Спасибо сказали:
Аватара пользователя
Liksys
Сообщения: 2910

Re: Сравнение производительности программ на некоторых языках

Сообщение Liksys »

Спор бесполезен. Уже изложены все факты о байт-коде и бессмыслено их отрицать.
Спасибо сказали: