Inicial > Java, Programação, Python, Ruby > Comparação de performance

Comparação de performance

Com a ajuda de alguns amigos, fizemos uma comparação de performance bem simples e muito distante de ser um benchmark confiável entre algumas linguagens/versões usando o fibonacci de 35. Também foi realizado o fibonacci de 45 nas linguagens com melhor performance. Foi somente uma experiência e o resultado em minha máquina foi esse:

gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) – fib.c – fib2
Compilação otimizada usando: gcc -O3 -o fib2 fib.c (contribuição de Filipe Saraiva)
./fib2 35
Tempo: 0.124780
Resultado: 9227465
./fib2 45
Tempo: 15.655936
Resultado: 1134903170

Scala 2.7.7final – Fib1.scala (contribuição do Matheus Moreira)
scala Fib1 35
Tempo: 0.137780472
Resultado: 9227465
scala Fib1 45
Tempo: 19.697318756
Resultado: 1134903170

Java(TM) SE Runtime Environment (build 1.6.0_24-b07) – fib.javafib.class
java fib 35
Tempo: 0.146963799
Resultado: 9227465
java fib 45
Tempo: 20.793879543
Resultado: 1134903170

Free Pascal Compiler version 2.4.0-2 [2010/03/06] for x86_64 – fib.pas – fibp (contribuição do Nécio Veras)
Compilação otimizada usando: fpc -O3 fib.pas -ofibp
./fibp 35
Tempo: 0.221000001
Resultado: 9227465
./fibp 45
Tempo: 30.445999150
Resultado: 1134903170

gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) – fib.cfib
Compilação não otimizada usando: gcc -o fib fib.c
./fib 35
Tempo: 0.276678
Resultado: 9227465
./fib 45
Tempo: 32.527250
Resultado: 1134903170

Groovy Version: 1.8.0 JVM: 1.6.0_24 – fib2.groovy (contribuição do Wanderson Santos)
groovy fib2.groovy 35
Tempo: 0.290426544
Resultado: 9227465
groovy fib2.groovy 45
Tempo: 33.457977715
Resultado: 1134903170

Haskell – The Glorious Glasgow Haskell Compilation System, version 6.12.1 – fib.hsfibh (contribuição do Diego Victor com correção da Mônica Regina da Silva)
Compilado usando: ghc –make -O3 fib.hs -o fibh
./fibh 35
9227465
0.317424
./fibh 45
1134903170
40.989142

Ruby  – Rubinious 1.2.1dev (1.8.7 f4c08fbe 2010-12-21 JI) [x86_64-unknown-linux-gnu] – fib.rb
ruby fib.rb 35
Tempo: 1.339709
Resultado: 9227465
ruby fib.rb 45
Tempo: 158.686395
Resultado: 1134903170

JRuby 1.5.3 (ruby 1.8.7 patchlevel 249) (2010-09-28 7ca06d7) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_20) [amd64-java]fib.rb
jruby fib.rb 35
Tempo: 4.371
Resultado: 9227465

Groovy Version: 1.8.0 JVM: 1.6.0_24 – fib.groovy (contribuição do Luís Bruno)
groovy fib.groovy 35
Tempo: 5.106544505
Resultado: 9227465

Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio – fib.lua (contribuição da Mônica Regina da Silva)
lua5.1 fib.lua 35
Tempo: 5.36
Resultado: 9227465

Ruby 1.9.1p378 (2010-01-10 revision 26273) [x86_64-linux] – fib.rb
ruby1.9.1 fib.rb 35
Tempo: 6.81764046
Resultado: 9227465

Ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]fib.rb
ruby fib.rb 35
Tempo: 7.65983433
Resultado: 9227465

Groovy Version: 1.7.5 JVM: 1.6.0_20fib.groovy (contribuição do Luís Bruno)
groovy fib.groovy 35
Tempo: 8.653575988
Resultado: 9227465

Python 2.6.5 – fib.py
python fib.py 35
Tempo: 0:00:11.448263
Resultado: 9227465

Python 3.1.2 – fib.py
python3.1 fib.py 35
Tempo: 0:00:12.620807
Resultado: 9227465

Ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux] – fib.rb
ruby fib.rb 35
Tempo: 34.993339
Resultado: 9227465

Agradecimentos especiais aos amigos que contribuíram com as seguintes implementações:

Groovy – Luís Bruno / Wanderson Santos / Thiago Witt
Haskell
– Diego Victor (com correção da Mônica)
Lua – Mônica Regina da Silva
Pascal – Nécio Veras
Scala – Matheus Moreira / Thiago Witt

O Thiago Witt contribuiu com versões Groovy e Scala extramamente otimizadas usando Tail-call. Foi tão otimizado que resolvi testar o fibonacci de 10000:

Scala 2.7.7final – Fib2.scala (contribuição do Thiago Witt – Tail-call)
scala Fib2 10000
Tempo: 0.09665077

Groovy Version: 1.8.0 JVM: 1.6.0_24 – fib3.groovy (contribuição do Thiago Witt – Tail-call otimizada para evitar StackOverFlow)
groovy fib3.groovy 10000
Tempo: 15.135361192

O Thiago Witt também contribuiu com uma versão em Groovy extramamente otimizada, mas que dá StackOverflow para números grandes. Assim, testei as versões Tail Call com fibonacci de 4000:

Scala 2.7.7final – Fib2.scala (contribuição do Thiago Witt – Tail-call)
scala Fib2 4000
Tempo: 0.062994021

Groovy Version: 1.8.0 JVM: 1.6.0_24 – fib4.groovy (contribuição do Thiago Witt – Tail-call)
groovy fib4.groovy 4000
Tempo: 0.14749984

Groovy Version: 1.8.0 JVM: 1.6.0_24 – fib3.groovy (contribuição do Thiago Witt – Tail-call otimizada para evitar StackOverFlow)
groovy fib3.groovy 4000
Tempo: 2.789794005

  1. Filipe Saraiva
    24/10/2010 às 12:10

    Opa Regis! Como devoto das linguagens compiladas, do C e do gcc que sou, tive que comentar este post ao ver que o desempenho da minha linguagem preferida foi menor que em java. 😉

    Acontece que a compilação padrão do gcc não faz muitas otimizações no código em C (e nas demais linguagens suportadas também). Isso possibilita uma compilação mais rápida e melhor suporte ao debug e verificação de erros, mas na hora da execução o desempenho fica inferior.

    Então, baixei o código e fiz a compilação padrão (gcc -o fib fib.c) e a compilação com o máximo de otimização (gcc -O3 -o fib fib.c). Executei algumas vezes o código compilado e a diferença é bem perceptível:

    [filipe@localhost Downloads]$ gcc -o fib fib.c
    [filipe@localhost Downloads]$ ./fib 35
    Tempo: 0.388445
    Resultado: 9227465

    [filipe@localhost Downloads]$ gcc -O3 -o fib fib.c
    [filipe@localhost Downloads]$ ./fib 35
    Tempo: 0.122428
    Resultado: 9227465

    E quanto à java…

    [filipe@localhost Downloads]$ javac fib.java
    [filipe@localhost Downloads]$ java fib 35
    Tempo: 0.168618716
    Resultado: 9227465

    Uso o linux Mandriva 2010.1 x86_64 num Intel Core 2 Duo.

    Então é isso. Bem interessante esse micro teste, serve para vermos rapidamente a diferença em termos de desempenho e como isso é fortemente dependente da linguagem escolhida.

    Grande abraço, Regis!

    • regispires
      24/10/2010 às 16:48

      Oi, Filipe!!! Muito obrigado pela sua contribuição. Realmente fiquei surpreso ao ver o C com desempenho inferior ao Java. Agora compreendi melhor e inclusive vou atualizar o post com os novos resultados.

  2. 24/10/2010 às 23:48

    Olha ae em Ruby 1.9.2 🙂

    [23:42:05 caironoleto] ~/Downloads (ruby-1.9.2-p0)
    $ ruby fib.rb 35
    Tempo: 3.470373
    Resultado: 9227465

    • regispires
      25/10/2010 às 19:54

      Cairo, atualizei o post com a performance do Ruby1.9.2-p0 em minha máquina. No meu caso, a performance foi um pouco inferior à performance do Ruby 1.9.1.

  3. Luís Bruno
    25/10/2010 às 01:53

    Olá Regis, ótimo post!
    Bem legal esse teste, brinquei um pouco aqui também:

    A versão do Ruby na minha máquina é 1.8.7 e resultou em:
    Tempo: 17.839598
    Resultado: 9227465

    Fiz em Groovy:
    bruno@bruno-desktop:~/Documentos/groovy$ groovy Fibonacci.groovy 35
    Tempo: 19935
    Resultado: 9227465

    bruno@bruno-desktop:~/Downloads$ java fib 35
    Tempo: 0.129493434
    Resultado: 9227465

    Bem, realmente não dá pra comparar a performance do Groovy com Java, até porque o Groovy roda no Java…
    Percebi que a mudança das versões do Ruby teve uma visível melhora na performance. O Groovy é criança ainda, espero que com o avançar das versões também tenha uma melhora satisfatória nesse quadro.

    Abraços Regis!

    • regispires
      25/10/2010 às 19:56

      Luís Bruno,
      Envie-me sua implementação em Groovy para eu incluir no post. É mais uma contribuição interessante.

    • regispires
      26/10/2010 às 09:09

      Incluí sua contribuição! Obrigado!

  4. Nécio Veras
    25/10/2010 às 13:59

    Grande Régis,

    Parabéns pela postagem! Realmente, gostei do post!
    Tanto que também resolvi brincar um pouco!

    Bom, fui buscar inspiração no memorial de Clóvis Beviláquia (grande jurista brasileiro, nascido aqui em Viçosa). Quando vierem por aqui não deixem de visitar o seu memorial, vale a pena! Enfim, quando digo que fui buscar inspiração em um “museu”, quis dizer que resolvi resgatar uma linguagem que, cientificamente, não tem tanta influência, mas serviu como base para o aprendizado de lógica em muitas gerações e impulsiona até hoje o mercado comercial com uma ferramenta poderosa! Ganhou certa “simpatia” quando foi lançada uma versão sob a licença GPL. Estou falando do bom e velho freePascal!
    Vamos aos resultados:
    Free Pascal Compiler version 2.4.0 (linux-x86)
    Tempo: 3.45000000
    Resultado: 9227465

    Nem foi tão ruim assim 🙂

    Abraços,

    Nécio de Lima Veras.

    • regispires
      25/10/2010 às 19:58

      Obrigado, Nécio,
      Envie-me sua implementação em Pascal para que eu possa adicionar ao post!

    • regispires
      26/10/2010 às 09:11

      Nécio, incluí sua contribuição. Obrigado, inclusive pela informação de que o Clóvis Beviláquia era de Viçosa, pois eu não sabia.

  5. Wanderson Santos
    15/05/2011 às 03:36

    Regis, quando puder atualize para Groovy 1.8. A melhoria no desempenho é impressionante!

    Confira: http://www.wiki.jvmlangsummit.com/images/0/04/Theodorou-Faster-Groovy-1.8.pdf

    Em alguns casos para calculos matemáticos, se mostrou mais rápido do que Scala (!) http://bit.ly/eSiTHf.

    • regispires
      15/05/2011 às 15:18

      Wanderson,
      Obrigado pelas informações referentes às melhorias do Groovy. Assim, baixei a versão 1.8.0 e atualizei os resultados no post.

      • Wanderson Santos
        15/05/2011 às 23:45

        Obrigado Regis!

  6. Wanderson Santos
    25/05/2011 às 01:59

    Olá Regis!

    Segue o calculo fibonacci otimizado para Groovy 1.8.

    //Autor: Wanderson Santos (@wanswins / wanderson.santos (arroba) gmail.com)
    int fib(int num) {
    if (num < 2) return num
    return fib(num – 1) + fib(num – 2)
    }
    def numero = Integer.parseInt(args[0])
    def t1 = System.nanoTime()
    resultado = fib(numero)
    def t2 = System.nanoTime()
    println "Tempo: ${(t2-t1)/1000000000}"
    println "Resultado: ${resultado}"

    • regispires
      25/05/2011 às 08:08

      Postei sua contribuição, Wanderson! Muito rápido mesmo!

      • Wanderson Santos
        26/05/2011 às 10:45

        Muito obrigado Regis!

        É muito bom ver o Groovy que já tem uma excelente legibilidade e fácil adoção dos desenvolvedores Java, também se mostrar extremamente rápido. E olha que estamos falando de uma linguagem dinâmica!

  7. Matheus Moreira
    26/05/2011 às 13:28

    Regis, beleza? Tem como eu contribuir com uma implementação em Scala?

    []’s

    • regispires
      26/05/2011 às 14:13

      Claro, Matheus! Basta me enviar o código que eu executo aqui na minha máquina e atualizo o post com sua contribuição. Abraços, Regis.

      • Matheus Moreira
        27/05/2011 às 10:32

        Regis, segue uma implementação simples:

        object Fib {
        def fib(n: Int): Int =
        if (n == 0 || n == 1) n
        else fib(n – 1) + fib(n – 2)

        def main(args: Array[String]) {
        def n = args(0).toInt

        def t1 = System.nanoTime()
        def resultado = fib(n)
        def t2 = System.nanoTime()

        println(“Tempo: ” + ((t2 – t1) / 1000000000.0)
        println(“Resultado: ” + resultado)
        }
        }

        Eu compilei esse arquivo com o comando “fsc (ou scalac) -g:none -optimise” supondo que isso garantiria um desempenho melhor. Ainda não comparei o desempenho do código compilado dessa forma com aquele compilado sem as opções -g e -optimise. Pode ser um teste interessante.

        Outra observação, testei com Scala 2.8.0.final mas a 2.9.0.final já está na área.

    • regispires
      02/07/2011 às 13:02

      Matheus, finalmente atualizei o post com sua contribuição em Scala! Desculpe-me pela demora. A performance realmente é excelente! A otimização sugerida não fez diferença na performance final.

  8. Wanderson Santos
    26/05/2011 às 15:20

    Regis, seguem várias implementações em várias linguagens!
    http://www.scriptol.com/programming/fibonacci.php

  9. Reuben Morais
    27/05/2011 às 09:11

    Faltou o LuaJIT 🙂

    $ luajit-2.0.0-beta7 fib.lua 35
    Tempo: 0.30
    Resultado: 9227465

  10. Thiago M. Witt
    15/06/2011 às 00:04

    O post me inspirou a fazer alguns testes com groovy e scala, com os quais eu nunca tinha mexido.
    Implementei o fib usando tail-call recursion, quem quiser pode ver ver os fontes aqui:

    Scala: http://pastebin.com/x7yn1cpU
    Groovy: http://pastebin.com/EUNG2Xpv

    A versão em scala aqui foi bem mais rápida que a em groovy.
    As opções de otimização comentadas pelo @Mateus Moreira não fizeram nenhuma diferença aqui na versão scala.

    • 24/06/2011 às 19:58

      Thiago, em nome de todos, muito obrigado pela contribuição!

      Vi que você utilizou a versão que contribui. As outras versões Groovy conseguiram resultado melhor?

      Contudo como diria o Professor Tibúrcio: “‘Bem mais rápida’ não é resposta”. 😉

      Compartilhe conosco os valores que você teve! Até mesmo pra gente discutir o que o conceito de “rápido”.

      Hoje na maioria dos casos de sistemas de informação este conceito é relativo a sensação de rapidez que usuário final tem ao executar uma tarefa. Neste contexto milésimos, décimos ou até poucos segundos não fazem diferença. Outros contextos são processamentos em lote (jobs) de grandes quantidades de dados, dentre outros onde isso realmente faria diferença. Mas a boa notícia é que paralelizando em vários cores (com GPars, Akka, etc.) isto pode também não fazer diferença.

      Grande abraço!

      • Thiago M. Witt
        24/06/2011 às 21:24

        Oi Wanderson,

        Sim, usei a sua versão, fiz uns testes com a sua e a anterior pra descobrir porque a sua era tão mais rápida. Legal ver como pequenos detalhes podem fazer uma boa diferença na performance.

        Quanto aos resultados, aqui na minha máquina (Macbook Pro, Core 2 Duo 2.4Ghz rodando Mac OS 10.6.7) foram os seguintes (editei os resultados pra diminuir a poluição visual):

        Versão scala (2.8.1.final):
        $ scala Fib 10000
        Tempo: 0.02375
        Resultado: 336447648764317832666(…)6073310059947366875

        Versão groovy (1.8.0):
        $ ./groovy fib3.groovy 10000
        Tempo: 8.188678
        Resultado: 33644764876431783266621(…)66073310059947366875

        O problema no groovy deve ser a implementação do trampoline(). A versão sem usar o trampoline tem velocidade muito próxima a da em scala, mas daí não dá pra calcular pra n muito maior que 4000 (aqui na minha máquina) porque estoura a pilha.

        $ scala Fib 4000
        Tempo: 0.017827
        Resultado: 3990947343500442279(…)3025993715274875

        $ ./groovy ~/Downloads/fib3.groovy 4000
        Tempo: 1.104713 <– com trampoline()
        Resultado: 3990947343500442279(…)3025993715274875
        Tempo: 0.036333 <– sem trampoline()
        Resultado: 3990947343500442279(…)3025993715274875

        Se conseguir deixar mais rápido me conta.

        Abraço,
        Thiago

    • regispires
      02/07/2011 às 17:56

      Thiago, postei suas contribuições. Obrigado!

  11. 26/06/2011 às 02:05

    A versão (Groovy) sem usar o trampoline tem velocidade muito próxima a da em scala….

    Era isso que queria saber. Tem como postar qual foi o valor?

    … mas daí não dá pra calcular pra n muito maior que 4000 (aqui na minha máquina) porque estoura a pilha.

    É o preço que se paga por ser uma linguagem dinâmica e ter MOP, AST e outras coisas fantásticas, rs. A memória é o gargalo, e acredito que dos males é o menor, ainda mais no mundo paralelizado. O que você acha?

    A propósito ainda tem lista de otimizações planejadas com ajustes já conhecidos abaixo que devem melhorar ainda mais o desempenho do Groovy.

    Groovy 1.8 runtime performance improvements
    http://jira.codehaus.org/browse/GROOVY-3951

    Até mais

  1. 02/07/2011 às 21:01

Deixar mensagem para Wanderson Santos Cancelar resposta