User bio

The first two systems I worked with using InterSystems technology were a PDP-11 running M11+ and a VAX 11/750 running M/VX. Too many years ago to count! 😊
Since then I've used most, if not all, InterSystems products up to IRIS and HealthShare today.
I'm Italian living in Switzerland and I work as Senior Consultant at GAIVOTA consultin SA, we provide professional services for InterSystems and other technologies.
Curiosity: apart from DC, I don't have ANY social account! 😁

Show all
Member since Aug 4, 2017
Replies:

IMHO the best approach is to take advantage of the  object-oriented development environment that IRIS provide and have the common functions/methods in a single (or multiple) classes, possible abstract classes, and inherit them in the "main" class.

Class Community.perf.ClassMain Extends Community.perf.ClassAbs
{

ClassMethod Compare(NumCalls As %Integer)
{
	Set Start=$zh
	Do ..ClassCalls(NumCalls)
	Set End=$zh
	Write "Class calls: ",End-Start,!
}

ClassMethod ClassCalls(NumCalls As %Integer)
{
	For i=1:1:NumCalls {
		Set x=..Compute(NumCalls)
	}
}

}
Class Community.perf.ClassAbs [ Abstract ]
{

ClassMethod Compute(Num As %Integer)
{
	;Quit Num
	Set ret=Num
	Quit ret
}

}

How about performance?

EPTEST>do ##class(Community.perf.ClassMain).Compare(100000000)
Class calls: 31.675438

In latest version of IRIS (and Cachè?) inherited members method code is no longer duplicated, so there is no difference then using separate classes but I think this approach is more modern, elegant and, depending on situations, MUCH more flexible,

To mesure the difference I've a differente approach then Robert and concentrate on same/different class calls without any additional overhead.
Please note that is my no means a demonstration of best/worst approach, IMHO there is a better solution, see my next post.

I've created two classes and simulated a big number of calls of a class method within the same class and same code calling a class method in a different class.

Class Community.perf.Class1
{

ClassMethod Compare(NumCalls As %Integer)
{
	Set SingleStart=$zh
	Do ..SingleClassCalls(NumCalls)
	Set SingleEnd=$zh
	Set MultiStart=$zh
	Do ..MultiClassCalls(NumCalls)
	Set MultiEnd=$zh
	Set Difference=(MultiEnd-MultiStart)-(SingleEnd-SingleStart)
	Set Percent=1-((SingleEnd-SingleStart)/(MultiEnd-MultiStart))*100
	Write "Same class calls: ",SingleEnd-SingleStart,!
	Write "Diff class calls: ",MultiEnd-MultiStart,!
	Write "Difference: ",Difference," ",Percent,"%",!
}

ClassMethod SingleClassCalls(NumCalls As %Integer)
{
	For i=1:1:NumCalls {
		Set x=..Compute(NumCalls)
	}
}

ClassMethod MultiClassCalls(NumCalls As %Integer)
{
	For i=1:1:NumCalls {
		Set x=##class(Community.perf.Class2).Compute(NumCalls)
	}
}

ClassMethod Compute(Num As %Integer)
{
	;Quit Num
	Set ret=Num
	Quit ret
}

}
Class Community.perf.Class2
{

ClassMethod Compute(Num As %Integer)
{
	;Quit Num
	Set ret=Num
	Quit ret
}

}

Calling the Compare() method with 100M iterations the result is:

EPTEST>do ##class(Community.perf.Class1).Compare(100000000)
Same class calls: 20.992929
Diff class calls: 31.460201
Difference: 10.467272 33.27147210534351%

Please note that changing the Compute() method in both classes to:

ClassMethod Compute(Num As %Integer)
{
    Quit Num
}

Makes a BIG difference:

EPTEST>do ##class(Community.perf.Class1).Compare(100000000)
Same class calls: 4.606181
Diff class calls: 5.52639
Difference: .920209 16.6511773508565266%

Using the first method code it adds the handling of the stack, therefore it takes longer and, for 100M calls, the difference is noticeable.
I think the first with "some" stack handling is a more realistic use case.

In conclusion, there is a difference and is measurable. Is it noticeable? Not much, IMHO in a computation that probably takes many minutes duplicating codes is not worth the gain.

There is however a better approach without duplicating the code, see my next post.

Ciao Robert,

I'm not sure your test address the original question, that is:

"whenever you call code outside of the routine as opposed to calling code in the same routine, some execution speed is lost"

In your test1 you do:

[call class method] -> [call class method in other class] -> [call a function in same class]

In your test2 you do:

[call class method] -> [call a function in same class]

This way you are not comparing "call code outside of the routine as opposed to calling code in the same routine", you are ADDING an additional call/level.

In addition, to measure the time penalty for calling inside/outside "routine" (or class), adding 100M global access does not help in getting a reliable measure because too many factors may change the time measured between different runs.
Finally a doubt, are we sure that calling a function and calling a class method is a fair comparison? May be or may be not, I don't know.

Certifications & Credly badges:
Global Masters badges:
Followers:
Following:
Enrico has not followed anybody yet.