Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ASP Speed Tricks Article 1

Status
Not open for further replies.
I just wanted to announce that I've posted an article I
wrote on techniques for increasing the speed of database
generated ASP pages. If you're interested, please check
it out at:


The article describes nearly a dozen practical methods,
and includes source code and test results. Comments
are welcome.

Thanks,
Shailesh
 
No, I think I get the point. Basically we're all talking about the same thing.

Theoretically, yes, concatenation and then writing to a buffer might be slower, but at the same time doing multiple writes to a buffer would have the same amount of overhead unless we assumed that the buffer was pre-allocating blocks of memory.

If the buffer was pre-allocating chunks of memory than it should be much faster to make multiple write calls than to concatenate and then make a single write.

But the problem here is we are talking about two seperate processes. That process communications isn't factored in in the above theory.
Code:
Without communications:
Concatenation: print x + y + z
allocate space for x, assign x
reallocate the space, assign y to the end
reallocate the space, assign z to the end
assign incoming value to buffer (already allocated)
clear buffer

prints: print x; print y; print z
assign x to buffer
assign y to buffer
assign z to buffer
clear buffer

Now with communications:
Concatenation: print x + y + z
allocate space for x, assign x
reallocate the space, assign y to the end
reallocate the space, assign z to the end
send new string to outside object
receive value, assign incoming value to buffer (already allocated)
clear buffer

prints: print x; print y; print z
send x to outside object
receive x, assign x to buffer
send y to outside object
receive y, assign y to buffer
send z to outside object
receive z, assign z to buffer
clear buffer

So without an outside object we have:
(number of strings) * (MAllocTime + AppendTime) + (AppendTime * NumberOfWrites)

The decision for this one is fairly obvious. In order to limit this the most we can we need to cut down on the number of strings used with each call (concatenation) and send them seperately (multiple writes). The decision point is:
(MAllocTime + AppendTime) vs AppendTime
with the first argument obviously being larger than the second in every scenario.

But with an outside object holding the buffer:
(number of strings) * (MAllocTime + AppendTime) + NumberOfWrites * (AppendTime + CommTime)

We now have a third variable. For the moment we will assume that the Append time is the same for both Strings and the Buffer in our outside object.
The decision point here is less obvious because we have more factors. The decision point is now:
(MAllocTime + AppendTime) vs (AppendTime + CommTime)
which can be factored to:
MAllocTime vs CommTime

Now we actually need to know implementation specifics in order to make a decision. If the memory allocation time is better than the communications time, then we will want more string concatenation and less Writes. If the Communications time is less than the memory allocation time, then we will want to concatenate less and use more writes.


So the real question is which is faster, memory allocation or communications?

Unfortunately I don't see an easy way to test this off the top of my head, at least not for VBScript.

[sub]01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111[/sub]
minilogo.gif alt=tiernok.com
The never-completed website
 
As far as concatenation vs multiple writes is concerned, there is an actual issue here that should be addressed.

Your testing above did not actually test accumulative concatenation, only multiple concatenations.

Accumulative concatenation is:
Code:
aStr = aStr & aValue

Multiple Concatenations, on the other hand:
Code:
aStr = aValue & bValue & cValue

A better test for this would be to setup an array and then loop through concatenating the values into one string, then output that array, like so
Code:
<%
Option Explicit

Dim arrValues(20)
Dim ctr

'simulate 20 values, ignore index 0
For ctr = 1 to 20
   arrValues(ctr) = &quot;a string &quot; & ctr
Next

'output some html for cleanliness
Response.Write &quot;<html><body><div style=&quot;&quot;display:hidden&quot;&quot;>&quot;


'Now run tests
Dim testCount, loopCount, arrCount, outputStr
Dim clockTimesA(10), clockTimesB(10)
Dim avgA, avgB

'Do ten runs of concatenation testing
For testCount = 1 to 10
	'start the clock
	StartClock()
	'start the test
	For loopCount = 1 to 5000
		'loop through the array
		For arrCount = 1 to UBound(arrValues)
			outputStr = outputStr & arrValues(arrCount)
		Next

		'output the string
		Response.Write outputStr

		'stop the clock
		StopClock()

		'Assign the clock time to our array
		clockTimesA(testCount) = GetElapsedTime()

		'clear the string
		outputStr = Empty

		'Reset the clock
		ResetClock()
	Next
Next


'Do ten runs of straight writes
For testCount = 1 to 10
	'start the clock
	StartClock()
	'start the test
	For loopCount = 1 to 5000
		'loop through the array
		For arrCount = 1 to UBound(arrValues)
			Response.Write arrValues(arrCount)
		Next

		'stop the clock
		StopClock()

		'Assign the clock time to our array
		clockTimesB(testCount) = GetElapsedTime()

		'Reset the clock
		ResetClock()
	Next
Next

'end the hidden div
Response.Write &quot;</div>&quot;

'calculate the averages, start the display table
Response.Write &quot;<table><tr><th>Run</th><th>Test A</th><th>Test B</th></tr>&quot;

For testCount = 1 to 10
	avgA = avgA + clockTimesA(testCount)
	avgB = avgB + clockTimesB(testCount)
	Response.Write &quot;<tr><td>&quot; & testCount & &quot;</td><td>&quot; & clockTimesA(testCount) & &quot;</td><td>&quot; & clockTimesB(testCount) & &quot;</td></tr>&quot;
Next

avgA = avgA/10
avgB = avgB/10

Response.Write &quot;<tr><td>Final Average:</td><td>&quot; & avgA & &quot;</td><td>&quot; & avgB & &quot;</td></tr></table></body></html>&quot;&quot;
%>

This truly pits accumulative concatenation against multiple writes. It compares 5000 concatenations against 5000 sets of writes, and also runs each test 10 times for even more accurate results. The outside 10x loop is probably not necessary, but makes me feel better :)

-Tarwn

[sub]01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111[/sub]
minilogo.gif alt=tiernok.com
The never-completed website
 
Sorry, wrote that on the fly, here is the corrected version that should actually work:
Code:
<%
Option Explicit

Dim arrValues(100)
Dim ctr

'simulate 100 values, ignore index 0
For ctr = 1 to 100
   arrValues(ctr) = &quot;a string &quot; & ctr
Next

'output some html for cleanliness
Response.Write &quot;<html><body><div style=&quot;&quot;display:hidden&quot;&quot;>&quot;


'Now run tests
Dim testCount, loopCount, arrCount, outputStr
Dim clockTimesA(10), clockTimesB(10)
Dim avgA, avgB

'Do ten runs of concatenation testing
For testCount = 1 to 10
	'start the clock
	StartClock()
	'start the test
	For loopCount = 1 to 5
		'loop through the array
		For arrCount = 1 to UBound(arrValues)
			outputStr = outputStr & arrValues(arrCount)
		Next

	Next

	'output the string
	Response.Write outputStr


	'clear the string
	outputStr = Empty

	'stop the clock
	StopClock()

	'Assign the clock time to our array
	clockTimesA(testCount) = cDbl(GetElapsedTime())


	'Reset the clock
	ResetClock()

Next


'Do ten runs of straight writes
For testCount = 1 to 10
	'start the clock
	StartClock()
	'start the test
	For loopCount = 1 to 5
		'loop through the array
		For arrCount = 1 to UBound(arrValues)
			Response.Write arrValues(arrCount)
		Next
	Next
	'stop the clock
	StopClock()

	'Assign the clock time to our array
	clockTimesB(testCount) = cDbl(GetElapsedTime())

	'Reset the clock
	ResetClock()
Next

'end the hidden div
Response.Write &quot;</div>&quot;

'calculate the averages, start the display table
Response.Write &quot;<table><tr><th>Run</th><th>Test A</th><th>Test B</th></tr>&quot;

For testCount = 1 to 10
	avgA = avgA + clockTimesA(testCount)
	avgB = avgB + clockTimesB(testCount)
	Response.Write &quot;<tr><td>&quot; & testCount & &quot;</td><td>&quot; & clockTimesA(testCount) & &quot;</td><td>&quot; & clockTimesB(testCount) & &quot;</td></tr>&quot;
Next

avgA = avgA/10
avgB = avgB/10

Response.Write &quot;<tr><td>Final Average:</td><td>&quot; & avgA & &quot;</td><td>&quot; & avgB & &quot;</td></tr></table></body></html>&quot;
%>

[sub]01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111[/sub]
minilogo.gif alt=tiernok.com
The never-completed website
 
Ok, One last correction:
display:none :p

I just ran the script, I don't suggest running it with a loopCount higher than about 200...this is fairly intensive when you put it higher.

Results: 10 runs, 20 loops:
Code:
Run	Accumulative	Writes 
1	5.578		0.016 
2	5.422		0.031 
3	5.547		0.016 
4	5.5		  0.016 
5	5.547		0.015 
6	5.531		0.016 
7	5.453		0.015 
8	5.578		0.016 
9	5.516		0.031 
10	5.484		0.016 
Final:5.516		0.019

The numbers are unchanged, though I did fiddle with the layout some.

[sub]01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111[/sub]
minilogo.gif alt=tiernok.com
The never-completed website
 
very interesting article - nice layout & helpful content.

From reading the above discussion can I conclude that you folks are still unsure whether using string concatenation vs multiple Response.Write commands is faster? That it will depend on the individual setup .. server/processor/scripting language/etc?






Posting code? Wrap it with code tags: [ignore]
Code:
[/ignore][code]CodeHere
[ignore][/code][/ignore].
 
My assumptions have been that the communication of the string to the response object is optimized, and that response buffering is enabled. This is true under IIS5/ASP3.0/VBScript. Under this assumption, any kind of concatenation is going to be slower than just writing it out using response.write. Accumulative concatenation will be awful, and non-accumulative concatenation will just be a minor performance drag.

If the assumptions change, which they may do under Python, PerlScript, or JavaScript, then the speed of the response.write has to be factored in. But it only really matters for non-accumulative concatenation, as accumulative concatenation will be incredibly slow for anything but very small data sets, as your last test shows. Caveat: some scripting engines may do concatenation differently than VBScript.

So I agree with all your results above. The question for people not using VBScript is when does the cost of doing multiple response.write outweigh the cost of doing a few concatenations? You're describing the same question, but calling it the question of memory allocation/copying versus communication. I think it can only be found out by doing some simple testing.

Thanks for all your discussion.

Shailesh
 
you might want to have a look at this related article, which compares the speed of using rs.getString() vs rs.getRows() vs recordset iteration.


Also seemed good


Posting code? Wrap it with code tags: [ignore]
Code:
[/ignore][code]CodeHere
[ignore][/code][/ignore].
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top