Page 1 of 1

Dynamic dbchart creation slow

Posted: Thu Aug 02, 2012 1:00 am
by 10048147
I have an application that creates the required dbcharts on startup. However, this dynamic chart creation is very slow, and slows down expotentially with the number of charts. After doing some profiling, I discovered that the 'findnameloop' routine is called excessively, in order, I believe to create unique 'names' for each of the created charts.

Is there a way around this? (having TeeChart calling this routine when dynamically creating dbcharts).

Thanks,

Dennis

Re: Dynamic dbchart creation slow

Posted: Thu Aug 02, 2012 3:16 pm
by yeray
Hi Dennis,

I don't think it's creating the charts, but maybe using CreateNewSeries, CreateNewTeeFunction, CloneChartTool,...
Could you please arrange a simple example project we can run as-is to reproduce the exact situation here so we can try to suggest you another way to do the same?

Re: Dynamic dbchart creation slow

Posted: Thu Aug 02, 2012 9:01 pm
by 10048147
Thanks so much Yeray, for your prompt reply. As it is a major project, and for expediency sake, is it OK that I include the procedure from my Delphi 2007 project that generates the charts - see below. (if this is too onnerous for you, please let me know. I will especially create a stand-alone application for you. I am hoping you have come across this before, and will have a 'quick' solution).

Also, FYI the FindNameLoop procedure appears to be in the GetUniqueName procedure in the TeeProcs Unit. It is being 'hit' 2018 times and is taking approx 45 secs out of the 55 secs to load the entire application.

Again, Thanks so much.

Here is the procedure:

procedure TForm24.createcharts(noofcharts: integer);
var
i:integer;
mytool, mytool1, mytool2:tdatatabletool;

begin
freecharts(chartarray);
freecharts(chartarray1);
freecharts(chartarray2);

ts.free;
ts:=nil;

ts1.Free;
ts1:=nil;

ts2.Free;
ts2:=nil;


setlength(chartarray,noofcharts);
setlength(chartarray1,noofcharts);
setlength(chartarray2, noofcharts);
setlength(tabsheetarray,noofcharts);
setlength(tabsheetarray1,noofcharts);
setlength(tabsheetarray2, noofcharts);
setlength(myseries,noofcharts);
setlength(myseries1,noofcharts);
setlength(myseries2, noofcharts);
setlength(mylineseries, noofcharts);
setlength (mylineseries1, noofcharts);
setlength (mylineseries2, noofcharts);
setlength(mybuttons,3*noofcharts);

adoquery2.Recordset.MoveFirst;

ts:=ttabsheet.Create(self);
ts.PageControl:=pagecontrol1;
ts.Caption:='Machine Downtime Hrs';
pc:=tpagecontrol.Create(self);
pc.Parent:=ts;
pc.Align:=alclient;

ts2:=ttabsheet.Create(self);
ts2.PageControl:=pagecontrol1;
ts2.Caption:='Machine Downtime %';
pc2:=tpagecontrol.Create(self);
pc2.Parent:=ts2;
pc2.Align:=alclient;


ts1:=ttabsheet.Create(self);
ts1.PageControl:=pagecontrol1;
ts1.Caption:='Machine Incidents';
pc1:=tpagecontrol.Create(self);
pc1.Parent:=ts1;
pc1.Align:=alclient;

for I := 1 to noofcharts do
begin
if screen.Forms[0].Name = 'splashscreen' then
begin
splashscreen.ProgressBar1.StepIt;
splashscreen.Label2.Caption:='creating chart group ' + inttostr(i);
splashscreen.Update;
end;
tabsheetarray:=ttabsheet.Create(self);
tabsheetarray.PageControl :=pc;
tabsheetarray.Caption:=adoquery2.Recordset.Fields[0].Value;
tabsheetarray.OnShow:=tabshow;
mybuttons:=tbutton.Create(self);
mybuttons.Parent:=tabsheetarray;
mybuttons.Anchors:=[aktop,akright];
mybuttons.Top:=10;
mybuttons.Left:=tabsheetarray[i].Width-150;
mybuttons[i].Caption:='Print This Chart';
mybuttons[i].Width:=100;
mybuttons[i].OnClick:=buttonclicked;

tabsheetarray2[i]:=ttabsheet.Create(self);
tabsheetarray2[i].PageControl :=pc2;
tabsheetarray2[i].Caption:=adoquery2.Recordset.Fields[0].Value;
tabsheetarray2[i].OnShow:=tabshow;
mybuttons[i+noofcharts]:=tbutton.Create(self);
mybuttons[i+noofcharts].Parent:=tabsheetarray2[i];
mybuttons[i+noofcharts].Anchors:=[aktop,akright];
mybuttons[i+noofcharts].Top:=10;
mybuttons[i+noofcharts].Left:=tabsheetarray2[i].Width-150;
mybuttons[i+noofcharts].Caption:='Print This Chart';
mybuttons[i+noofcharts].Width:=100;
mybuttons[i+noofcharts].OnClick:=buttonclicked;

tabsheetarray1[i]:=ttabsheet.Create(self);
tabsheetarray1[i].PageControl :=pc1;
tabsheetarray1[i].Caption:=adoquery2.Recordset.Fields[0].Value;
tabsheetarray1[i].OnShow:=tabshow;
mybuttons[(i+(noofcharts*2))]:=tbutton.Create(self);
mybuttons[(i+(noofcharts*2))].parent:=tabsheetarray1[i];
mybuttons[(i+(noofcharts*2))].Anchors:=[aktop,akright];
mybuttons[(i+(noofcharts*2))].Top:=10;
mybuttons[(i+(noofcharts*2))].Left:=tabsheetarray1[i].Width-150;
mybuttons[(i+(noofcharts*2))].Caption:='Print This Chart';
mybuttons[(i+(noofcharts*2))].Width:=100;
mybuttons[(i+(noofcharts*2))].OnClick:=buttonclicked;

chartarray[i]:=tdbchart.Create(self);
with chartarray[i] do
begin
Title.Text.Text:=adoquery2.Recordset.Fields[0].Value + ' - ' + adoquery2.Recordset.Fields[1].Value;;
Title.Font.Size:=11;
Title.Font.Color:=clblack;
color:=clwhite;
backwall.Color:=clbtnface;
backwall.Transparent:=false;
view3d:=false;
legend.Visible:=false;
//legend.CheckBoxes:=true;
leftaxis.LabelsSize:=30;
leftaxis.Title.Caption:='Downtime Hrs';
bottomaxis.Increment:=datetimestep[dtonemonth];
bottomaxis.DateTimeFormat:='mmm-yy';
bottomaxis.Grid.Style:=psclear;
bottomaxis.MinorTickCount:=1;
bottomaxis.MinorTickLength:=10;
bottomaxis.Title.caption:='Month-Year';
bottomaxis.LabelsSize:=50;
marginbottom:=10;
onclickseries:=chartclickseries;
borderstyle:=bsnone;
bevelinner:=bvnone;
bevelouter:=bvnone;
Parent:=tabsheetarray[i];
align:=alclient;
tools.Add(tdatatabletool);
zoom.allow:=false;
end;

mytool:=chartarray[i].Tools.Items[0] as tdatatabletool;
mytool.Legend.OtherSide:=true;
mylineseries[i]:=tlineseries.Create(self);
mylineseries[i].ParentChart:=chartarray[i];
mylineseries[i].DataSource:=adoquery1;
mylineseries[i].YValues.ValueSource:='#sum#sumdowntimehours';
mylineseries[i].XLabelsSource:='yearmonth';
mylineseries[i].Title:='TOTAL';
mylineseries[i].Pointer.Visible:=true;
mylineseries[i].LinePen.Width:=2;
mylineseries[i].Active:=true;
mycrosstabsource:=tdbcrosstabsource.Create(self);
myseries[i]:=tbarseries.Create(self);
myseries[i].Marks.Visible:=false;
myseries[i].ParentChart:=chartarray[i];
//myseries[i].XValues.DateTime:=true;
myseries[i].Active:=true;
myseries[i].MultiBar:=mbstacked;
mycrosstabsource.Series:=myseries[i];
mycrosstabsource.LabelField:='yearmonth';
mycrosstabsource.GroupField:='machinefaultdesc';
mycrosstabsource.ValueField:='sumdowntimehours';
mycrosstabsource.Formula:=gfsum;
mycrosstabsource.DataSet:=adoquery1;
mycrosstabsource.Active:=true;

chartarray2[i]:=tdbchart.Create(self);
with chartarray2[i] do
begin
Title.Text.Text:=adoquery2.Recordset.Fields[0].Value + ' - ' + adoquery2.Recordset.Fields[1].Value;;
Title.Font.Size:=11;
Title.Font.Color:=clblack;
color:=clwhite;
backwall.Color:=clbtnface;
backwall.Transparent:=false;
view3d:=false;
legend.Visible:=false;
//legend.CheckBoxes:=true;
leftaxis.LabelsSize:=30;
leftaxis.Title.Caption:='Downtime %';
bottomaxis.Increment:=datetimestep[dtonemonth];
bottomaxis.DateTimeFormat:='mmm-yy';
bottomaxis.Grid.Style:=psclear;
bottomaxis.MinorTickCount:=1;
bottomaxis.MinorTickLength:=10;
bottomaxis.Title.caption:='Month-Year';
bottomaxis.LabelsSize:=50;
marginbottom:=10;
onclickseries:=chartclickseries;
borderstyle:=bsnone;
bevelinner:=bvnone;
bevelouter:=bvnone;
Parent:=tabsheetarray2[i];
align:=alclient;
tools.Add(tdatatabletool);
zoom.Allow:=false;
end;

mytool2:=chartarray2[i].Tools.Items[0] as tdatatabletool;
mytool2.Legend.OtherSide:=true;
mylineseries2[i]:=tlineseries.Create(self);
mylineseries2[i].ParentChart:=chartarray2[i];
mylineseries2[i].DataSource:=adoquery8;
mylineseries2[i].YValues.ValueSource:='#sum#pcdwntimehrs';
mylineseries2[i].XLabelsSource:='ym';
mylineseries2[i].Title:='TOTAL';
mylineseries2[i].Pointer.Visible:=true;
mylineseries2[i].LinePen.Width:=2;
mylineseries2[i].Active:=true;
mycrosstabsource2:=tdbcrosstabsource.Create(self);
myseries2[i]:=tbarseries.Create(self);
myseries2[i].Marks.Visible:=false;
myseries2[i].ParentChart:=chartarray2[i];
//myseries2[i].XValues.DateTime:=true;
myseries2[i].Active:=true;
myseries2[i].MultiBar:=mbstacked;
mycrosstabsource2.Series:=myseries2[i];
mycrosstabsource2.LabelField:='ym';
mycrosstabsource2.GroupField:='machinefaultdesc';
mycrosstabsource2.ValueField:='pcdwntimehrs';
mycrosstabsource2.Formula:=gfsum;
mycrosstabsource2.DataSet:=adoquery8;
mycrosstabsource2.Active:=true;


chartarray1[i]:=tdbchart.Create(self);

with chartarray1[i] do
begin
Title.Text.Text:=adoquery2.Recordset.Fields[0].Value + ' - ' + adoquery2.Recordset.Fields[1].Value;;
Title.Font.Size:=11;
Title.Font.Color:=clblack;
color:=clwhite;
backwall.Color:=clbtnface;
backwall.Transparent:=false;
view3d:=false;
legend.Visible:=false;
//legend.CheckBoxes:=true;
leftaxis.LabelsSize:=30;
leftaxis.Title.Caption:='Number of Incidents';
bottomaxis.Increment:=datetimestep[dtonemonth];
bottomaxis.DateTimeFormat:='mmm-yy';
bottomaxis.Grid.Style:=psclear;
bottomaxis.MinorTickCount:=1;
bottomaxis.MinorTickLength:=10;
bottomaxis.Title.caption:='Month-Year';
bottomaxis.LabelsSize:=50;
marginbottom:=10;
onclickseries:=chartclickseries;
borderstyle:=bsnone;
bevelinner:=bvnone;
bevelouter:=bvnone;
Parent:=tabsheetarray1[i];
align:=alclient;
sendtoback;
tools.Add(tdatatabletool);
zoom.allow:=false;
end;

mytool1:=chartarray1[i].Tools.Items[0] as tdatatabletool;
mytool1.Legend.OtherSide:=true;
mylineseries1[i]:=tlineseries.Create(self);
mylineseries1[i].ParentChart:=chartarray1[i];
mylineseries1[i].DataSource:=adoquery1;
mylineseries1[i].YValues.ValueSource:='#sum#countdowntimehours';
mylineseries1[i].XLabelsSource:='yearmonth';
mylineseries1[i].Title:='TOTAL';
mylineseries1[i].Pointer.Visible:=true;
mylineseries1[i].LinePen.Width:=2;
mylineseries1[i].Active:=true;
mycrosstabsource1:=tdbcrosstabsource.Create(self);
myseries1[i]:=tbarseries.Create(self);
myseries1[i].Marks.Visible:=false;
myseries1[i].ParentChart:=chartarray1[i];
myseries1[i].MultiBar:=mbstacked;
//myseries1[i].XValues.DateTime:=true;
myseries1[i].Active:=true;
mycrosstabsource1.Series:=myseries1[i];
mycrosstabsource1.LabelField:='yearmonth';
mycrosstabsource1.GroupField:='machinefaultdesc';
mycrosstabsource1.ValueField:='countdowntimehours';
mycrosstabsource1.Formula:=gfsum;
mycrosstabsource1.DataSet:=adoquery1;
mycrosstabsource1.Active:=true;
mybuttons[i].BringToFront;
mybuttons[i+noofcharts].BringToFront;
adoquery2.Recordset.MoveNext;
end;
if screen.Forms[0].Name = 'splashscreen' then
begin
splashscreen.Label2.Caption:='almost done!';
screen.Cursor:=crdefault;
splashscreen.visible:=false;
end;

end;

Re: Dynamic dbchart creation slow

Posted: Fri Aug 03, 2012 7:38 pm
by yeray
Hi Dennis,

Thanks for the code but I'm afraid it's not enough. There are too many undeclared arrays, data queries, etc
So I have to ask you if you can arrange a simple example project.

Re: Dynamic dbchart creation slow

Posted: Wed Aug 08, 2012 11:25 pm
by 10048147
Yeray:

After some 'light reading', I decided to dynamically create my dbcharts with no owners (ie dbchart.create(nil)) in Delphi. I then wrote code to destroy these components upon form.close. This speeded up the loading of the form from 50+ seconds to approx. 8 seconds. This is good enough!

It is curious, however, that the FindNameLoop procedure is still being 'hit' 2016 times (according to my profiler). I still am not able to determine what 'call' is doing this.

I thought I would post my 'solution' to put this topic to rest and perhaps help others who want to speed up form loading for forms with dynamically created dbcharts (and other components).

Thanks,

Cheers,

Dennis

Re: Dynamic dbchart creation slow

Posted: Thu Aug 09, 2012 2:52 pm
by yeray
Hi Dennis,

Thanks for sharing.
If you find a way to reproduce the problem in a simple example project we can run as-is here, we'll be glad to take a look at it.