Rss Feed
Tweeter button
Facebook button
Technorati button
Reddit button
Myspace button
Linkedin button
Webonews button
Delicious button
Digg button
Stumbleupon button
Newsvine button
Software Verification logo

What is the difference between a page and a paragraph?

March 8th, 2010

In the real world we all know that pages contain paragraphs and that paragraphs are full of sentences created from words.

In the world of Microsoft Windows Operating Systems it is somewhat different – paragraphs contain pages!

In this article I’m to going to explain what a page is and what a paragraph is and how they relate to each other and why this information can be useful helping to identify and resolve certain memory related bugs.

Virtual Memory Pages
A virtual memory page is the smallest unit of memory that can be mapped by the CPU. In the case of 32 bit x86 processors such as the Intel Pentium and AMD Athlon, a page is 4Kb. When you make a call to VirtualProtect() or VirtualQuery() you will be setting or querying the memory protection for sizes that are multiples of a page.

The size of a page may vary from CPU type to CPU type. For example a 64 bit x86 CPU will have a page size of 8Kb.

You can determine the size of a page by calling GetSystemInfo() and reading the SYSTEM_INFO.dwPageSize value.

Virtual Memory Paragraphs
A virtual memory paragraph is the minimum amount of memory that can be commited/reserved using the VirtualAlloc() call. On 32 bit x86 CPUs this value is 64Kb (0×00010000). If you have ever used the debugger and looked at the load addresses of DLLs in the Modules list you may have noticed that DLLs always load on 64Kb boundaries. This is the reason – the area a DLL is loaded into is initialised by a call to VirtualAlloc to reserve the memory prior to the DLL being loaded.

Loaded Modules

You can determine the size of a paragraph by calling GetSystemInfo() and reading the SYSTEM_INFO.dwAllocationGranularity value.

Given these values, you can see that (on 32 bit 86 systems) a virtual memory paragraph is composed of 16 virtual memory pages.

How can I use this information?
If you are using VirtualAlloc() it is important to know the granularity at which the allocations will be returned. This is the size of a paragraph. This information is fundamental in deciding how you would implement a custom heap. You know there are fixed boundaries at which your data can exist. You can enumerate the list of possible paragraph locations very quickly (there are 32,768 possible locations in a 2GB space, as opposed to 2 billion locations if the paragraph could start anywhere).

Custom heaps
If you are writing a custom heap, a key indicator to keep track of is memory fragmentation and memory utilisation. Knowing your paragraph and page sizes you can inspect how each page and each paragraph of memory are used by the application and the custom heap to determine if there is wastage, what wastage there is and what form the wastage takes. This information could lead you to modify your heap algorithm to use pages differently to reduce fragmentation. See Delete memory 5 times faster for one simple technique, using HeapAlloc, the same principles apply here.

Loading large data files
Another use for this information is finding out why a certain large file will not load into memory despite Task Manager saying that you have 2GB of free memory. It is not uncommon to find a forum posting somewhere from someone that has a large image file (a satellite phote, MRI scan, etc) that is about 1GB in size. They wish to load it into memory, do in-memory processing on it, save the results, discard the memory then repeat the process, often for numerous images.
Typically on the third attempt to load a large file, the file will not load and the forum poster is left very confused.

The typical implementation is to allocate space for the large file using a call such as malloc() or operator new(). Both of which use the C runtime heap to allocate the memory.

The principle seems fine, but the problem is caused by memory fragmentation which results in a less accessible, totally usable, free space because the remaining free space blocks are separated into a many smaller regions, most of which are smaller than any forthcoming large allocation required by the application. Without the information about where pages and paragraphs are situated, how big they are and what their status is, identifying the cause of this failure could be very time consuming. Once you know the cause, you can think about allocating and managing your memory differently and prevent the bug from happening in the first place.

For situations like these, using HeapAlloc() with a dedicate heap (created using HeapCreate()) or even just directly using VirtualAlloc() will most likely lead to superior results than using the C runtime heap.

Tools
A first step in understanding such bugs is to be able to visualize the memory and to also inspect the various page and paragraph information.

To aid in these tasks we have just added a VM Pages view and VM Paragraphs view to VM Validator to make identifying such issues easier. VM Validator is a free download.

Memory Validator will also be updated with a VM Paragraphs view in the next release (Memory Validator already has a more detailed VM Pages view).

Thank you to Blake Miller of Invensys for suggesting an alternative wording for one paragraph of this article.

Delete memory 5 times faster

March 2nd, 2010

Memory management in C and C++ is typically done using either the malloc/realloc/free C runtime functions or the C++ operators new and delete. Typically the C++ operators call down to the underlying malloc/free implementation to do the actual memory allocations.

This is great, its useful, it works, BUT it puts all the allocations in the same heap. So when you come around to deallocating the heap manager will need to take into account all the other objects and allocations that are also in the heap but unrelated to the data you are deallocating. That adds overhead to the heap manager, causing memory fragmentation and slower heap management.

There is a different way you can handle this situation – you can use your own heap for a given group of allocations.

	HANDLE	hHeap;

	hHeap = HeapCreate(0, 0x00010000, 0); // 64K growable heap

The downside to this is that you have to remember to use the correct allocators and deallocators for these objects and not to use malloc/free etc. You can mitigate this in C++ by overriding new/delete to use your own heap.

void *myClass::operator new(size_t size)
{
	return HeapAlloc(hHeap, 0, size);
}

void myClass::operator delete(void *ptr)
{
	HeapFree(hHeap, 0, ptr);
}

The upside to this technique is that you can delete all your deallocations in one call by deleting the heap and not bothering with deleting individual allocations. This is also about 5 times faster.

Old style:

	for(i = 0; i < count; i++)
	{
		HeapFree(hHeap, 0, ptrs[i]);
	}

New style:

	HeapDestroy(hHeap);
	hHeap = NULL;

There is another benefit to this technique: By deleting the heap and then re-creating a heap for new allocations you remove all fragmentation from the heap and start the new heap with 0% fragmentation.

HeapDestroy timing demonstration

Download the source of the demonstration application. Project and solution files for Visual Studio 6.0 and Visual Studio 2008 are provided.

We use this technique for some of our tools where we want a high performance heap and zero fragmentation.

You will also want to ensure that whatever software tool you are using to monitor memory allocations will mark all entries in a heap that is destroyed as deallocated.

Speed up your MFC program without a profiler!

February 13th, 2010

I’m going to explain how to potentially improve the performance of MFC programs using CMap<> and related containers (CMapStringToPtr, etc) by a substantial amount.

We use MFC for quite a lot of our software. We also use STL and also some custom containers. It is easy to fall into certain programming habits of using a particular container for a particular task. Sometimes the result is not what you expected!

During the Christmas break I decided to write some software to analyse the Software Verification website log files. Initially I wanted to do keyword mining, but it soon blossomed into a stats package calculating different statistics for keywords, referrers, domains, URLs, favourite domains, bounce rates, evaluation download rates, etc.

I was also reading the wonderful "Web Analytics an Hour a Day" book by Avinash Kauschik. And to top it all, I was ill. I’ve since been told by various people that I had Swine Flu.

The initial version didn’t calculate much and was quite fast, but when I wanted to scale up to calculating monthly data as well as yearly, that was 13 times as much calculation and the inefficiencies in container choice started to show. I’d been lazy, this was a hobby project, nothing serious, so I’d chosen the MFC class CMap.

I wanted to map keyword strings to countData objects which would hold all the data on that keyword. Later we could discard the map and just use an array of keyword objects for random access and sorting.  I wanted data for unique keywords, so during processing of the data it seemed natural to want to map the keyword to the keyword data. I was doing similar things for referrers, referring domains, requested URLs, etc.

A CMap<> is an MFC hash table. A declaration would look like this:

CMap<CString, LPCTSTR, countData *, countData *&> mfcData;

The data processing would be something like this (simplified)

	BOOL	b;

	while(TRUE)
	{
		CString	s;

		b = file.ReadString(s);
		if (!b)
			break;

		// lookup string

		countData	*cd = NULL;

		if (mfcData.Lookup(s, cd))
		{
			// if we know about the string update the count

			cd->addCount(1);
		}
		else
		{
			// otherwise create the string and update the count

			cd = new countData(s, 1);
			mfcData.SetAt(s, cd);
		}
	}

The problem with the CMap<> class is that its hash key calculation isn’t very sophisticated, so you get collisions reasonably quickly, which forces the CMap to start making linked lists for the non-identical collisions, and walking the linked lists for subsequent searches is linear time. That gets slower as you add more data.

After processing for one particlularly large set of data for 2009 took 36 hours I thought a better solution was required. Why did I let it run so long? Partly because once it got past a few hours I was curious to see how long it would take. By this time I was ill, so it didn’t really matter, I was spending much of this time in bed alternately too hot or too cold :-(

The STL has a non-standard hash table, so we didn’t want to use that, so we opted to use the STL <map> class. The declaration would look like this

map<CString, countData *> stlData;

The data processing would be something like this (simplified)

	BOOL	b;

	while(TRUE)
	{
		if (stopScan)
			break;

		CString	s;

		b = file.ReadString(s);
		if (!b)
			break;

		// lookup string

		MAP_STL::iterator	iter;

		iter = stlData.find(s);
		if (iter != stlData.end())
		{
			// if we know about the string update the count

			iter->second->addCount(1);
		}
		else
		{
			// otherwise create the string and update the count

			countData	*cd;

			cd = new countData(s, 1);
			stlData[s] = cd;
		}
	}

This is not a hash table, its a B-tree, so it will use more memory than the hash map, and unique entries should be slower than the hash table, but colliding entries should be faster. With this new style of map substituted all over the program, for all the many unique datatypes being calculated, the processing time dropped from 36 hours to 1 hour.

In other words, the STL version processed the data in 2.77% of the time the MFC version processed the data. That is a 97% improvement in processing time.

I am not saying that you will get this improvement. This improvement was acheived partly because of the type of statistics being calculated and partly due to the input data having so many collisions. The dataset for the above test was 17.1GB of Apache log files.

I have created an example MFC program that shows a trivial example of reading in lines from a file, testing them for uniqueness and storing them and updating the counts for them. The program also does the same using STL. Some sample times shown below:

Size (MB) MFC STL Improvement
34 00:00:12 00:00:06 50%
2048 00:22:46 00:05:21 76%

Time comparison of reading a 34MB file with MFC and STL
For a sample 34MB input file, the MFC program processes the data in 12+ seconds and the STL program processes the same data in 6+ seconds. An approximately 50% improvement.

Time comparison of reading a 2GB file with MFC and STL
For a sample 2GB input file, the MFC program processes the data in 22 minutes 46 seconds seconds and the STL program processes the same data in 5 minutes 21 seconds. An approximately 76% improvement.

The larger the dataset, or the more different CMap<> you are using calculating the data, the chances are that changing them to STL <map> would be highly effective in speeding up that part of your application. Note that if you are only loading a few tens of items into the map, it will not be worth making the change.

You can download the executable and the source code with project files so that you can test this yourself.

I don’t recommend changing all occurrences of CMap<> for STL <map>, but changing a the right ones should make some easy and worthwhile gains for you.

Code signing and user hinting

December 22nd, 2009

We have just released new versions of our software tools that are code signed.

This change will please those of you that are using more recent operating systems that will ask your permission to start an executable that is not signed by a company that you trust. No more warnings for Vista and Windows 7 users!

We have also introduced a new user hinting feature that provides some general guidance on what to do next using unused space on the user interface. This user hinting came about as a result of some usability testing we did during November. We hope you find this useful, if not for yourself, but your colleagues when introduced to the software.

Support for MinGW and QtCreator

December 4th, 2009

Everyone uses Visual Studio to write C and C++ software don’t they? Yes! you all chorus. Apart from some guys at the back who like to use gcc and g++. They use MinGW when working on Windows. And they may even use Emacs, or perish the thought, vi!

Up until now we haven’t been able to cater to the needs of gcc and g++ users. We’d get email every month asking when we were going to support MinGW or if we supported QtCreator. It was frustrating admitting we couldn’t support that environment. Even more so as the founders of Software Verification wrote large GIS applications using gcc and g++ back in the early 1990s.

During October we integrated support for MinGW and QtCreator into Coverage Validator, Memory Validator, Performance Validator and Thread Validator. Both COFF and STABS debug formats are supported, which provides some flexibility in how you choose to handle your symbols.

We’ll continue to add support for additional compilers to our tools as long as there is interest from you, the kind people that use our software tools.

Got a crash with a strange pointer value?

December 4th, 2009

Ever had a crash with a pointer value of 0xcdcdcdcd or 0xdddddddd or 0xfeeefeee?

You have? Sooner or later when you work with C or C++ you’ll bump into one of these crashes. You will no doubt try to reproduce the crash and thats when you’ll probably notice this unusual value has repeated itself. Perhaps the value is significant, perhaps it is telling you something?

Stephen has just written an article about the unusual bit patterns you can find in variables on the stack or in the various Win32 heaps or in the CRT heap. The article closes with some suggestions on how to prevent these errors from occurring.

A few minutes spent reading about the bit patterns may help you see these bit patterns less frequently and dig you out of any 0xfeeefeee hole you may have fallen into.

What do programmers want for Christmas?

November 25th, 2008

T-shirts appears to be the answer. Even better if they come with a natty logo or slogan.

Andy Brice has come up with a wonderful idea of creating some interesting T shirt designs with programming related in-jokes. The profits from the sale of these T-shirts goes to two worthy charities: SightSavers and JairpurFoot. SightSavers is a charity helping to prevent blindness and eyesight problems and Jaipurfoot is a charity helping to provide low cost prosthetics to people in 22 countries.

Head on over to T-Shirts for Programmers to read about Andy’s motivations for the T-shirts. His blog also has lots of interesting articles about the independent software business.

Full disclosure: Andy Brice is a customer of ours. Andy uses Coverage Validator to improve the testing of his popular Table Planning software. Andy has recently written a review of Coverage Validator V3.

Robot footballers in China

August 8th, 2008

A while ago a German University Robot Football team asked us if we could help them with their software. We provided Performance Validator to them to see what they could do. Today we found out.

The Darmstadt Dribblers have just taken their robot Isra to RoboCup 2008, held in Suzhou, China. They came 4th in the championship (24 teams competing), losing to the championship winners (also from Germany). The other two quarter finalists were both from Japan. Thats a good result, against some good competition.

Isra running to the ball.

Isra running and kicking

Isra tackles an opponent.

Isra tackles

Isra scores a goal.

Isra scores a goal

This YouTube video shows Isra in action at Suzhou:
http://www.youtube.com/watch?v=QTbGXqQNkqQ&feature=PlayList&p=28F7B3DCA3198715&index=7

The Dramstadt Dribblers have uploaded various videos here:
http://www.youtube.com/profile_videos?user=DarmstadtDribblers

Still think software engineering can’t be fun?

We’ll be reporting on the Dribblers’ performance as they enter more competitions.

Tab controls and tree/grid controls – why change them?

May 12th, 2008

In this post I’m going to describe some of the changes we’ve been making to the user interface of our software tools and also why this change has become necessary.

Over the past few months we have made a variety of wide ranging changes to the GUI of our software tools. Earlier versions of our tools used some 3rd party tab controls and some 3rd party grid controls that could also function as tree controls. These controls were very useful and enabled us rapidly create the user interfaces we needed.

However, over time we found a few special cases where we needed something more powerful. This resulted in the virtual tree/grid control we now use to display the potentially very large datasets the tools can collect. We haven’t found any 3rd party tree or grid that can handle the volume of data the virtual tree/grid control can handle.

The result of this is that there were several competing styles of tree/grid control, some with white backgrounds, others with darker backgrounds, all with different visual styles for the way the grid was draw and the way it behaved in response to user input. This, while effective, was less than ideal.

At the same time, we have customers and potential customers asking us when our software will run on 64 bit Windows, or when it will run on Linux and Mac OS / X. We’ve been looking at the Linux and Mac OS / X issue for some time, evaluating which technology route to go with for the port, writing tools to automate as much of the port as possible (we have over 30 software tools to port if we port every tool) and assessing the “weak points” in our codebase that will cause us trouble.

Some customers having become used to our rapid turnaround of bug fixes have been somewhat surprised at how long we have taken to produce our ports to non-Windows operating systems. The main reason for the delay is that we want to port all the software tools that are appropriate, rather than just port Ruby Performance Validator and Ruby Memory Validator.

Having written the porting tools, we then ran up against our major weak points, consisting of the 3rd party tab control and 3rd part tree/grid controls, used in many, many places throughout our software. Thus, alongside our usual development goals of introducing new functionality and attending to customer issues, 2008 has been spent writing even more tools to aid us with the transition from the 3rd party tab control to a custom tab control and from the 3rd party tree/grid control to the virtual tree/grid control.

Today marks the first day without the 3rd party controls in our software. We still have some work to do before we can let the automated porting tools we’ve written loose on our codebase to product the cross-platform single source codebase we desire. However this is a significant step forward in that process.

Although we are not there yet, I hope this posting has provided some insight to what we are doing to those of you that are interested in this work.

Future postings will cover this topic as we have more to say about porting from a large MFC codebase to Linux and Mac OS / X.

XULRunner Support

April 3rd, 2007

About a month ago we hadn’t heard of XULRunner. Then the folks at Songbird emailed us asking if our JavaScript tools supported XULRunner.

Its easy to miss a new tool or technology what with all the various development directions people are taking. XULRunner is a platform independent way to write applications using the same technology used to create Firefox and Thunderbird. You use the XPCOM, XUL and JavaScript technologies to create your application. With a bit of magic it then runs on your platform of choice. Songbird are using XULRunner to create a platform independent media player. I guess they know their target market, they are founded by the same people that did Winamp and Yahoo! Music Engine.

Given that we already supported JavaScript for Firefox and Flock support for XULRunner seemed like a natural fit. Ideally it would have worked out of the box, just change a few settings on the UI of our tools and off you go. It didn’t turn out that way, although now we’ve made the appropriate changes, its as trivial as selecting xulrunner.exe instead of firefox.exe when you are choosing the JavaScript runtime.

The first problem we had was that xulrunner.exe doesn’t use the js3250.dll DLL directly, it does it via the xul.dll DLL. As a result the UI and the stub couldn’t find the js3250.dll and thus couldn’t determine the version information we use to choose how to interact with js3250.dll. So we needed to support that.

The second issue was that each js3250.dll we’ve encountered has some internal differences that make line numbers inconsistent unless you use a build against the same header files used for that build. Very annoying, but thats how it is. So we need to know if its Firefox 1.0, 1.5, 2.0, Flock 0.7, or xulrunner to choose the appropriate way to interact with the target. If our tools don’t know they assume you are using the latest and greatest and give you the firefox 2.0 treatment. XULRunner needs the 1.5 treatment not the 2.0 treatment so we had to put in a check for that. Also, the version ids on xulrunner.exe shipped with Songbird are "Personal" and not a version number. Excuse me? Whats up with that? Not very useful information. It should read "1.8" or something similar given that XULRunner is currently at 1.8.0.4. Hopefully someone will fix that.

A third issue was a killer. Songbird triggers a hook that causes a fatal crash. Whoops, how did that get past testing? Same way any other bug does I guess :-( Thats life, we are not perfect, so chalk that one up to experience.

We also needed a few XULRunner specific tweaks. For example when you are launching a XULRunner application you are looking for .ini files not .html/.js files.

To sum up, all our JavaScript tools now support XULRunner. This should help all of you using XULRunner to create platform neutral apps using Mozilla technology. If you have any specific issues please let support know at the usual address.


Perfect imprecision, thoughts on memory leaks, performance profiling, code coverage, deadlock detection and flow tracing is proudly powered by WordPress
Entries (RSS) and Comments (RSS).

About Us | Site Map | Legal | Contact Us | ©2002-2006: Software Verification Ltd : all rights reserved: registered in England No. 3939098 112
Design by ITS GUI