calin radoni's humble web presence

homedocstoolboxabout

Speed considerations in using the CString class

Table of Contents

How it all start

One day I have written a class to load and process a somehow large (~400k) text file. The problem was the time required for the operation to complete, a little bit over 3 seconds. Unacceptable I said.

My first idea was to reduce the file size but it could not be done without a higher increase of code. That is why I have started to count the time required for some blocks of code to complete.
Fine tunning has begun...
...and, as a result, the time required to load and process that file is now under one second !

Counting the time required for various operations

The easiest way is to use the GetTickCount function:

DWORD startTime, endTime;
DWORD elapsedTime;

startTime = GetTickCount();

// ... the code for which we want to measure the time required to work must be here ...

endTime = GetTickCount();

elapsedTime = endTime - startTime;
							

Warning: About the code

The code presented above is written with the intention to be as clear as possible. Do not consider it as THE way, or my way, to write code.

Note: About the GetTickCount function

The GetTickCount function returns the elapsed time since the system was started. The value is in miliseconds. The resolution is limited to the resolution of the system timer.

Because the result is stored as DWORD the value will overflow after ~49.7 days.

Using this method I have put together some lines of code for an application to be used for time measurements.
First I have made a function that runs the tests. The function has been called 25 times. Each test was called 10 thousands times.


// somewhere in the program:
int i;

for(i=0; i<25; i++)
	RunTheTests();

// ...

// a simple test function
void Test1(void)
{
	int i;
	
	for(i=0; i<10000; i++){
		// ... the code for which we want to measure the time required to work must be here ...
	}
}

// this function computes the elapsed time and display the result
void ComputeAndDisplayElapsedTime(DWORD sTime, DWORD eTime)
{
	// the code has been omitted for simplicity
}

// the function that runs the tests
void RunTheTests(void)
{
	DWORD startTime, endTime;
	
	startTime = GetTickCount();
	Test1();
	endTime = GetTickCount();
	ComputeAndDisplayElapsedTime(startTime, endTime);
	
	startTime = GetTickCount();
	Test2();
	endTime = GetTickCount();
	ComputeAndDisplayElapsedTime(startTime, endTime);
	
	startTime = GetTickCount();
	Test3();
	endTime = GetTickCount();
	ComputeAndDisplayElapsedTime(startTime, endTime);

	// ... and so on ...
}
							

Note

The actual code used was a little more complicated then the one presented above. The purpose of the previous code is to show you the principles that I have used.

In the next three paragraphs I will present you some of the results related to the usage of the CString class.

Test no.1

Tested code A:

void TestA(void)
{
	CString s1, s2, s3;
	int i;

	for(i=0; i<10000; i++){
		s3 = _T("alfa");				
		s1 = s3 + _T("beta");
		s2 = s3 + _T("gamma");
	}
}
							
Tested code B:
void TestB(void)
{
	CString s1, s2;
	int i;

	for(i=0; i<10000; i++){
		s1  = _T("alfa");
		s2  = s1;
		s1 += _T("beta");
		s2 += _T("gamma");
	}
}
							

Result: code A is 170 percent slower compared with code B.

Test no.2

Tested code A:

void TestA(void)
{
	CString str;
	int i;

	for(i=0; i<10000; i++){
		str = _T("123456789abcd");
		str = str.Mid(9);
	}
}
							
Tested code B:
void TestB(void)
{
	CString str;
	LPCSTR alfa;
	int i;

	for(i=0; i<10000; i++){
		str  = _T("123456789abcd");
		alfa = str;
		str  = &alfa[9];
	}
}
							

Result: code A is 349 percent slower compared with code B.

Test no.3

Tested code A:

void TestA(void)
{
	CString str, s1, s2;
	int i;

	for(i=0; i<10000; i++){
		str = _T("1234-1234-1234");
		s1  = str.Mid(4, 1);
		s2  = str.Mid(9, 1);
		if(s1==s2){
			i = i;
		}
	}
}
							
Tested code B:
void TestB(void)
{
	CString str, s1, s2;
	int i;

	for(i=0; i<10000; i++){
		str = _T("1234-1234-1234");
		s1  = str.Mid(4, 1);
		s2  = str.Mid(9, 1);
		if(s1.Compare(s2)==0){
			i = i;
		}
	}
}
							
Tested code C:
void TestC(void)
{
	CString str, s1, s2;
	int i;

	for(i=0; i<10000; i++){
		str = _T("1234-1234-1234");
		s1  = str.Mid(4, 1);
		s2  = str.Mid(9, 1);
		if(s1.CompareNoCase(s2)==0){
			i = i;
		}
	}
}
							
Tested code D:
void TestD(void)
{
	CString str;
	LPCSTR alfa;
	int i;

	for(i=0; i<10000; i++){
		str  = _T("1234-1234-1234");
		alfa = str;
		if(alfa[4]==alfa[9]){
			i = i;
		}
	}
}
							

Results:
Code A is 964 percent slower compared with code D.
Code B is 973 percent slower compared with code D.
Code C is 968 percent slower compared with code D.

Conclusion

By comparing the result it is easy to see how you can get a speed boost by using a method instead another.
This document is intended to open your eyes to this phase of programming applications: increasing the quality of your final work by increasing the speed of code without loosing functionality.

History

Copyright and License

This document is copyrighted (c) 2006 by Calin Radoni. Permission is granted to copy and/or distribute this document.

Disclaimer

No liability for the contents of this document can be accepted. Use the concepts, examples and information at your own risk. There may be errors and inaccuracies that could be damaging to your system. Proceed with caution, the author do not take any responsibility.

All copyrights are held by their respective owners, unless specifically noted otherwise. Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark. Naming of particular products or brands should not be seen as endorsements.


Copyright © 2005 - 2009 Calin Radoni Hosted on http://www.oocities.org/calinradoni Last page modification is 18 January 2006