Rodrigo Strauss :: Blog
![]() |
Follow @rodrigostrauss |
Usando Win32 API para otimizar o I/O, parte 4
Parte Zero Parte 1 Parte 2 Parte 3 Parte 4 Parte 5 Parte 6 Fontes do parser
Conhecer a arquitetura do sistema operacional e de todas as dependências do seu software é essencial na hora de fazer otimização. Muitas vezes, mudanças muito pequenas no código podem melhorar substancialmente um software. Até porque, uma mudança pequena pode causar grandes mudanças no funcionamento de um módulo do sistema operacional ou de alguma biblioteca.
Além do conhecimento, é importante saber bem o que se está fazendo (e prestar atenção na documentação :-)). Na documentação do CreateFile na MSDN, estão listados diversos flags que você pode passar quando abre um arquivo. No nosso caso específico, o que mais chama atenção é o FILE_FLAG_SEQUENTIAL_SCAN:
FILE_FLAG_SEQUENTIAL_SCAN |
A file is accessed sequentially from beginning to end. The system can use this as a hint to optimize file caching. If an application moves the file pointer for random access, optimum caching may not occur. However, correct operation is still guaranteed.
Specifying this flag can increase performance for applications that read large files using sequential access. Performance gains can be even more noticeable for applications that read large files mostly sequentially, but occasionally skip over small ranges of bytes. |
Usando essa flag, estamos dizendo ao Windows que acessaremos o arquivo do início ao fim, sequencialmente. A função interpreta isso como uma dica, que pode ser usada para otimizar o cache do arquivo. Sabendo como acessaremos o arquivo, o Windows pode "prever" nosso comportamento e ficar preparado para isso.
Modificando o trecho de código que abre o arquivo, ele ficará assim:
// // chama atual para abrir um arquivo // hFile = CreateFile(str.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); // // nova chamada para abrir um arquivo // hFile = CreateFile(str.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
Refeitos os testes de desempenho, temos os seguintes resultados:
Média de tempo (50 chamadas):
228,01 ms - versão usando a runtime do C++
214,68 ms - versão usando CreateFile
204,17 ms - versão usando CreateFile com FILE_FLAG_SEQUENTIAL_SCAN
5,15% - melhoria em relação a versão Win32 sem FILE_FLAG_SEQUENTIAL_SCAN
11,68% - melhoria em relação a versão inicial (runtime C++)
Ganhamos mais ~5% de desempenho somente trocando UM flag em UMA chamada. Isso foi quase a mesma melhoria que ganhamos trocando todos os acessos feitos usando a runtime do C++ por chamadas Win32. Conhecimento é poder.
Em 29/08/2005 16:15, por Rodrigo Strauss