python tão rápido quanto fortran?
DESCRIPTION
Dissertaçaõ sobre o desempenho de Python e Fortran em computação científicaTRANSCRIPT
Python tão rápido quanto Fortran?
Nelson Luís Dias1
1Professor Associado, Departamento de Engenharia Ambiental, UniversidadeFederal do Paraná, e-mail: [email protected]. url: www.lemma.ufpr.br/nldias
3 de janeiro de 2013
LemmaUFPR
1
Pesquisa e programação
• Programas (em geral) são meios para fazer pesquisa.
LemmaUFPR
1
Pesquisa e programação
• Programas (em geral) são meios para fazer pesquisa.
• Portanto, a pergunta principal de pesquisa/programação é:
Quais são as melhores ferramentas para cada tarefa?
LemmaUFPR
1
Pesquisa e programação
• Programas (em geral) são meios para fazer pesquisa.
• Portanto, a pergunta principal de pesquisa/programação é:
Quais são as melhores ferramentas para cada tarefa?
• Não há uma única resposta, porque, como sempre, o resultado depende doconhecimento que o usuário tem da ferramenta.
LemmaUFPR
1
Pesquisa e programação
• Programas (em geral) são meios para fazer pesquisa.
• Portanto, a pergunta principal de pesquisa/programação é:
Quais são as melhores ferramentas para cada tarefa?
• Não há uma única resposta, porque, como sempre, o resultado depende doconhecimento que o usuário tem da ferramenta.
• Nesta apresentação: algumas técnicas para fazer bom uso de Fortran ×Python
LemmaUFPR
2
Principais pontos desta apresentação:
• Python é conveniente, mas é lento.
LemmaUFPR
2
Principais pontos desta apresentação:
• Python é conveniente, mas é lento.
• Fortran é muito menos conveniente, e verborrágico, mas é muito rápido.
LemmaUFPR
2
Principais pontos desta apresentação:
• Python é conveniente, mas é lento.
• Fortran é muito menos conveniente, e verborrágico, mas é muito rápido.
• Mas BLAS muda tudo, e torna Python (com Numpy e Numba) quase tão rápidoquanto — ou até mesmo mais rápido que — Fortran.
LemmaUFPR
3
Parte I: Fortran × Python em Linux, sem BLAS
LemmaUFPR
3
Parte I: Fortran × Python em Linux, sem BLAS
Fortran:
• várias linguagens em uma (F66, F77,F90, F95, F03, F08)
• muito grande e mais difícil de aprender edominar
• muito popular entre cientistas e enge-nheiros
• muito rápido (compilado)
LemmaUFPR
3
Parte I: Fortran × Python em Linux, sem BLAS
Fortran:
• várias linguagens em uma (F66, F77,F90, F95, F03, F08)
• muito grande e mais difícil de aprender edominar
• muito popular entre cientistas e enge-nheiros
• muito rápido (compilado)
Python:
• uma única linguagem• muitas bibliotecas padrão, e muitas ex-
tensões• pequena e simples• muito lento (interpretado)• Numpy, Scipy, SymPy, rPython: gigan-
tescas bibliotecas numéricas e simbóli-cas pré-compiladas (em Fortran ou C) edisponíveis
LemmaUFPR
4
Gênesis
1. No princípio, criou Deus os céus e a terra.
2. E a terra era sem forma e vazia; e havia trevas sobre a face do abismo; e oEspírito de Deus se movia sobre a face das águas.
3. E disse Deus: Haja luz Fortran. E houve luz.
4. E viu Deus que era boa a luz; e fez Deus separação entre a luz Fortran e astrevas tabelas de logaritmos.
5. E Deus chamou à luz Dia; e às trevas chamou Noite. E foi a tarde e a manhã:o dia primeiro.
LemmaUFPR
4
Gênesis
1. No princípio, criou Deus os céus e a terra.
2. E a terra era sem forma e vazia; e havia trevas sobre a face do abismo; e oEspírito de Deus se movia sobre a face das águas.
3. E disse Deus: Haja luz Fortran. E houve luz.
4. E viu Deus que era boa a luz; e fez Deus separação entre a luz Fortran e astrevas tabelas de logaritmos.
5. E Deus chamou à luz Dia; e às trevas chamou Noite. E foi a tarde e a manhã:o dia primeiro.
Fortran (1957) foi a primeira linguagem de programação de “alto nível” (que usavaum compilador).
LemmaUFPR
5
Portanto, comece com Fortran
1 program cacumij
2 integer , parameter :: n = 5000
3 real (kind =8) :: a(0:n-1,0:n-1)
4 integer (kind =4) :: i,j
5 call cpu_time(t1)
6 do i = 0,n-1
7 do j = 0,n-1
8 a(i,j) = i+j
9 end do
10 end do
11 call cpu_time(t2)
12 write (*,*) t2 - t1
13 end program
LemmaUFPR
5
Portanto, comece com Fortran
1 program cacumij
2 integer , parameter :: n = 5000
3 real (kind =8) :: a(0:n-1,0:n-1)
4 integer (kind =4) :: i,j
5 call cpu_time(t1)
6 do i = 0,n-1
7 do j = 0,n-1
8 a(i,j) = i+j
9 end do
10 end do
11 call cpu_time(t2)
12 write (*,*) t2 - t1
13 end program
gfortran cacumij.f90 -o cacumij
./ cacumij
0.552033007
LemmaUFPR
6
E agora compare com Python + Numpy
1 #!/usr/bin/python
2 from numpy import arange , array ,int32 ,float64 ,zeros
3 from time import time
4 n = 5000
5 t1 = time()
6 ix = arange(n,dtype=int32)
7 iy = arange(n,dtype=int32)
8 a = zeros((n,n),float64)
9 a = ix[:,None] + iy[None ,:]
10 t2 = time()
11 print t2 - t1
LemmaUFPR
6
E agora compare com Python + Numpy
1 #!/usr/bin/python
2 from numpy import arange , array ,int32 ,float64 ,zeros
3 from time import time
4 n = 5000
5 t1 = time()
6 ix = arange(n,dtype=int32)
7 iy = arange(n,dtype=int32)
8 a = zeros((n,n),float64)
9 a = ix[:,None] + iy[None ,:]
10 t2 = time()
11 print t2 - t1
./cacum.py
0.309801101685
LemmaUFPR
7
Observações
• O algoritmoaij = i + j
aparentemente não é vetorizável: BLAS (que surgirá daqui a pouco) não seaplica.
• No entanto, a sintaxe de cacum.py é vetorial (e um pouco estranha para osnão-iniciados).
LemmaUFPR
7
Observações
• O algoritmoaij = i + j
aparentemente não é vetorizável: BLAS (que surgirá daqui a pouco) não seaplica.
• No entanto, a sintaxe de cacum.py é vetorial (e um pouco estranha para osnão-iniciados).
• cacum.py é quase duas vezes mais rápido que cacumij.f90.
LemmaUFPR
7
Observações
• O algoritmoaij = i + j
aparentemente não é vetorizável: BLAS (que surgirá daqui a pouco) não seaplica.
• No entanto, a sintaxe de cacum.py é vetorial (e um pouco estranha para osnão-iniciados).
• cacum.py é quase duas vezes mais rápido que cacumij.f90.
• o que está errado?
LemmaUFPR
8
Troque i com j
1 program cacumji
2 integer , parameter :: n = 5000
3 real (kind =8) :: a(0:n-1,0:n-1)
4 integer (kind =4) :: i,j
5 call cpu_time(t1)
6 do j = 0,n-1
7 do i = 0,n-1
8 a(i,j) = i+j
9 end do
10 end do
11 call cpu_time(t2)
12 write (*,*) t2 - t1
13 end program
LemmaUFPR
8
Troque i com j
1 program cacumji
2 integer , parameter :: n = 5000
3 real (kind =8) :: a(0:n-1,0:n-1)
4 integer (kind =4) :: i,j
5 call cpu_time(t1)
6 do j = 0,n-1
7 do i = 0,n-1
8 a(i,j) = i+j
9 end do
10 end do
11 call cpu_time(t2)
12 write (*,*) t2 - t1
13 end program
gfortran cacumji.f90 -o cacumji
./ cacumji
0.212011993
LemmaUFPR
9
E dê mais uma tentativa a Python
1 #!/usr/bin/python
2 from numpy import arange , array ,int32 ,zeros
3 from time import time
4 n = 5000
5 t1 = time()
6 a = zeros((n,n),'f8')
7 def aom(a):
8 for i in range(n):
9 for j in range(n):
10 a[i,j] = i+j
11 aom(a)
12 t2 = time()
13 print t2 - t1
LemmaUFPR
9
E dê mais uma tentativa a Python
1 #!/usr/bin/python
2 from numpy import arange , array ,int32 ,zeros
3 from time import time
4 n = 5000
5 t1 = time()
6 a = zeros((n,n),'f8')
7 def aom(a):
8 for i in range(n):
9 for j in range(n):
10 a[i,j] = i+j
11 aom(a)
12 t2 = time()
13 print t2 - t1
./cacumij -slow.py
4.56774091721
LemmaUFPR
10
. . . e mais uma:
1 #!/usr/bin/python
2 from numpy import arange , array ,int32 ,zeros
3 from time import time
4 from numba import jit ,float64
5 n = 5000
6 t1 = time()
7 a = zeros((n,n),'f8')
8 @jit(argtypes =[ float64 [: ,:]])
9 def aom(a):
10 for i in range(n):
11 for j in range(n):
12 a[i,j] = i+j
13 aom(a)
14 t2 = time()
15 print t2 - t1
LemmaUFPR
10
. . . e mais uma:
1 #!/usr/bin/python
2 from numpy import arange , array ,int32 ,zeros
3 from time import time
4 from numba import jit ,float64
5 n = 5000
6 t1 = time()
7 a = zeros((n,n),'f8')
8 @jit(argtypes =[ float64 [: ,:]])
9 def aom(a):
10 for i in range(n):
11 for j in range(n):
12 a[i,j] = i+j
13 aom(a)
14 t2 = time()
15 print t2 - t1
./ cacumij.py
0.290515899658
LemmaUFPR
11
Conclusões desta parte
• Um bom conhecimento dos detalhes de uma linguagem (no caso, como Fortranarmazena matrizes) é muitas vezes necessário para otimizar um programa.
• A ordem em que uma matriz é percorrida (ij , ji) importa muito, porque a CPUé muito mais rápida do que qualquer memória. A diferença de velocidade estáaumentando: a tecnologia está tornando as CPUs relativamente mais e maisrápidas que as memórias.
• Depois de otimizado, Fortran ainda é (neste exemplo) 33% mais rápido.
• No entanto, obtivemos a mesma ordem de grandeza de tempo de CPU comPython, de duas maneiras diferentes (sem e com numba).
• Compiladores “just in time” (numba) estão chegando próximos do desempenhode Fortran.
LemmaUFPR
12
O efeito que BLAS faz. . .
BLAS = Basic Linear Algebra Subprograms.
BLAS é um conjunto altamente otimizado de rotinas para realizar operações deálgebra linear.
Existem hoje em dia várias implementações (http://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms):
Accelerate, ACML, C++ AMP BLAS, ATLAS, ESSL, Eigen BLAS, Goto BLAS, HPMLIB, Intel MKL, MathKeisan, Netlib BLAS, Netlib CBLAS, PDLIB/SX, SCSL, SunPerformance Library, SurviveGotoBLAS2, OpenBLAS, cuBLAS,
Em Linux: é relativamente fácil instalar um BLAS pré-compilado (nunca tão bomquanto compilar e ajustar para a própria máquina). Minha escolha: ATLAS.
Em Windows: um pequeno pesadelo, se não houver um compilador comercial deFortran. Minha escolha: MingGW (compilador C e Fortran) + OpenBLAS.
LemmaUFPR
13
Produto de 2 matrizes em Fortran:1 program cabum
2 integer , parameter :: size = 1000
3 real (kind =8) :: a(size ,size), b(size ,size), c(size ,size)
4 integer (kind =4) :: seed
5 call random_seed ()
6 call random_number(a)
7 call random_number(b)
8 call cpu_time(t1)
9 c = matmul(a,b)
10 call cpu_time(t2)
11 write (*,*) t2 - t1
12 end program
LemmaUFPR
13
Produto de 2 matrizes em Fortran:1 program cabum
2 integer , parameter :: size = 1000
3 real (kind =8) :: a(size ,size), b(size ,size), c(size ,size)
4 integer (kind =4) :: seed
5 call random_seed ()
6 call random_number(a)
7 call random_number(b)
8 call cpu_time(t1)
9 c = matmul(a,b)
10 call cpu_time(t2)
11 write (*,*) t2 - t1
12 end program
sem BLAS: gfortran -o3 cabum.f90 -o cabum -noblas
./cabum -noblas; 1.62810099
LemmaUFPR
13
Produto de 2 matrizes em Fortran:1 program cabum
2 integer , parameter :: size = 1000
3 real (kind =8) :: a(size ,size), b(size ,size), c(size ,size)
4 integer (kind =4) :: seed
5 call random_seed ()
6 call random_number(a)
7 call random_number(b)
8 call cpu_time(t1)
9 c = matmul(a,b)
10 call cpu_time(t2)
11 write (*,*) t2 - t1
12 end program
sem BLAS: gfortran -o3 cabum.f90 -o cabum -noblas
./cabum -noblas; 1.62810099
com BLAS: gfortran -o3 -fexternal -blas cabum.f90 -lblas -o cabum -blas
./cabum -blas; 0.300018996
LemmaUFPR
14
Produto de 2 matrizes em Python/Numpy:
1 #!/usr/bin/python
2 import numpy
3 n = 1000
4 a = numpy.random.rand(n,n)
5 b = numpy.random.rand(n,n)
6 from time import time
7 t1 = time()
8 c = numpy.dot(a, b)
9 t2 = time()
10 print t2 -t1
LemmaUFPR
14
Produto de 2 matrizes em Python/Numpy:
1 #!/usr/bin/python
2 import numpy
3 n = 1000
4 a = numpy.random.rand(n,n)
5 b = numpy.random.rand(n,n)
6 from time import time
7 t1 = time()
8 c = numpy.dot(a, b)
9 t2 = time()
10 print t2 -t1
./cabum.py
0.295262813568
LemmaUFPR
15
Conclusões, com BLAS
• BLAS faz toda a diferença: não saia de casa sem ele.
LemmaUFPR
15
Conclusões, com BLAS
• BLAS faz toda a diferença: não saia de casa sem ele.
• BLAS torna um programa Fortran otimizado para multiplicar matrizes 6 vezesmais rápido.
LemmaUFPR
15
Conclusões, com BLAS
• BLAS faz toda a diferença: não saia de casa sem ele.
• BLAS torna um programa Fortran otimizado para multiplicar matrizes 6 vezesmais rápido.
• Numpy tira toda a vantagem possível de BLAS: neste exemplo Python/Numpyé ligeiramente mais rápido que Fortran.
LemmaUFPR
15
Conclusões, com BLAS
• BLAS faz toda a diferença: não saia de casa sem ele.
• BLAS torna um programa Fortran otimizado para multiplicar matrizes 6 vezesmais rápido.
• Numpy tira toda a vantagem possível de BLAS: neste exemplo Python/Numpyé ligeiramente mais rápido que Fortran.
• Com esforço suficiente (opções de compilação, BLAS compilado para a má-quina, etc.) deve ser possível tornar Fortran mais rápido que Python/Numpy.
LemmaUFPR
16
III: Rodando em Windows
Por que desenvolver para Windows?
LemmaUFPR
16
III: Rodando em Windows
Por que desenvolver para Windows?
Porque muitos não têm acesso a Linux.
LemmaUFPR
16
III: Rodando em Windows
Por que desenvolver para Windows?
Porque muitos não têm acesso a Linux.
Como ter Fortran/BLAS gratuitamente em Windows:
• Obtenha e instale MingGW www.mingw.org
• Dentro do shell de MingGW, obtenha e instale wget: mingw-get install wget
• Obtenha OpenBLAS http://xianyi.github.com/OpenBLAS/
• Desempacote na pasta c:\mingw\msys\1.0\OpenBLAS
• Nesta pasta (cd /OpenBLAS/):– ./quickbuild.win32
– Espere uma eternidade (muitas horas ou uma noite inteira)– make install /mingw (deve copiar libopenblas.lib para c:\mingw\lib)
• Copie libopenblas.dll para alguma pasta no PATH (por exemplo,c:\mingw\bin)
LemmaUFPR
17
Dentro de um prompt de Windows7
Rodando dentro de uma máquina virtual (Virtual Box) Windows7gfortran -o3 cacumij.f90 -o cacumij.exe
cacumij
1.5822750
gfortran -o3 cacumji.f90 -o cacumji.exe
0.85122401
gfortran -o3 cabum.f90 -o cabum -noblas.exe
cabum -noblas
1.7925980
gfortran -fexternal -blas -o3 cabum.f90 -lopenblas -o cabum -blas.exe
0.26037401
cabum.py
0.501000165939
LemmaUFPR
18
Conclusões desta parte
• Não há numba em meu Windows7; portanto, não há comparação comcacumij.py.
• Os tempos de máquina dependem dos processos rodando em todo o sistemaoperacional anfitrião (Linux); portanto, as comparações são aproximadas e de-pendem do estado do sistema.
• Os tempos em Windows são comparáveis com os tempos em Linux: depen-dendo do caso, Fortran ou Python podem “ganhar” entre si ou entre sistemasoperacionais diferentes.
LemmaUFPR
19
Conclusões gerais
• Não é possível ainda prescindir totalmente de Fortran ou C: vale a pena man-ter compiladores atualizados em todos os sistemas operacionais em que fornecessário trabalhar.
• Fortran sem BLAS não é competitivo com Python/Numpy, todas as vezes emque operações vetoriais e matriciais forem uma parte significativa (em tempode máquina) do programa.
• Portanto, é fundamental possuir BLAS no sistema, tão otimizado quanto possí-vel.
• Python/Numpy/Numba possuem desempenho comparável a Fortran, pelo me-nos em ordem de grandeza (digamos, entre 50% e 100% da velocidade deFortran).
LemmaUFPR
19
Conclusões gerais
• Não é possível ainda prescindir totalmente de Fortran ou C: vale a pena man-ter compiladores atualizados em todos os sistemas operacionais em que fornecessário trabalhar.
• Fortran sem BLAS não é competitivo com Python/Numpy, todas as vezes emque operações vetoriais e matriciais forem uma parte significativa (em tempode máquina) do programa.
• Portanto, é fundamental possuir BLAS no sistema, tão otimizado quanto possí-vel.
• Python/Numpy/Numba possuem desempenho comparável a Fortran, pelo me-nos em ordem de grandeza (digamos, entre 50% e 100% da velocidade deFortran).
Tenha a sabedoria de escolher as melhores ferramentas.
LemmaUFPR
20
Thanks!
LemmaUFPR