After adding some optimizations to HTML/XML parser I was curious to compare its performance to other implementations.
After adding some optimizations to HTML/XML parser I was curious to compare its performance to other implementations.
As a test sample I used Golf.xml file (500Kb) from this page
http://www.enetpulse.com/documentation/
As a participants were choosen OXML http://www.kluug.net/oxml.php (it seems to be a fastest native XML implementation for Delphi)
and standard MSXML (Xml.XMLDoc).
It is not serious test, because results are vary widely from file to file (on some files MS was 9 times slower than HCL) but gives some notion.
Delphi XE2, Win32, Windows 7, Intel Core i5.
1. Reading (string -> DOM, creating and destroying )
HCL: 1.622 ms
THtXMLNode.Create(s);
OXML: 4.415 ms
OD:=OXMLPDOM.TXMLDocument.Create;
OD.LoadFromXML(s);
MSXML: 4.524 ms
MD:=XMl.XMLDoc.TXMLDocument.Create(nil);
MD.LoadFromXML(s);
2. Memory (after loading 100 documents)
HCL: 177 Mb
OXML: 206 Mb.
MSXML: 253 Mb.
3. Serialization (DOM -> string )
HCL: 2.65 ms
OXML: 11.07 ms
MSXML: 7.18 ms
4. Simple XPath query: //results 10000 times (304 nodes selected)
HCL: 671 ms
(THtXMLNode).XPath('//results');
OXML: 58650 ms
(OXMLPDOM.TXMLDocument).Node^.SelectNodes('//results');
MSXML: 1295 ms
(DOMDocument as IDomNodeSelect).selectNodes('//results');
4. XPath query with attribute: //result[@value="69"] 1000 times
HCL: 390ms
OXML: 5803 ms
MSXML: 609 ms
OXML results are very strange. Considering tests on OXML page it should be significantly faster than MSXML, so maybe I've missed something.
http://www.enetpulse.com/documentation
As a test sample I used Golf.xml file (500Kb) from this page
http://www.enetpulse.com/documentation/
As a participants were choosen OXML http://www.kluug.net/oxml.php (it seems to be a fastest native XML implementation for Delphi)
and standard MSXML (Xml.XMLDoc).
It is not serious test, because results are vary widely from file to file (on some files MS was 9 times slower than HCL) but gives some notion.
Delphi XE2, Win32, Windows 7, Intel Core i5.
1. Reading (string -> DOM, creating and destroying )
HCL: 1.622 ms
THtXMLNode.Create(s);
OXML: 4.415 ms
OD:=OXMLPDOM.TXMLDocument.Create;
OD.LoadFromXML(s);
MSXML: 4.524 ms
MD:=XMl.XMLDoc.TXMLDocument.Create(nil);
MD.LoadFromXML(s);
2. Memory (after loading 100 documents)
HCL: 177 Mb
OXML: 206 Mb.
MSXML: 253 Mb.
3. Serialization (DOM -> string )
HCL: 2.65 ms
OXML: 11.07 ms
MSXML: 7.18 ms
4. Simple XPath query: //results 10000 times (304 nodes selected)
HCL: 671 ms
(THtXMLNode).XPath('//results');
OXML: 58650 ms
(OXMLPDOM.TXMLDocument).Node^.SelectNodes('//results');
MSXML: 1295 ms
(DOMDocument as IDomNodeSelect).selectNodes('//results');
4. XPath query with attribute: //result[@value="69"] 1000 times
HCL: 390ms
OXML: 5803 ms
MSXML: 609 ms
OXML results are very strange. Considering tests on OXML page it should be significantly faster than MSXML, so maybe I've missed something.
http://www.enetpulse.com/documentation
Krasimir Ivanov
ReplyDeleteSame result:
HCL: 1528
OXML: 4306
XMLDoc := CreateXMLDoc;
XMLDoc.LoadFromXML(s);
XMLDoc:=nil;
For those kind of tests is interesting sorurce. Can you post this somewhere?
ReplyDeleteKrasimir Ivanov Source code is very simple (form with 3 buttons and memo)
ReplyDeleteunit Unit10;
interface
{$DEFINE HCL}
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
{$IFDEF HCL} htmlpars, htxml, {$ENDIF}
Xml.xmldom, Xml.XMLIntf, Xml.Win.msxmldom, Xml.XMLDoc, Xml.adomxmldom, msxml, oxmlpdom;
const
TestFile = 'h:\golf.xml';
type
TForm10 = class(TForm)
Memo1: TMemo;
ReadBtn: TButton;
WriteBtn: TButton;
XPathBtn: TButton;
XPath2Btn: TButton;
procedure ReadBtnClick(Sender: TObject);
procedure WriteBtnClick(Sender: TObject);
procedure XPathBtnClick(Sender: TObject);
procedure XPath2BtnClick(Sender: TObject);
public
{$IFDEF HCL}
HN: THtXMLNode;
{$ENDIF}
OD: oxmlpdom.TXMLDocument;
MD: Xml.XMLDoc.TXMLDocument;
XMLDoc: IXMLDocument;
Sel: IDOMNodeSelect;
function LoadFile: string;
end;
var
Form10: TForm10;
implementation
{$R *.dfm}
function TForm10.LoadFile: string;
var
L: TStringList;
begin
L := TStringList.Create;
try
L.LoadFromFile(TestFile);
Result := L.Text;
finally
L.Free
end;
end;
procedure TForm10.ReadBtnClick(Sender: TObject);
var
s: string;
i, T: integer;
begin
s := LoadFile;
Memo1.Lines.Add('Read');
{$IFDEF HCL}
T := GetTickCount;
for i := 1 to 100 do begin
HN := THtXMLNode.Create(s);
HN.Free;
end;
Memo1.Lines.Add('HCL: ' + inttostr(GetTickCount - T));
{$ENDIF}
T := GetTickCount;
for i := 1 to 100 do begin
XMLDoc := CreateXMLDoc;
XMLDoc.LoadFromXML(s);
XMLDoc := nil;
end;
Memo1.Lines.Add('OXML: ' + inttostr(GetTickCount - T));
T := GetTickCount;
for i := 1 to 100 do begin
MD := Xml.XMLDoc.TXMLDocument.Create(nil);
MD.LoadFromXML(s);
MD.Active := true;
MD.Free;
end;
Memo1.Lines.Add('MSXML: ' + inttostr(GetTickCount - T));
end;
procedure TForm10.WriteBtnClick(Sender: TObject);
var
s, s1: string;
i, T: integer;
begin
s := LoadFile;
Memo1.Lines.Add('Write');
{$IFDEF HCL}
HN := THtXMLNode.Create(s);
T := GetTickCount;
for i := 1 to 100 do begin
s1 := HN.Code;
end;
Memo1.Lines.Add('HCL: ' + inttostr(GetTickCount - T));
HN.Free;
{$ENDIF}
OD := oxmlpdom.TXMLDocument.Create;
OD.LoadFromXML(s);
T := GetTickCount;
for i := 1 to 100 do begin
s1 := OD.Xml;
end;
Memo1.Lines.Add('OXML: ' + inttostr(GetTickCount - T));
OD.Free;
MD := Xml.XMLDoc.TXMLDocument.Create(nil);
MD.LoadFromXML(s);
T := GetTickCount;
for i := 1 to 100 do begin
MD.SaveToXML(s1);
end;
Memo1.Lines.Add('MSXML: ' + inttostr(GetTickCount - T));
MD.Free;
end;
procedure TForm10.XPathBtnClick(Sender: TObject);
var
s, s1: string;
i, T: integer;
begin
s := LoadFile;
Memo1.Lines.Add('XPath: //results');
{$IFDEF HCL}
HN := THtXMLNode.Create(s);
T := GetTickCount;
for i := 1 to 10000 do begin
HN.XPath('//results');
end;
Memo1.Lines.Add('HCL: time ' + inttostr(GetTickCount - T));
Memo1.Lines.Add('Count: ' + inttostr(HN.XPath('//results').GetCount));
HN.Free;
{$ENDIF}
OD := oxmlpdom.TXMLDocument.Create;
OD.LoadFromXML(s);
T := GetTickCount;
ReplyDeletefor i := 1 to 1000 do begin
OD.Node^.SelectNodes('//results');
end;
Memo1.Lines.Add('OXML: time ' + inttostr(GetTickCount - T));
Memo1.Lines.Add('Count: ' +
inttostr(OD.Node^.SelectNodes('//results').Count));
OD.Free;
MD := Xml.XMLDoc.TXMLDocument.Create(nil);
MD.LoadFromXML(s);
T := GetTickCount;
for i := 1 to 10000 do begin
Sel := MD.DOMDocument as IDOMNodeSelect;
Sel.SelectNodes('//results');
end;
Memo1.Lines.Add('MSXML: time ' + inttostr(GetTickCount - T));
Memo1.Lines.Add('Count: ' + inttostr(Sel.SelectNodes('//results').length));
MD.Free;
end;
procedure TForm10.XPath2BtnClick(Sender: TObject);
var
s, s1: string;
i, T: integer;
begin
s := LoadFile;
Memo1.Lines.Add('XPath: //result[@value="69"]');
{$IFDEF HCL}
HN := THtXMLNode.Create(s);
T := GetTickCount;
for i := 1 to 1000 do begin
HN.XPath('//result[@value="69"]');
end;
Memo1.Lines.Add('HCL: time ' + inttostr(GetTickCount - T));
Memo1.Lines.Add('Count: ' + inttostr(HN.XPath('//result[@value="69"]')
.GetCount));
HN.Free;
{$ENDIF}
OD := oxmlpdom.TXMLDocument.Create;
OD.LoadFromXML(s);
T := GetTickCount;
for i := 1 to 1000 do begin
OD.Node^.SelectNodes('//result[@value="69"]');
end;
Memo1.Lines.Add('OXML: time ' + inttostr(GetTickCount - T));
Memo1.Lines.Add('Count: ' +
inttostr(OD.Node^.SelectNodes('//result[@value="69"]').Count));
OD.Free;
MD := Xml.XMLDoc.TXMLDocument.Create(nil);
MD.LoadFromXML(s);
T := GetTickCount;
for i := 1 to 1000 do begin
Sel := MD.DOMDocument as IDOMNodeSelect;
Sel.SelectNodes('//result[@value="69"]');
end;
Memo1.Lines.Add('MSXML: time ' + inttostr(GetTickCount - T));
Memo1.Lines.Add('Count: ' +
inttostr(Sel.SelectNodes('//result[@value="69"]').length));
MD.Free;
end;
end.