331 lines
9.9 KiB
ObjectPascal
331 lines
9.9 KiB
ObjectPascal
|
|
unit StackTraceViewerFastMMUnit;
|
||
|
|
|
||
|
|
interface
|
||
|
|
|
||
|
|
uses
|
||
|
|
SysUtils, Classes, Forms, Contnrs, FastMMParser, JclStackTraceViewerAPI;
|
||
|
|
|
||
|
|
type
|
||
|
|
TCustomTreeViewLinkClass = class of TCustomTreeViewLink;
|
||
|
|
|
||
|
|
TCustomTreeViewLink = class(TInterfacedObject, IJclStackTraceViewerTreeViewLink)
|
||
|
|
private
|
||
|
|
FItems: TInterfaceList;
|
||
|
|
FText: string;
|
||
|
|
public
|
||
|
|
constructor Create(const AText: string);
|
||
|
|
destructor Destroy; override;
|
||
|
|
function Add(const AText: string; AClass: TCustomTreeViewLinkClass): TCustomTreeViewLink;
|
||
|
|
procedure Clear;
|
||
|
|
procedure DoShow(AFrame: TCustomFrame); virtual;
|
||
|
|
function GetCount: Integer;
|
||
|
|
function GetFrameClass: TCustomFrameClass; virtual;
|
||
|
|
function GetItems(AIndex: Integer): IJclStackTraceViewerTreeViewLink;
|
||
|
|
function GetText: string;
|
||
|
|
end;
|
||
|
|
|
||
|
|
TRootTreeViewLink = class(TCustomTreeViewLink);
|
||
|
|
|
||
|
|
TDummyTreeViewLink = class(TCustomTreeViewLink);
|
||
|
|
|
||
|
|
TLeakTreeViewLink = class(TCustomTreeViewLink)
|
||
|
|
private
|
||
|
|
FLeakData: TFastMMLeak;
|
||
|
|
public
|
||
|
|
constructor Create(const AText: string);
|
||
|
|
procedure DoShow(AFrame: TCustomFrame); override;
|
||
|
|
function GetFrameClass: TCustomFrameClass; override;
|
||
|
|
property LeakData: TFastMMLeak read FLeakData write FLeakData;
|
||
|
|
end;
|
||
|
|
|
||
|
|
TLeakGroupTreeViewLink = class(TCustomTreeViewLink)
|
||
|
|
private
|
||
|
|
FLeakGroupData: TFastMMLeakGroup;
|
||
|
|
public
|
||
|
|
constructor Create(const AText: string);
|
||
|
|
procedure DoShow(AFrame: TCustomFrame); override;
|
||
|
|
function GetFrameClass: TCustomFrameClass; override;
|
||
|
|
property LeakData: TFastMMLeakGroup read FLeakGroupData write FLeakGroupData;
|
||
|
|
end;
|
||
|
|
|
||
|
|
TLeakSummaryTreeViewLink = class(TCustomTreeViewLink)
|
||
|
|
private
|
||
|
|
FReport: TFastMMReport;
|
||
|
|
public
|
||
|
|
constructor Create(const AText: string);
|
||
|
|
procedure DoShow(AFrame: TCustomFrame); override;
|
||
|
|
function GetFrameClass: TCustomFrameClass; override;
|
||
|
|
property Report: TFastMMReport read FReport write FReport;
|
||
|
|
end;
|
||
|
|
|
||
|
|
TFreedObjectTreeViewLink = class(TCustomTreeViewLink)
|
||
|
|
private
|
||
|
|
FFreedObjectData: TFastMMVMOnFreedObject;
|
||
|
|
public
|
||
|
|
constructor Create(const AText: string);
|
||
|
|
procedure DoShow(AFrame: TCustomFrame); override;
|
||
|
|
function GetFrameClass: TCustomFrameClass; override;
|
||
|
|
property FreedObjectData: TFastMMVMOnFreedObject read FFreedObjectData write FFreedObjectData;
|
||
|
|
end;
|
||
|
|
|
||
|
|
TFastMMReportData = class(TObject)
|
||
|
|
private
|
||
|
|
FReportList: TObjectList;
|
||
|
|
FRootLink: TRootTreeViewLink;
|
||
|
|
FRootLinkIntf: IJclStackTraceViewerTreeViewLink;
|
||
|
|
public
|
||
|
|
constructor Create;
|
||
|
|
destructor Destroy; override;
|
||
|
|
procedure LoadFastMMFile(const AFileName: string);
|
||
|
|
end;
|
||
|
|
|
||
|
|
implementation
|
||
|
|
|
||
|
|
uses
|
||
|
|
FastMMLeakFrame, FastMMLeakGroupFrame, FastMMLeakSummaryFrame, FastMMFreedObjectFrame;
|
||
|
|
|
||
|
|
{ TTestTreeViewLink }
|
||
|
|
|
||
|
|
constructor TCustomTreeViewLink.Create(const AText: string);
|
||
|
|
begin
|
||
|
|
inherited Create;
|
||
|
|
FItems := TInterfaceList.Create;
|
||
|
|
FText := AText;
|
||
|
|
end;
|
||
|
|
|
||
|
|
destructor TCustomTreeViewLink.Destroy;
|
||
|
|
begin
|
||
|
|
//FStack.Free;
|
||
|
|
FItems.Free;
|
||
|
|
inherited Destroy;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TCustomTreeViewLink.Add(const AText: string; AClass: TCustomTreeViewLinkClass): TCustomTreeViewLink;
|
||
|
|
begin
|
||
|
|
Result := AClass.Create(AText);
|
||
|
|
FItems.Add(Result);
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TCustomTreeViewLink.Clear;
|
||
|
|
begin
|
||
|
|
FItems.Clear;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TCustomTreeViewLink.DoShow(AFrame: TCustomFrame);
|
||
|
|
begin
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TCustomTreeViewLink.GetCount: Integer;
|
||
|
|
begin
|
||
|
|
Result := FItems.Count;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TCustomTreeViewLink.GetFrameClass: TCustomFrameClass;
|
||
|
|
begin
|
||
|
|
Result := nil;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TCustomTreeViewLink.GetItems(AIndex: Integer): IJclStackTraceViewerTreeViewLink;
|
||
|
|
begin
|
||
|
|
if FItems[AIndex].QueryInterface(IJclStackTraceViewerTreeViewLink, Result) <> S_OK then
|
||
|
|
Result := nil;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TCustomTreeViewLink.GetText: string;
|
||
|
|
begin
|
||
|
|
Result := FText;
|
||
|
|
end;
|
||
|
|
|
||
|
|
{ TLeakTreeViewLink }
|
||
|
|
|
||
|
|
constructor TLeakTreeViewLink.Create(const AText: string);
|
||
|
|
begin
|
||
|
|
inherited Create(AText);
|
||
|
|
FLeakData := nil;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TLeakTreeViewLink.DoShow(AFrame: TCustomFrame);
|
||
|
|
begin
|
||
|
|
inherited DoShow(AFrame);
|
||
|
|
if (AFrame is TfrmLeak) and Assigned(FLeakData) then
|
||
|
|
begin
|
||
|
|
if FLeakData.Stack.Count > 0 then
|
||
|
|
StackTraceViewerStackProcessorServices.PrepareLocationInfoList(FLeakData.Stack, False);
|
||
|
|
TfrmLeak(AFrame).LeakData := FLeakData;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TLeakTreeViewLink.GetFrameClass: TCustomFrameClass;
|
||
|
|
begin
|
||
|
|
Result := TfrmLeak;
|
||
|
|
end;
|
||
|
|
|
||
|
|
{ TLeakGroupTreeViewLink }
|
||
|
|
|
||
|
|
constructor TLeakGroupTreeViewLink.Create(const AText: string);
|
||
|
|
begin
|
||
|
|
inherited Create(AText);
|
||
|
|
FLeakGroupData := nil;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TLeakGroupTreeViewLink.DoShow(AFrame: TCustomFrame);
|
||
|
|
begin
|
||
|
|
inherited DoShow(AFrame);
|
||
|
|
if (AFrame is TfrmLeakGroup) and Assigned(FLeakGroupData) then
|
||
|
|
begin
|
||
|
|
if (FLeakGroupData.Count > 0) and (FLeakGroupData[0].Stack.Count > 0) then
|
||
|
|
StackTraceViewerStackProcessorServices.PrepareLocationInfoList(FLeakGroupData[0].Stack, False);
|
||
|
|
TfrmLeakGroup(AFrame).LeakGroupData := FLeakGroupData;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TLeakGroupTreeViewLink.GetFrameClass: TCustomFrameClass;
|
||
|
|
begin
|
||
|
|
Result := TfrmLeakGroup;
|
||
|
|
end;
|
||
|
|
|
||
|
|
{ TLeakSummaryTreeViewLink }
|
||
|
|
|
||
|
|
constructor TLeakSummaryTreeViewLink.Create(const AText: string);
|
||
|
|
begin
|
||
|
|
inherited Create(AText);
|
||
|
|
FReport := nil;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TLeakSummaryTreeViewLink.DoShow(AFrame: TCustomFrame);
|
||
|
|
begin
|
||
|
|
inherited DoShow(AFrame);
|
||
|
|
if (AFrame is TfrmLeakSummary) and Assigned(FReport) then
|
||
|
|
TfrmLeakSummary(AFrame).Report := FReport;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TLeakSummaryTreeViewLink.GetFrameClass: TCustomFrameClass;
|
||
|
|
begin
|
||
|
|
Result := TfrmLeakSummary;
|
||
|
|
end;
|
||
|
|
|
||
|
|
{ TFreedObjectTreeViewLink }
|
||
|
|
|
||
|
|
constructor TFreedObjectTreeViewLink.Create(const AText: string);
|
||
|
|
begin
|
||
|
|
inherited Create(AText);
|
||
|
|
FFreedObjectData := nil;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TFreedObjectTreeViewLink.DoShow(AFrame: TCustomFrame);
|
||
|
|
begin
|
||
|
|
inherited DoShow(AFrame);
|
||
|
|
if (AFrame is TfrmFreedObject) and Assigned(FFreedObjectData) then
|
||
|
|
begin
|
||
|
|
if FFreedObjectData.Stack1.Count > 0 then
|
||
|
|
StackTraceViewerStackProcessorServices.PrepareLocationInfoList(FFreedObjectData.Stack1, False);
|
||
|
|
if FFreedObjectData.Stack2.Count > 0 then
|
||
|
|
StackTraceViewerStackProcessorServices.PrepareLocationInfoList(FFreedObjectData.Stack2, False);
|
||
|
|
if FFreedObjectData.Stack3.Count > 0 then
|
||
|
|
StackTraceViewerStackProcessorServices.PrepareLocationInfoList(FFreedObjectData.Stack3, False);
|
||
|
|
TfrmFreedObject(AFrame).FreedObjectData := FFreedObjectData;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TFreedObjectTreeViewLink.GetFrameClass: TCustomFrameClass;
|
||
|
|
begin
|
||
|
|
Result := TfrmFreedObject;
|
||
|
|
end;
|
||
|
|
|
||
|
|
{ TFastMMReportData }
|
||
|
|
|
||
|
|
constructor TFastMMReportData.Create;
|
||
|
|
begin
|
||
|
|
inherited Create;
|
||
|
|
FReportList := TObjectList.Create;
|
||
|
|
FRootLink := TRootTreeViewLink.Create('');
|
||
|
|
FRootLinkIntf := FRootLink;
|
||
|
|
end;
|
||
|
|
|
||
|
|
destructor TFastMMReportData.Destroy;
|
||
|
|
begin
|
||
|
|
FRootLinkIntf := nil;
|
||
|
|
FReportList.Free;
|
||
|
|
inherited Destroy;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TFastMMReportData.LoadFastMMFile(const AFileName: string);
|
||
|
|
var
|
||
|
|
I, J, K: Integer;
|
||
|
|
FastMMFileParser: TFastMMFileParser;
|
||
|
|
FastMMReport: TFastMMReport;
|
||
|
|
ReportLink: TDummyTreeViewLink;
|
||
|
|
LeakGroup: TLeakGroupTreeViewLink;
|
||
|
|
Leak: TLeakTreeViewLink;
|
||
|
|
Summary: TLeakSummaryTreeViewLink;
|
||
|
|
FreedObject: TFreedObjectTreeViewLink;
|
||
|
|
begin
|
||
|
|
if Assigned(StackTraceViewerStackServices) then
|
||
|
|
begin
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmLeak);
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmLeakGroup);
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmLeakSummary);
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmFreedObject);
|
||
|
|
StackTraceViewerStackServices.ShowTree(nil);
|
||
|
|
end;
|
||
|
|
FReportList.Clear;
|
||
|
|
FRootLink.Clear;
|
||
|
|
FastMMFileParser := TFastMMFileParser.Create;
|
||
|
|
try
|
||
|
|
FastMMFileParser.ParseFile(AFileName, FReportList);
|
||
|
|
finally
|
||
|
|
FastMMFileParser.Free;
|
||
|
|
end;
|
||
|
|
if Assigned(StackTraceViewerStackServices) then
|
||
|
|
begin
|
||
|
|
for I := 0 to FReportList.Count - 1 do
|
||
|
|
begin
|
||
|
|
FastMMReport := TFastMMReport(FReportList[I]);
|
||
|
|
ReportLink := TDummyTreeViewLink(FRootLink.Add(Format('Report %d', [I + 1]), TDummyTreeViewLink));
|
||
|
|
if FastMMReport.LeakSummary.Count > 0 then
|
||
|
|
begin
|
||
|
|
Summary := TLeakSummaryTreeViewLink(ReportLink.Add('Leak Summary', TLeakSummaryTreeViewLink));
|
||
|
|
Summary.Report := FastMMReport;
|
||
|
|
end;
|
||
|
|
for J := 0 to FastMMReport.LeakGroupCount - 1 do
|
||
|
|
begin
|
||
|
|
if FastMMReport.LeakGroupItems[J].Count = 1 then
|
||
|
|
begin
|
||
|
|
Leak := TLeakTreeViewLink(ReportLink.Add(Format('Leak %d', [J + 1]), TLeakTreeViewLink));
|
||
|
|
Leak.LeakData := FastMMReport.LeakGroupItems[J][0];
|
||
|
|
end
|
||
|
|
else
|
||
|
|
begin
|
||
|
|
LeakGroup := TLeakGroupTreeViewLink(ReportLink.Add(Format('Leak Group %d', [J + 1]), TLeakGroupTreeViewLink));
|
||
|
|
LeakGroup.LeakData := FastMMReport.LeakGroupItems[J];
|
||
|
|
for K := 0 to FastMMReport.LeakGroupItems[J].Count - 1 do
|
||
|
|
begin
|
||
|
|
Leak := TLeakTreeViewLink(LeakGroup.Add(Format('Leak %d', [K + 1]), TLeakTreeViewLink));
|
||
|
|
Leak.LeakData := FastMMReport.LeakGroupItems[J][K];
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
for J := 0 to FastMMReport.VMOnFreedObjectCount - 1 do
|
||
|
|
begin
|
||
|
|
FreedObject := TFreedObjectTreeViewLink(ReportLink.Add(Format('Freed Object %d', [J + 1]), TFreedObjectTreeViewLink));
|
||
|
|
FreedObject.FreedObjectData := FastMMReport.VMOnFreedObjectItems[J];
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
StackTraceViewerStackServices.ShowTree(FRootLinkIntf);
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
initialization
|
||
|
|
|
||
|
|
finalization
|
||
|
|
if Assigned(StackTraceViewerStackServices) then
|
||
|
|
begin
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmLeak);
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmLeakGroup);
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmLeakSummary);
|
||
|
|
StackTraceViewerStackServices.UnregisterFrameClass(TfrmFreedObject);
|
||
|
|
StackTraceViewerStackServices.ShowTree(nil);
|
||
|
|
end;
|
||
|
|
|
||
|
|
end.
|