Я раньше немного пользовался AQTime для Delphi, в частности для оптимизации кода. AQTime в теории должен показывать участки кода, которые надо оптимизировать. Но я не очень верю в этот подход, потому что для измерения скорости нужно ставить в коде счётчики, а счётчики сами отнимают ресурсы. Мне интуитивно кажется что такие вещи, как работа счётчиков, необходимо контролировать самому.
Поэтому я написал такой объект на Delphi:
type
TSpeedManager=record
FSession:record
CurTagsCount:integer;
AllTagsCount:integer;
Tags:array[0..maxsessiontagscount-1] of record
RunsCount:int64;
RunsSumTimeMs:int64;
LastTime:longword;
end;
SessionActivationTime:longword;
SessionFinalizationTime:longword;
end;
FSessionFinalized:boolean;
FReport:tstringlist;
procedure WriteSessionReport;
procedure SaveReportToFile;
procedure StartSession(alltagscount:integer);
procedure FinalizeSession;
procedure PlaceTag(tagnum:integer);
procedure Initialize;
procedure Finalize;
end;
var
ProjectSpeedManager:TSpeedManager;
В моём коде этот объект используется, например, вот так:
function TLinearTrianlesPlaneUnpackedModel.CalculateQPart(pointx,pointy:integer):double;
begin
projectspeedmanager.StartSession(4);
projectspeedmanager.PlaceTag(1);
result:=CalculateQPartR(pointx,pointy)*(1-FKDeriv2);
projectspeedmanager.PlaceTag(2);
result:=result+CalculateQPartDN(pointx,pointy)*FKDeriv2;
projectspeedmanager.PlaceTag(3);
projectspeedmanager.FinalizeSession;
end;
Это код для МНК-минимизации некоего функционала; функционал состоит из двух слагаемых, соответственно считается двумя разными функциями. В данном участке считается не сам функционал, а его градиент по конкретному параметру, и градиент также состоит из двух слагаемых.
Когда программа отработала, projectspeedmanager сохранил текстовой файл отчёт, из которого я узнал, что код между тагами 1 и 2 занял 68% всего времени, а код между тэгами 2 и 3 – 31% времени. Соответственно я теперь знаю, что для оптимизации нужно прежде всего ускорить функцию CalculateQPartR, и в ней я также могу разместить тэги в разных её участках, чтобы узнать какие участки самые проблемные, потом разместить тэги и в них и т.д. Также projectspeedmanager сообщил мне, что выполнение всего кода между StartSession и FinalizeSession заняло 82% всего времени работы программы, точнее кода, который вызывал эту функцию CalculateQPartR (я и сам уже знал что функция CalculateQPartR лимитирующая, но на всякий случай полезно такие вещи проверять).
Это пока работает скорее в самых простых случаях, а мне придётся ещё приспосабливать мой амперметр для более сложных вариантов, например когда часть счётчиков находится внутри цикла, а часть за его пределами. Возможно тут будут нужны какие-то вложенные сессии, каждая со своим набором счётчиков.
В дальнейшем, возможно, потребуется сделать ещё вот что: “прокалибровать” мой амперметр, чтобы знать, сколько времени отнимает вызов счётчиков, и учесть это в пересчёте процентов, отданных каждому участку кода.
Можете подсказать, как аналогичный объект будет выглядеть на C++?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать". АБ Стругацкие.