BOOKS i'm reading |
Enhance your dynamic memory allocation in C++ with an undocumented MFC class (CFixedAlloc)Contents
The demo programThe demo program is very simple. It just declares two almost identical classes: one without
#define ITER_NUM 1000*1024 class A { public: A( A *next ) : m_next(next) {} A *m_next; int dummy1; int dummy2; }; class B { public: B( B *next ) : m_next(next) {} B *m_next; int dummy1; int dummy2; DECLARE_FIXED_ALLOC(B); }; IMPLEMENT_FIXED_ALLOC(B,ITER_NUM); void CCFixedAllocDemoDlg::OnTestTimebutton() { // TODO: Add your control notification // handler code here A *curAObj, *firstAObj = NULL; B *curBObj, *firstBObj = NULL; DWORD startA, endA, startB, endB; register int i; { CWaitCursor wait; startA = GetTickCount(); for( i = 0; i < ITER_NUM; i++ ) { firstAObj = new A(firstAObj); } while( firstAObj ) { curAObj = firstAObj->m_next; delete firstAObj; firstAObj = curAObj; } startB = endA = GetTickCount(); for( i = 0; i < ITER_NUM; i++ ) { firstBObj = new B(firstBObj); } while( firstBObj ) { curBObj = firstBObj->m_next; delete firstBObj; firstBObj = curBObj; } endB = GetTickCount(); } displayResult( endA-startA,endB-startB ); } #define BYTES_PER_PARA 16 void CCFixedAllocDemoDlg::displayResult( DWORD timeA, DWORD timeB ) { TCHAR buf[1024]; /* * Each object A takes 32 bytes. See article for details */ int overheadA = (32-sizeof(A))*ITER_NUM; /* * First compute the allocated size then substract the * requested size */ int overheadB = (8+sizeof(B)*ITER_NUM + sizeof(CPlex) + (BYTES_PER_PARA-1)) & ~(BYTES_PER_PARA - 1); overheadB -= sizeof(B)*ITER_NUM; wsprintf( buf, __TEXT("Creating and destroying %d objects\n") __TEXT("without CFixedAlloc\t: %4d ms\n") __TEXT("with CFixedAlloc\t: %4d ms\n") __TEXT("You saved %d bytes with CFixedAlloc"), ITER_NUM, timeA, timeB, overheadA - overheadB ); MessageBox(buf,__TEXT("Results")); } SuggestionsYou could make a single thread version of // DECLARE_FIXED_ALLOC -- used in class definition #define DECLARE_FIXED_ALLOC_NOSYNC(class_name) \ public: \ void* operator new(size_t size) \ { \ ASSERT(size == s_alloc.GetAllocSize()); \ UNUSED(size); \ return s_alloc.Alloc(); \ } \ void* operator new(size_t, void* p) \ { return p; } \ void operator delete(void* p) { s_alloc.Free(p); } \ void* operator new(size_t size, LPCSTR, int) \ { \ ASSERT(size == s_alloc.GetAllocSize()); \ UNUSED(size); \ return s_alloc.Alloc(); \ } \ protected: \ static CFixedAllocNoSync s_alloc \ // IMPLEMENT_FIXED_ALLOC_NOSYNC -- used in class implementation file #define IMPLEMENT_FIXED_ALLOC_NOSYNC(class_nbame, block_size) \ CFixedAllocNoSync class_name::s_alloc(sizeof(class_name), block_size) \ There is a mistake in the
/* * Uncomment the next define statement * to use the single thread version of * CFixedAlloc. Prior to recompilation, * you must fix a syntax error in * fixalloc.h. The IMPLEMENT_FIXED_ALLOC_NOSYNC() * macro parameter class_nbame * should be rename to class_name. * * Note: The single thread version is only * available in VC++.NET and up. */ //#define _USE_SINGLE_THREAD #ifndef _USE_SINGLE_THREAD class B { public: B( B *next ) : m_next(next) {} B *m_next; int dummy1; int dummy2; DECLARE_FIXED_ALLOC(B); }; IMPLEMENT_FIXED_ALLOC(B,ITER_NUM); #else class B { public: B( B *next ) : m_next(next) {} B *m_next; int dummy1; int dummy2; DECLARE_FIXED_ALLOC_NOSYNC(B); }; IMPLEMENT_FIXED_ALLOC_NOSYNC(B,ITER_NUM); #endif My testing of the no sync version has shown a speedup improvement of 40% over the original ConclusionThat is it! I hope you enjoyed this C++ Windows programming tutorial and that you have found it useful. In the next section, you will find the books that I have consulted to build this C++ Windows programming tutorial. If you liked this tutorial then you might be interested in the follow-up tutorial that presents a real case on how to apply the CFixedAlloc optimzation on an existing MFC software. Bibliography
|