Desenvolvimento - C/C++

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.

por Rodrigo Strauss



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.

Por isso que eu amo essa linguagem e esse compilador.

-->

(Não esqueça que o código gerado pelo JIT do .NET é bem parecido com o gerado pelo Visual C++ em configuração Debug. Ah, e não esqueça também que o overhead da System.String é maior do que o do std::string)

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.

Rodrigo Strauss

Rodrigo Strauss - MCP em Visual C++ e C#. Começou a programar com 12 anos de idade, e desde lá nunca mais parou. Trabalha atualmente desenvolvendo softwares para área financeira usando Visual C++, focando a parte server side e de otimização de performance. Entre seus objetos de estudo estão as linguagens C++ e Python, otimização de performance, e programação kernel mode para plataforma Windows.
Mantém o site
www.1bit.com.br, onde escreve um blog e artigos sobre C++ e programação em geral.