quinta-feira, 14 de março de 2013

O Retorno (2/2) - Sobre o que conhecemos

A ideia desse texto veio de uma tarde de trabalho. Daquelas tardes em que tu simplesmente tens que dar uma volta no meio das árvores pra se tranquilizar depois de tentar (e não conseguir) resolver um pepinão. Então, nessa tarde, resolvi dar uma volta na redenção. Além de me tranquilizar pelo trabalho, ainda tinha que eliminar a cafeína do meu sistema (será que fazer exercício ajuda?), mas essa informação não é tão relevante.

Caminhando no parque, é possível ver outras pessoas também caminhando, ou correndo, pedalando, jogando bola, tomando mate, dormindo, levando as crianças nos brinquedos e, nos dias mais quentes, até nadando no chafariz. E eu lá, caminhando para relaxar um pouco.

Isso me levou a pensar: o que eu posso saber sobre essas pessoas na redenção? Pouca coisa, na verdade. Não posso inferir nada, não posso pensar que eu sei as condições que levaram as pessoas  a estarem ali naquele momento e naquela hora realizando a atividade que estão realizando.

E esse é um pensamento importante pra mim, pois lembrei de uma atitude que eu acho no mínimo irritante, apesar de ser um tanto comum. Tem gente que tem certo prazer de ver pessoas em volta e ifcar imaginando historais pra elas, e comentando das vidas de todo mundo, ou de como pensam serem as vidas de todos em volta, de forma pejorativa. O que é irritante, mas só se torna prejudicial se a pessoa ouvir e ficar ofendida, a meu ver.

O problema de não se ter consicência do que não podemos saber é um tanto mais grave. É generalizar esse comportamento para inventar qualidades depreciativas sobre todos aqueles que realizam uma atitude contrária ao que se pensa serem adequadas. Um exemplo CLÁSSICO é aquele conservador conformista que diz que "todo manifestante é vagabundo". Daria pra aplicar ao meu caso, e dizer que o pessoal que tava no meio da semana e no meio da tarde na redenção devem ser todos vagabundos, ou será que eram pós-graduandos também?

E eu comento isso porque acho importante evitar seguir o caminho do preconceito. Acho que só temos a crescer quando passamos a tentar compreender as pessoas no lugar de julgá-las. E infelizmente vejo muita gente que prefere seguir o caminho simples da generalização do que não lhe agrada em vez de admitir que seus (pré)conceitos não são tão bem fundamentados assim.

***

E agora, só para finalizar esse texto mal escrito em dois momentos, com um muito de cansaço e um pouco de álcool, Lightning Bolt:

domingo, 10 de março de 2013

Se eu soubesse antes... 2

Um pequeno complemento no texto anterior. O programa chamado "errado" roda sem problemas aparentes se não é usada a opção -fbounds-check (ou -fcheck=bounds na versão mais atualizada).
program errado
implicit none
integer,dimension(:),allocatable :: a
integer :: b
allocate(a(10))
b = a(11)
endprogram errado
Usando o Valgrind (mais especificamente, a ferramenta MemCheck), aparece o seguinte aviso:
==5433== Invalid read of size 4
==5433==    at 0x4008F2: MAIN__ (errado.f03:6)
==5433==    by 0x40094A: main (errado.f03:7)

Rodando um segundo programa, que eu fiz pra continuar testando como se encontrar os erros, encontrei o seguinte:
program errado2

integer,parameter :: kr = 8
integer,dimension(6) :: r
real(kr),dimension(:),allocatable :: a,b
integer :: i,j

allocate(a(10),b(10))

b = (/ (real(i,kr),i=1,10) /)

do i=1,10
 r = (/ (i+j,j=1,6) /)
 write(*,'(6ES13.3E3)')a(r)
enddo

do i=1,10
 r = (/ (i+j,j=1,6) /)
 write(*,'(6ES13.3E3)')b(r)
enddo

write(*,*)'Fim'
endprogram errado2

$ valgrind --track-origins=yes ./errado2
*** algumas linhas cortadas ***
==5672== Conditional jump or move depends on uninitialised value(s)
==5672==    at 0x4F0FF57: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x4F10BC6: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x4F11D80: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x4F0AC25: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x4F08F72: _gfortran_transfer_array (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x400E8F: MAIN__ (errado2.f03:15)
==5672==    by 0x40118F: main (errado2.f03:24)
==5672==  Uninitialised value was created by a heap allocation
==5672==    at 0x4C28B8C: malloc (vg_replace_malloc.c:270)
==5672==    by 0x400AD7: MAIN__ (errado2.f03:9)
==5672==    by 0x40118F: main (errado2.f03:24)
==5672== 
==5672== Syscall param write(buf) points to uninitialised byte(s)
==5672==    at 0x58E0AF0: __write_nocancel (syscall-template.S:82)
==5672==    by 0x4F0E0BC: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x4F145EE: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x4F09B76: ??? (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x4F0A458: _gfortran_st_write_done (in /usr/lib/x86_64-linux-gnu/libgfortran.so.3.0.0)
==5672==    by 0x400E9E: MAIN__ (errado2.f03:15)
==5672==    by 0x40118F: main (errado2.f03:24)
*** mais algumas linhas cortadas ***
A opção --track-origins=yes mostra as informações em Unitialised value was created by a heap allocation ... As linhas que apontam onde está o erro (dessas que eu colei acima) são as seguintes:
==5672==    by 0x400E8F: MAIN__ (errado2.f03:15)
==5672==    by 0x400AD7: MAIN__ (errado2.f03:9)
==5672==    by 0x400E9E: MAIN__ (errado2.f03:15)
Nota-se que a linha 9 é onde a variável é alocada, e esse local é apontado onde diz como o valor não inicializado foi criado.

sexta-feira, 22 de fevereiro de 2013

Se eu soubesse antes...

Quando eu peguei meu projeto de pesquisa, imaginei que seria tranquilo. O maior trabalho seria criar a ferramenta para as análises, que é a modificação de um programa já existente em Fortran 90.

Se eu tivesse me mantido nas ferramentas que eu conhecia na época, talvez tivesse sido mesmo tranquilo. Até entrar no mestrado eu usava o editor de VBA pra Excel, depois eu comecei a usar o Visual Studio. Daí no meio do mestrado eu troquei o sistema operacional pra GNU/Linux e não me preocupei com IDE. E o que eu tinha feito antes era tão simples que eu também não me preocupei com debuggers.

Até lá, eu vivia no mundo mágico onde tudo funcionava, mesmo que eu não soubesse exatamente como. Não que eu não ficasse intrigado, mas eu não tive maiores problemas por não conhecer profundamente o que eu estava fazendo.

Então começaram os trabalhos. Enquanto eu ficava com o notepad++ (windows) ou o gedit (ubuntu) mais uma tela de terminal aberta, meus colegas rodavam o Visual Compaq em máquinas virtuais rodando Windows XP. Enquanto eu usava gFortran, eles usavam o iFort (é da Intel, não da Apple).

E daí eu tive umas dificuldades a mais, que aos poucos fui entendendo como solucionava.

1) A primeira coisa que eu deveria saber, na verdade eu já sabia, só não apliquei direito. Comecei a fazer as alterações criando módulos novos e testando. Só que chegou uma hora que eu parei de testar os módulos porque não conseguia mais entender como modularizar os testes das funções. Esse foi o primeiro erro. Com um pouco de conversa com os mais experientes eu provavelmente teria conseguido fazer os testes, e não programar várias funções diferentes sendo chamadas umas nas outras sem saber onde estavam os erros.

2) Flags de compilação. Isso é básico, muito básico. O que foi mais útil pra mim foram as flags de avisos, que me ajudaram a rastrear não só os erros, como o que estava mal escrito. Sem esses avisos, o compilador apontava pra linhas que eu não conseguia entender por que havia um erro. Depois de ativar os avisos veio a resposta: porque o erro não estava ali. Então, comecei compilando com:
$ gfortran programa.f90 -o programa

E agora eu faço usando scripts como esse:
$ cat c.sh
str=$1
len=${#str}
gfortran -g -fbounds-check -fmax-errors=3 -Wuninitialized -ffpe-trap=overflow -fbacktrace -ffree-line-length-0 -Wall -Wtabs $1 -o ${str:0:(len-4)}
$ ./c.sh programa.f03
Para o .bat, eu lembro que a referência é dada por %1 e não $1, mas nunca lembro como manipula strings.

Nota que tem um ponto importante que foi a fonte dos meus pepinos dos últimos meses, que o -fbounds-check evita. O seguinte código não vai dar erro sem o -fbounds-check. Por sinal, por algum motivo não consegui fazer dar erro agora pelo vetor a não ter sido inicializado, tenho que dar uma olhada nisso com mais calma.
program errado
implicit none
integer,dimension(:),allocatable :: a
integer :: b
allocate(a(10))
b = a(11)
endprogram errado


3) Debugger. Fiz o debug por mais de um ano colocando todos os write(*,*) possíveis e imagináveis no código, até perceber que tinha variáveis demais e eu não estava entendo mais o que acontecia. Meu trabalho teria sido mais rápido e fácil se, 1 ano atrás, eu tivesse aprendido a usar algum debugger. Então, era hora de procurá-lo, antes tarde do que nunca, dizem por aí. Resolvi usar o GDB. O detalhe é que ele, a princípio, tá redondinho pro Fortran 77, mas não necessariamente pros mais recentes. Não sei se o pepino é do GDB ou do gFortran, mas depois de 2 dias aprendendo a usar o GDB eu descobri que não conseguia ver as variáveis dos arrays alocados dinamicamente. Resolvi fazer um programa de teste pra encontrar o problema, e mudei pra encontrar a "solução" (também conhecida como gambiarra). O programa ficou o seguinte:
program kindreal
implicit none

integer,parameter :: kr4=4,kr8=8

real(kr4),dimension(2)   :: a4
real(kr8),dimension(2)    :: a8
real(kr4),dimension(:),allocatable :: b4
real(kr8),dimension(:),allocatable :: b8

real(kr8) :: arg1,arg2

arg1 = 10.d0
arg2 = 9.d200

a8 = (/ arg1,arg2 /)
b8 = (/ arg1,arg2 /)

a4(1) = real(arg1,kr4)
b4(1) = real(arg1,kr4)
a4(2) = huge(a4(2))
b4(2) = huge(b4(2))

write(*,*)'a4',a4(:)
write(*,*)'b4',b4(:)
write(*,*)'a8',a8(:)
write(*,*)'b8',b8(:)

endprogram kindreal

E a saída ficou:
 a4   10.000000      3.40282347E+38
 b4   10.000000      3.40282347E+38
 a8   10.000000000000000       8.99999999999999939E+200
 b8   10.000000000000000       8.99999999999999939E+200

Vendo no GDB, fica da seguinte forma:
(gdb) p a4
$1 = (10, 3.40282347e+38)
(gdb) p b4
$2 = (0)
(gdb) p a8
$3 = (10, 8.9999999999999994e+200)
(gdb) p b8
$4 = (0)
(gdb) p *((real *)b4)
$5 = 10
(gdb) p *((real *)b4)@2
$6 = (10, 3.40282347e+38)
(gdb) p *((real *)b8)@2
$7 = (0, 2.5625)
O que mostra que o problema é como mostrar os arranjos alocáveis em real(8), que eu não descobri como fazer.

Bom, na verdade o erro é não saber o que se está fazendo, mas aos poucos eu vou descobrindo.

PS: O texto "O Retorno (2/2)" está quase escrito. Só não sei se vai ser (2/2) ou (1,5/2), hehe.
PS2: Como eu não sabia colocar código na página (não manjo nada de html), usei isso aqui: http://formatmysourcecode.blogspot.com.br/
PS3: Não podia faltar uma música pra encerrar o texto:

domingo, 17 de fevereiro de 2013

O Retorno (1/2) - Sobre a Fofoca

Depois de 2 anos, 1 mês e 5 dias, espero ter o ânimo de voltar a publicar minhas bobagens por aqui, já que elas têm que tomar seu rumo pra liberar o espaço em disco pra bobagens novas.

Eu costumo dizer que a fofoca é um meio de auto-defesa. Enquanto governos têm suas agências de inteligência, o cidadão comum tem a fofoca.

Embora a fofoca seja geralmente vista como ruim, eu ejo como apenas uma troca de informações entre as pessoas quando seus assuntos pessoais já se extinguiram, algo bastante natural entre seres que precisam se comunicar constantemente. Assim, a fofoca permite que se conheça melhor (e de forma mais rápido, porque ela tem um certo dinamismo) as pessoas com quem se convive. Isso vale tanto para o sujeito da fofoca (o que espalha a informação) quanto para o objeto (o que é relacionado na informação).

Uma parte muito importante da fofoca é o fofoqueiro. Suas intenções e seu relacionamento com o fofocado são tão importantes quanto o fato da fofoca em si. Isso porque na fofoca ocorre o efeito do telefone sem fio: a cada retransmissão a historia se altera um pouco, de acordo com quem conta. Assim, a confiança que se deve ter na historia é a mesma que se dá numa corrente do facebook.

Então, se houver a intenção de repassar a informação, é bom que fique claro que: a) quando tu repassas uma informação sobre outrem, ao mesmo tempo estás passando informações sobre ti e; b) o risco é grande da informação ser falsa ou estar bastante distorcida, caso não seja verificada.

E agora, com todo esse risco da informação não ser confiável, como é que a fofoca pode ser útil mesmo? Eu vejo as informações de fofoca como partes de um quebra-cabeça. Se a historia vier muito alterada, a peça na verdade faz parte de outro quebra-cabeça, e cabe ao receptor usar seu discernimento para filtrar as informações e colocá-las em seu devido lugar. E esse quebra-cabeça sempre terá mais peças a acrescentar, nunca estará completo. Se nem sobre nós mesmos conseguimos ter conhecimento pleno, imagina se poderíamos ter sobre os outros.


E uma questão final: fofocar é errado? Se é certo ou errado, não sei dizer. Mas eu acho que é natural. Na minha visão pessoal, não é errado se a informação não for difamadora, nem confidencial (e talvez algum outro critério que eu não lembre agora, mas esses são essenciais). Também lembro que informação confidencial não é aquela que vem num envelope com um escrito de "ULTRA SECRETO" em letras garrafais, e sim aquela informação que é de algo mais delicado, ou que simplesmente a pessoa sobre a qual se fofoca não queira que seja compartilhada. E esse tipo de classificação varia de pessoa pra pessoa, então é necessário algum tato pra não falar bobagem por aí.

A parte 2 d'O Retorno será um complemento desta primeira, mas não relacionada com fofocas, exatamente. Até lá, ouve aí esse som do caralho: Kruger

Kruger_Dukes_Rock Altitude 2010 from PATLALA. on Vimeo.