Medidas de desempenho em mili e microssegundos
Autor: Geek on the beach | Publicado: 2012-07-17T00:03:00-03:00



Introdução



Depois de um longo tempo sem postar, nesse tópico iremos
abordar um pouco sobre como tirar medidas de desempenho de métodos, funções e
procedures, as medições são feitas baseadas em milissegundos e unidades
menores.



Desempenho em milissegundos



Uma forma de medir o desempenho computacional é através do
tempo de execução de uma determinada rotina, para o usuário final medidas
levianas como "rápido", "lento" ou "muito rápido"
acabam sendo parte usual do dia a dia de utilização de um sistema, mas tornar o
sistema "rápido" exige um pouco trabalho, principalmente quando
falamos de ganhos em milissegundos ou unidades menores (Que serão apresentadas
mais tarde).



O Delphi nos proporciona uma função chamada
"GetTickCount", essa função retorna um valor em cardinal que é a hora
atual em milissegundos, através dela é possível marcar o inicio e fim da
execução de um código, obtendo assim o tempo total despendido para sua
execução. A ideia é simples:
 

&nbsp;Armazenamos o valor de "GetTickCount"
antes da execução do código.&nbsp;
&nbsp;Após a execução da rotina, tiramos a diferença
de "GetTickCount" e do valor armazenado inicialmente
A diferença entre os valores revela o tempo
total em milissegundos que a rotina demorou para ser executada.

&nbsp;Na codificação ficamos com algo similar a isso:









var

&nbsp;&nbsp; Start:
Cardinal;

begin

&nbsp;&nbsp; Start :=
GetTickCount;

&nbsp;&nbsp; // Rotina em Questão

&nbsp;&nbsp; ShowMessage(IntToStr(GetTickCount - Start) +
' milissegundos');

end;



Desempenho
em microssegundos



Bom, na
teoria a medida de em milissegundos atende bem o uso geral, porem, o problema
acontece em 2 casos:

&nbsp;Quando é necessário uma medida mais precisa
que milissegundos.&nbsp;
&nbsp;Quando o tempo em milissegundos é igual a 0
(zero), ou seja, não é possível medir aquela rotina ou comando porque o tempo
despendido é inferior a 1ms.


Nesse caso nossa opção é utilizar uma medida de desempenho em
microssegundos, lembrando que milissegundos (10^-3) e microssegundos (10^-6),
basicamente 1 segundo possui 1000ms e 1ms possui 1000µs.



Para extrairmos isso a ideia principal é a mesma do
milissegundos, porem ao invés de utilizar a função "GetTickCount",
utilizamos uma função do kernel do Windows (WinApi) chamada
"QueryPerformanceCounter", repare que por se tratar de uma função api
do Windows, ela pode ser utilizada em qualquer linguagem que possua acessa
direto as Api's do Windows, eu testei essa função em Delphi e C (Declarada em
windows.h), e um amigo me fez o favor de testa-la em C# (Nesse caso é necessário
utilizar um Import de DLL), em java não sei dizer como ficaria por causa da VM,
já que em teoria o ideal é não acessar funções nativas do SO diretamente, se alguém
souber algo a respeito e se habilitar a comentar sobre, sinta-se a vontade.



A função "QueryPerformanceCounter", exige uma
passagem de parâmetro, que é basicamente uma variavel do tipo Int64 ou TLargeInteger,
após a execução o retorno da variável é a data atual em microssegundos,
seguindo o raciocínio inicial basta tirar a diferença do inicio e fim, que
obteremos a execução do código em microssegundos.



Na codificação fica assim:



var

&nbsp;&nbsp; Start, Stop: Int64;

begin

&nbsp;&nbsp; QueryPerformanceCounter(Start);

&nbsp;&nbsp; // Rotina em questão

&nbsp;&nbsp;
QueryPerformanceCounter(Stop);

&nbsp;&nbsp; ShowMessage(IntToStr(Stop - Start) + '
microssegundos');

end;



Como a implementação dessa rotina é um pouco chata, eu criei uma
classe que ajuda bastante nesse caso, pra quem quiser utilizar basta copiar e
colar em uma nova unit.



type

&nbsp;&nbsp; TMetric = class

&nbsp;&nbsp; private

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class var FStart: Int64;

&nbsp;&nbsp; public

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class procedure Start;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class procedure StopAndShow;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class function Stop: Int64;

&nbsp;&nbsp; end;



implementation



class procedure
TMetric.Start;

begin

&nbsp;&nbsp; QueryPerformanceCounter(FStart);

end;



class procedure
TMetric.StopAndShow;

var

&nbsp;&nbsp; Stop: Int64;

begin

&nbsp;&nbsp; QueryPerformanceCounter(Stop);

&nbsp;&nbsp; ShowMessage(IntToStr(Stop - FStart) + '
microssegundos');

end;



class function TMetric.Stop:
Int64;

var

&nbsp;&nbsp; Stop: Int64;

begin

&nbsp;&nbsp; QueryPerformanceCounter(Stop);

&nbsp;&nbsp; Result := Stop - FStart;

end;



A utilização da classe fica assim:



var

&nbsp;&nbsp; Metric: TMetric;

begin

&nbsp;&nbsp; Metric.Start;

&nbsp;&nbsp; // Alguma Rotina

&nbsp;&nbsp; Metric.StopAndShow; // Também
poderia ser Metric.Stop, depende de como você ira utilizar

end;



Repare que a classe "TMetric" é composta por métodos
statics ou class, que já foram citados anteriormente, logo não é necessário
instanciar a classe para utiliza-la, o mesmo vale para a variável "class
var FStart: Int64", somente se declarada dessa forma é possível utilizar
uma variável dentro de uma método static.



Conclusão



Tirar medidas de tempo em milissegundos e microssegundos é muito útil
quando queremos ter uma ideia de em quanto tempo uma rotina é executada, o
curioso é no geral quase não levamos isso em consideração, mas se você testar
por si mesmo ficara surpreso.



No próximo post, eu irei apresentar algumas medidas em mili e
microssegundos de alguns comandos, e consequentemente irei mostrar alguns
vilões que no geral passam desapercebidos enquanto programamos.