logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog

follow us in feedly

A otimização do Visual C++ faz toda a diferença

Estou fazendo um parser de IDL para meu projeto de computação distribuída. Nessa primeira fase, eu interpreto o aquivo IDL e preencho várias estruturas que descrevem as interfaces e seus métodos.

Todo esse projeto está sendo feito em C++ padrão ISO, sem usar recursos específicos do Windows. Eu uso std::string em todo o programa, e o tratamento de erro é feito usando exceções. Para fazer o parse do arquivo eu usei o boost::tokenizer, que eu gostei muito. Você passa um std::string (ou dois iterators, início e fim) com o conteúdo do arquivo e ele te retorna um iterator forward-only para você percorrer os tokens do arquivo. Além disso você precisa informar quais serão os separadores de token, mas é só isso:

#include <iostream>
#include <boost/tokenizer.hpp>

#include <string>

using namespace std;
using namespace boost;


int main()
{
   string str = "int main() { std::cout << "1bit.com.br" << std::endl; }";
   tokenizer<char_separator<char> > Tokenizer(string());
   
   Tokenizer.assign(str,char_separator<char>("tr " , "n"*,;:{}/\[]()"));
   
   //
   // percorre todos os tokens
   //
   for(tokenizer<char_separator<char> >::const_iterator i = Tokenizer.begin() ;
       i != Tokenizer.end();
       ++i)
   {
       cout << *i << "n";
   }
}

Depois de algumas noites e alguns fins de semana programando, eu finalmente terminei uma versão usável do meu parser. No final, eu coloquei um contador de tempo para medir se eu precisava ou não otimizar o código, e para comparar com o MIDL da Microsoft. Esse é o resultado que eu obtive com a versão debug (Athlon XP 2600+, Visual C++ 7.1) :

// versão debug
Parsing import file oaidl.idl
Parsing import file objidl.idl
Parsing import file unknwn.idl
Parsing import file wtypes.idl
Parsing import file ocidl.idl
Parsing import file oleidl.idl
Parsing import file servprov.idl
Parsing import file urlmon.idl
Parsing import file msxml.idl
Parsing import file spbase.idl
Finish (7625 ms)

Mais do que 7 segundos, muito lento. Foi então que eu resolvi mudar para versão Release e configurar as otimizações com carinho. Veio então o resultado:

// versão release
Parsing import file oaidl.idl
Parsing import file objidl.idl
Parsing import file unknwn.idl
Parsing import file wtypes.idl
Parsing import file ocidl.idl
Parsing import file oleidl.idl
Parsing import file servprov.idl
Parsing import file urlmon.idl
Parsing import file msxml.idl
Parsing import file spbase.idl
Finish (265 ms)

28 vezes mais rápido!! Todo o "overhead" de usar std::string desapareceu. Vendo o disassembly do código gerado, muitos dos métodos do std::string foram transformados em inline, e era como se eu estivesse usando string C nativa. Isso acaba com as desculpas de pessoas que não usam STL dizendo que ela deixa o programa mais lento. Além do overhead já ser pequeno pela simplicidade da implementação do STL, essa desculpa desaparece na versão Release. Mesmo porque, como o código da STL é simples, o compilador tem mais facilidade para otimizá-lo. Muito mais do que para otimizar a gambiarra complicada que você perderia dias e dias para fazer.

Vale lembrar que eu me esforcei para fazer o código da forma mais clara e bug-free possível. Nem acesso a arquivos foi otimizado, eu simplesmente li o arquivo inteiro em uma std::string usando getline(f, str, f.widen(EOF)). Eu ainda posso otimizar isso usando FileMapping e passando o ponteiro de início e fim como iterators para o boost::tokenizer.


Em 26/07/2005 18:53, por Rodrigo Strauss


  
 
 
Comentários
Wanderley Caloni Jr | website | e-mail | em 27/07/2005 | #
De fato o VC otimiza que é uma beleza. Vale a pena a quem está interessado observar a diferença do assembly das versões Debug e Release de rotinas simples, como loops e chamadas de funções simples. E, é claro, STL.

Só uma coisa me deixou triste: o sizeof(std::string) da STL padrão que vem no VC 2003 tem 28 bytes!! Fiquei mais decepcionado ainda ao notar que para as classes CAtlString e CSimpleString o sizeof é igual a 4. Se você notar na definição da classe, verá que eles criam um buffer de 16 bytes para strings pequenas, o que evita a alocação dinâmica desnecessária, mas deixa a string padrão c++ bem maior que um simples ponteiro. Seria o caso de utilizar um heap de blocos de tamanho fixo para std::string's alocadas? O que levou essa implementação da STL a ter esse overhead?
Rodrigo Strauss | website | em 27/07/2005 | #
Eu acho esse overhead bom (?!). Muitas vezes você usa uma string pequena, e essa implementação faz com que uma string pequena seja alocada na pilha como uma string C. Eu não sabia que era assim, mas acho ótimo.

O overhead de alocação/desalocação do heap é MUITO maior do que 28 bytes na pilha. Na verdade, 28 bytes de pilha causa um overhead zero, já que alocação da pilha não gasta tempo considerável.

No livro "Modern C++ Design", o Alexandrescu implementa um "Small Object Allocator", justamente por saber que o gerenciamento de Heap do C++ é geralmente só uma camada sobre o gerenciamento do C (malloc), que funciona muito bem para alocações grandes (kbytes), mas nem-tão-bem-assim para alocações menores (bytes).
Wanderley Caloni Jr | website | e-mail | em 27/07/2005 | #
É, pensando por esse lado, até que é uma coisa boa. De qualquer forma, strings podem existir das mais variadas, pois tudo depende do objetivo em mente.

Só acho que seria interessante se o VC tivesse maneiras de configurar o funcionamento das classes STL. Se existe, desconheço. Procurei a respeito da std::string e não encontrei nada nos fontes.
Fabio Galuppo | em 03/08/2005 | #
Isto me lembrou um antigo post no falecido blog :) : http://br.thespoke.net/BlogReader/SingleEntry.aspx?ID=17516
Pressley Neto | e-mail | em 13/08/2005 | #
sou um principiante em c++
tenho 17 anos
é quero ser um exelente programador ( em c++ é claro)
Algo a dizer?
Nome:


Site:


E-mail:


Escreva o número vinte e seis:


 Não mostre meu e-mail no site, não serve pra nada mesmo...

Comentário





Os comentários devem ser sobre assuntos relativos ao post, eu provavelmente apagarei comentários totalmente offtopic. Se quiser me enviar uma mensagem, use o formulário de contato. E não esqueça: isso é um site pessoal e eu me reservo o direito de apagar qualquer comentário ofensivo ou inapropriado.
rebarba rebarba
  ::::