Otimizações automáticas (I)

Antes de mais nada…

Já que na maioria do tempo vou falar sobre desenvolvimento usando linguagem C, é bom entendermos algumas coisas sobre o compilador: Em primeiro lugar, existem diversos compiladores C/C++ no mercado. O gcc (GNU C Compiler) não é o melhor, mas é um dos primeiros da lista. Em termos de geração de código performático o icc (Intel C++ Compiler) parece ser o melhor. O Compiler and Linker (cl.exe) da Microsoft é muito bom, mas não chega perto do gcc. Se isso soa perigosamente como uma quase declaração de amor ao projeto GNU e ao Linux, você está correto!

Compiladores C/C++ são os únicos que conheço que permitem controlar o nível de otimização do código final. Outros compiladores de outras linguagens prometem a mesma coisa, mas não fazem. O C# Compiler (csc.exe), da Microsoft, por exemplo, possui uma opção única -O (ou algo parecido), só que o código gerado é para um processador virtual, em uma “linguagem intermediária” (não é “linguagem de máquina”). Daí não tem muito sentido controlar a otimização do código final. O mesmo vale para o Java Compiler (javac). Se você é um feliz programador Delphi, o Delphi Compiler não tem muita opção de controle de otimização. O código gerado pelo Delphi é, por padrão, destinado ao 386.

O primeiro ponto que quero ressaltar é como usar o compilador (gcc) para gerar códigos eficientes. Para conseguir isso precisamos passar “dicas” para o compilador para que ele decida se deve ou não otimizar certas características de nossos códigos. Só que, antes, precisamos gerar códigos sem otimização para podermos debugá-los. Isso é feito passando a opção -O0 (“O” de “Optimization”). Nos compiladores mais antigos apenas a opção -O existia, nos mais recentes temos um conjunto de possibilidades de otimizações. Eis uma lista das possibilidades do gcc:

Opções que são ligadas pelos atalhos -O#

Em tempo: A opção -Os é destinada para otimização de tamanho de código. Não é lá uma otimização de fato, no meu ponto-de-vista.

Na realidade essas opções são atalhos para outras. Esses atalhos evitam que tenhamos que passar um caminhão de opções na linha de comando. A linha de comando mínima para obter código performático é:

$ gcc -mtune=<cpu> -O3 <arquivo.c> -o <arquivo-executável>

No caso da plataforma Intel “<cpu>” pode ser uma dessas: gemeric, native, i386, i486, pentium, i686, pentium2, prntiumpro, pentium3, pentium4, prescott e core2 (e ainda, as variações das CPUs da AMD e algumas outras). A não ser que seu alvo seja máquinas que tenham o Core 2 Duo (ou Quad), não recomendo o uso de “core2” e sim o uso de, pelo menos, “pentium3” (já que processadores inferiores a este são ferro-velho, hoje em dia). Também não recomendo “native”, que gerará código otimizado para sua máquina especificamente. E, mesmo que você use “core2” ou “native”, isso não garante que o código rodará apenas nos Core 2, da Intel (ou na sua máquina), mas que o compilador tentará ordenar as instruções de forma tal que o paralelismo entre as pipes U e V de um dos “cores” sejam plenamente usadas. Se você usar “core2”, por exemplo, como arquitetura e executar seu programa num Pentium, é provável que funcione, mas a performance pode ficar ligeiramente comprometida.

Dê uma olhada na lista de opções do gcc (é enorme!), o manual pode ser baixado aqui. Mas tenha em mente que as opções -O# são um bom começo para a geração de código otimizado.

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s