É a Vida, é Bonita e é Bonita

A cachorrinha nova da Ana Paula, o nome dela é Vida. Ela ainda é uma filhotinha e é da raça Pug.

Vida, a pug

É uma raça muito carinho, sociável, obediente e leal. Como eles tem vias nasais bem pequenas, eles tem jeito estranho de respirar. Para quem nunca esteve perto de um Pug antes, como eu, a impressão que se tem é que ele está doente ou sem conseguir respirar.

Fotos:

Deborah e Vida, cachorra, cadela Deborah e Vida Deborah e Vida beijando-se Vida cabisbaixa Vida de cachorro Vida dormindo Vida Olhando a Vida Vida olhando para a c Vida Olhando para cima na grama Pug sentado na mesa Pug olhando para trás Pug pensando pug olhando pra trás pug pensando Pug tristonha

Conclusão: até o Mickey que é um rato tem um cachorro. Só eu que não tenho :(

Javascript dentro do WordPress

Vamos fazer um teste:

O código-fonte:

<input type='button' value='clique em mim' onclick="alert('funcionou')"/>

Se você clicou no botão e apareceu uma janelinha chata, então a coisa deu certo.

Para escrever códigos dentro do WordPress você precisa desligar o editor rico nas configurações. Além disso é necessário escrever códigos de uma só linha. Para códigos mais violentos, você precisa invocar o código de um arquivo .js externo.

<SCRIPT src="my.js" type="text/javascript"></SCRIPT>

Se você escrever o código dentro do editor o WordPress vai esculhambar seu código com tags html de fim de linha e parágrafo. Então você vai precisar realmente de um arquivo externo.

Decimal para Binário

Código em C para converter um inteiro positivo em uma representação em string binária.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
 
char * decpbin(unsigned int n){
   int i, r, c;
   char * bin;
   bin = calloc(16,sizeof(char));
   memcpy(bin, "0000000000000000", 16);
   i = n;
   c = 0;
   while(i>0){
      r = i % 2;
      i = i/2;
      bin[15-c] = '0'+r;
      c++;
   }
   return bin;
}
 
int main(){
   char * dec;
   dec = decpbin(1985);
   printf("%s\n", dec);
   free(dec);
}

Compilando e Testando:

$ gcc decbin.c -o decbin
$ ./decbin
0000011111000001

No caso, ele foi feito para inteiros não sinalizados. Como um inteiro ocupa 16 bits, e não estamos gastando um bit para o sinal, o maior número que pode ser convertido é 65535. Por isso criamos a string bin com 16 casas de tamanho.

Basicamente é o algoritmo que se usa para transformar um inteiro em binário. Você pega o número, pega o resto da divisão por 2, que vai ser 0 ou 1 e usa isso para representar o bit menos significativo, ou seja, o mais a direita. Depois pega o número e divide por dois e pega novamente o resto. Fica fazendo isso até que o número dividido por 2 seja 0.

Olá Mundo Paralelo com MPI

MPI é a sigla para Message Passing Interface, um padrão de comunicação de dados para computação paralela. O MPI oferece diversas abstracções que facilitam e padronizam o desenvolvimento de aplicações paralelas. Por exemplo, você pode programar para vários processadores, nós de um cluster, supercomputadores ou Internet utilizando a mesma infraestrutura transparentemente.

Supercomputador Nasa
Cluster Columbia da NASA, com 1024 nós.

Como MPI é um padrão, existem vários padrões de implementação, abertas, fechadas, comerciais ou gratuitas. MPI é definido a princípio para C e Fortran, mas há implementações em outras linguagens como Java ou Python, por exemplo. A implementação que eu vou utilizar nesse exemplo é a OpenMPI.

A notícia boa é que você não precisa ter um supercomputador em casa para aprender e praticar computação paralela, uma máquina doméstica serve. Se você tiver uma máquina com múltiplos processadores, melhor ainda.

Instalação

Para instalar um ambiente de desenvolvimento para MPI no Ubuntu Linux basta um comando:

sudo apt-get install build-essential openmpi-dev

Isso vai instalar um conjunto básico de compiladores e o ambiente OpenMPI.

O código

Vamos criar um arquivo chamado ola.c com o conteúdo:

#include
#include
int size, rank;
int main(int argc, char *argv[]){
   MPI_Init(&amp;argc,&amp;argv);
   MPI_Comm_size(MPI_COMM_WORLD,&amp;size);
   MPI_Comm_rank(MPI_COMM_WORLD,&amp;rank);
   printf("Oi. Eu sou o processo %d de %d\n", rank, size);
   MPI_Finalize();
}

Compilação

Para compilar esse código vamos usar o comando mpicc que foi instalado junto com o pacote openmpi-dev. Ele é uma interface para o gcc, e vai cuidar de toda a linkagem com as bibliotecas do MPI. Você pode usar os parâmetros do gcc com o mpicc.

mpicc ola.c -o ola

Se tudo der certo esse comando vai criar o binário ola.

Execução

Outra ferramenta importante é o mpirun, que levantar o mpi nos diversos nós e mandar cada nó executar o binário. O mpirun não precisa de um programa mpi para rodar, por exemplo, se dermos esse comando:

mpirun -np 4 echo oi

Você vai ter essa saída:

oi
oi
oi
oi

Você mandou 4 nós (-np 4) executar o comando echo oi (imprime oi). Para mandar 5 nós executarem nosso binário ola:

mpirun -np 5 ola

E vamos ter uma saída mais ou menos assim:

Oi. Eu sou o processo 1 de 5
Oi. Eu sou o processo 4 de 5
Oi. Eu sou o processo 0 de 5
Oi. Eu sou o processo 2 de 5
Oi. Eu sou o processo 3 de 5

Por que as saídas sairam desordenadas? Porque elas rodaram em paralelo e não temos como saber qual foi sua ordem de execução. Assim cada nó entrou no printf em um momento diferente e imprimiu seu rank e seu size naquele momento. Você pode experimentar usar o parâmetro -np com outros números maiores ou menores que 5.

Troca de Mensagens

Até aqui não há muita graça porque não há troca de mensagens. Há muito o que se dizer sobre como trocar mensagens do MPI mas a maneira mais fácil de se começar é com a função mpi_send.

Vamos fazer um programa bem simples onde o nó 0 vai mandar uma mensagem para o nó 1. A mensagem vai ser um número, 42. Criemos um arquivo chamado msg.c com o código:

#include
#include
 
int size, rank, msg, source, dest, tag;
 
int main(int argc, char *argv[]){
   MPI_Status stat;
 
   MPI_Init(&amp;argc,&amp;argv);
   MPI_Comm_size(MPI_COMM_WORLD,&amp;size);
   MPI_Comm_rank(MPI_COMM_WORLD,&amp;rank);
 
	if(rank==0){
   	msg = 42; dest = 1; tag = 0;
   	MPI_Send(&amp;msg, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
   	printf("Processo %d enviou %d para %d.\n", rank, msg, dest);
	}
 
	if(rank==1){
		source = 0; tag = 0;
		MPI_Recv(&amp;msg, 1, MPI_INT, source, tag, MPI_COMM_WORLD, &amp;stat);
		printf("Processo %d recebeu %d de %d.\n", rank, msg, source);
	}
 
   MPI_Finalize();
}

No processo de rank 0 vamos enviar o conteúdo da variável inteira msg para o processo de rank 1. Note que no processo de rank 1, o valor de msg não está definido. O comando MPI_Send vai receber 6 parâmetros.

int MPI_Send( void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)

  • void *buf, um ponteiro para a mensagem que você vai mandar. No nosso caso a variável inteira msg.
  • int count, a quantidade de elementos que tem nessa mensagem. No nossa caso só 1. Se quisemos mandar um vetor de dois inteiros, seria 2.
  • MPI_Datatype datatype, uma constante que define o tipo de dados que você está enviando. No nosso caso MPI_INT. Isso evita que ajam incompatibilidade no tamanho de inteiros entre arquiteturas diferentes.
  • int dest, o rank do nó destino, o destinatário. No nosso caso o nó 1.
  • int tag, a tag seria num email o assunto da mensagem. Estamos mandando tag 0 então no outro lado tem que estar esperando uma tag 0, caso contrário não há comunicação.
  • MPI_Comm comm, o comunicador. Nesse e na maioria dos casos a constante MPI_COMM_WORLD.

Do outro lado, no processo 1 vamos usar o MPI_recv, que recebe 7 parâmetros.

int MPI_Recv( void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

  • void *buf, um ponteiro para onde vai ser guardada a mensagem que vamos receber. No nosso caso a variável msg, que no processo 1 está vazia.
  • int count, a quantidade de elementos que vem nessa mensagem.
  • MPI_Datatype datatype, a mesma constante do MPI_send.
  • int source, o rank do nó remetente. No nosso caso o nó 0.
  • int tag, a tag da mensagem conforme explicado no MPI_send.
  • MPI_Comm comm, o comunicador.
  • MPI_Status *status, uma estrutura para que depois que a função for executada você possa inspecionar detalhes da transmissão. No nosso caso ela é inútil.

Para compilar esse exemplo usamos novamente o mpicc.

mpicc msg.c -o msg

E para executa-lo o mpirun.

mpirun -np 2 msg

O programa vai escrever essa mensagem:

Processo 0 enviou 42 para 1.
Processo 1 recebeu 42 de 0

No processo 1 a msg estava inicialmente vazia e no processo 0 havia 42, mas depois do MPI_recv o processo 1 pode escrever o conteúdo 42 de msg. Logo, houve comunicação.

Dicas

Por um problema no empacotamento do mpich no Ubuntu toda vez que você executa o MPI você recebe umas mensagens horrorosas de erro, que na verdade são só um aviso que ele não encontrou uma placa de rede Infiniband.

Para você silenciar na unha essa chatice use o mpirun assim:

mpiexec –mca btl ^openib -np 1 executável

Onde -np 1 deve ser substituido pelo seu número de processos e executável pelo seu executável.

Outra dica é que você pode utilizar uma distribuição Linux que já venha com o MPI instalado. Por exemplo o Scientific Linux ou o Parallel Knoppix.

Qual o Tamanho da Wikipédia?

Se a Wikipédia em inglês fosse impressa ela teria esse tamanho:

Tamanho estimado da Wikipédia em inglês impressa
Ilustração original de Nikola Smolenski.

Usando livros de 25 centímetros por 5 centímetros, com mais ou menos 400 páginas, cada página contendo duas colunas, cada coluna contendo 80 linhas e cada linha contendo 50 caracteres, dá aproximadamente 6MB por volume. Como a versão da Wikipédia em inglês tem 4.4 GB de texto (isso em Outubro de 2006) temos então 750 volumes. E isso é uma medida conservadora visto que não estamos incluindo imagens e tabelas, que consomem muito mais espaço nas folhas.

E pelo crescimento da Wikipédia desde esse período, o tamanho da prateleira deve ter dobrado! E olhe que isso é só a Wikipédia em inglês.

carbon-based lifeform. virgo supercluster