Aligned C++ objects created with a 'new' C++ operator

Aligned C++ objects created with a 'new' C++ operator

This is a new thread related to aligned memory management C++ operators 'new' / 'delete' and 'new[]' / 'delete[]'.

Please take a look at a similar thread:

Forum topic: 'Aligning with new: for a beginner'
Web-link: http://software.intel.com/en-us/forums/topic/328019

Thanks to a User 'llevrel' for that subject!

Best regards,
Sergey

PS: This is the first post and many more will follow...

25 Beiträge / 0 neu
Letzter Beitrag
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.

Here are source codes of my test case:


...

class CAlignedObject

{

public:

	CAlignedObject( void )

	{

	//	printf( "CAlignedObject::CAlignedObjectn" );

	};
	~CAlignedObject( void )

	{

	//	printf( "CAlignedObject::~CAlignedObjectn" );

	};
	void * operator new( size_t nSize, size_t nAlignment );

	void operator delete( void *pObject, size_t nAlignment );

};
void * CAlignedObject::operator new( size_t nSize, size_t nAlignment )

{

	if( ( (nAlignment)&(nAlignment-1) ) == 0 )

		return ( void * )_aligned_malloc_dbg( nSize, nAlignment, __FILE__, __LINE__ );

	else

		return ( void * )NULL;

}
void CAlignedObject::operator delete( void *pObject, size_t nAlignment )

{

	if( pObject != NULL )

		_aligned_free_dbg( pObject );

}
...

		CAlignedObject *pAO = NULL;
		for( int i = 1; i <= 1024; i++ )

		{

			pAO = new( i ) CAlignedObject();

			if( pAO != NULL )

				printf( "Object Aligned on %4ld - %sn", ( int )i, ( ( int )pAO % i == 0 ) ? "Yes" : "No" );

			else

				printf( "Alignment value   %4ld is NOT a power of 2n", ( int )i );
			if( pAO != NULL )

			{

				delete pAO;

				pAO = NULL;

			}

		}

...

>>...Here are source codes of my test case
.
Sorry for formatting issues in the submitted test case. It's not my fault...

We discussed a lot of different issues in the 'Aligning with new: for a beginner' thread and after my additional investigation I have very interesting results.
.
Here is a summary:
.
- CRT-functions '_aligned_malloc_dbg' or '_aligned_malloc' could be used in a C++ operator 'new' ( so far I didn't try to use these functions in a C++ operator 'new[]' / please try by yourself if interested )
.
- When CRT-functions '_aligned_malloc_dbg' or '_aligned_malloc' are used in a C++ operator 'new' a C++ object constructor will be called and object will be constructed ( about 1.5 year ago I had some problems with it / unfortunately, it is hard to recall what was wrong )
.
- C++ operator 'new' allocates memory for a C++ object if alignment boundary value IS a power of 2 ( verified on a range of alignment boundary values up to 1024 )
.
- C++ operator 'new' doesn't allocate memory for a C++ object if alignment boundary value is NOT a power of 2 and returns NULL ( this is by design of '_aligned_offset_malloc_dbg' CRT-function / a Release configuration '_aligned_offset_malloc' CRT-function makes a call to '_aligned_offset_malloc_dbg' (!) )
.
- CRT-functions '_aligned_malloc_dbg' / '_aligned_free_dbg' or '_aligned_malloc' / '_aligned_free' are Microsoft specific ( I didn't see a similar set of functions in GCC-like or some legacy C++ compilers / MinGW or Borland C++, for example )

Here are some outputs from my test case:
.
[ Output 1 ]
...
CAlignedObject::CAlignedObject
...
CAlignedObject::~CAlignedObject
...
.
[ Output 2 ]
...
Object Aligned on 1 - Yes
Object Aligned on 2 - Yes
Alignment value 3 is NOT a power of 2
Object Aligned on 4 - Yes
Alignment value 5 is NOT a power of 2
Alignment value 6 is NOT a power of 2
Alignment value 7 is NOT a power of 2
Object Aligned on 8 - Yes
Alignment value 9 is NOT a power of 2
Alignment value 10 is NOT a power of 2
Alignment value 11 is NOT a power of 2
Alignment value 12 is NOT a power of 2
Alignment value 13 is NOT a power of 2
Alignment value 14 is NOT a power of 2
Alignment value 15 is NOT a power of 2
Object Aligned on 16 - Yes
Alignment value 17 is NOT a power of 2
...
Alignment value 31 is NOT a power of 2
Object Aligned on 32 - Yes
Alignment value 33 is NOT a power of 2
...
Alignment value 63 is NOT a power of 2
Object Aligned on 64 - Yes
Alignment value 65 is NOT a power of 2
...
Alignment value 127 is NOT a power of 2
Object Aligned on 128 - Yes
...
Object Aligned on 256 - Yes
...
Object Aligned on 512 - Yes
...
Alignment value 777 is NOT a power of 2
...
and so on

Here is some additional information:
.
CRT-functions '_aligned_malloc_dbg' or '_aligned_malloc' don't allocate memory directly and use 'malloc_dbg' or 'malloc' CRT-functions:
.
[ For Debug configuration ]
.
_aligned_malloc_dbg -> _aligned_offset_malloc_dbg -> malloc_dbg
.
At some point it will do a verification in a '_aligned_offset_malloc_dbg' CRT-function if a value of alignment is a power of 2 using IS_2_POW_N( align ) macro of Microsoft CRT library
.
[ For Release configuration ]
.
_aligned_malloc -> _aligned_offset_malloc -> malloc
.
Note: Let me repeat again, in the Release configuration '_aligned_offset_malloc' CRT-function makes a call to '_aligned_offset_malloc_dbg'

I had a couple of MS C/C++ compiler warnings for my test case:
.
warning C4291: 'void * CTestObject::operator new( size_t )' : no matching operator delete found; memory will not be freed if initialization throws an exception
warning C4311: 'type cast' : pointer truncation from 'CTestObject *' to 'int'
.
These two warnings could be disabled with pragma directives:
.
#pragma warning ( disable : 4291 )
#pragma warning ( disable : 4311 )

Sergey,

Consider adding an ASSERT((sizeof(*this)%nAlignment) == 0); in your overloaded new. This will assure during testing that the "you" in user has properly padded the struct/class to force a size of a multiple of the alignment (this need not be a power of 2). Note, when the sizeof the struct/class (including virtual function pointers if any) is a multiple of the size of alignment then an array of the struct/class can be

// in the overload for new MyClass[nElements]
MyClass* array = (MyClass*)aligned_malloc(sizeof(*this)*nElements, nAlignment);
if(array)
{
for(int i=0; i < nElements; ++i)
new (&array[i]) MyClass; // Perform the ctor at address specified
}
Jim Dempsey

www.quickthreadprogramming.com

Hi Jim,
...
>>...Consider adding an ASSERT((sizeof(*this)%nAlignment) == 0); in your overloaded new. This will assure during testing that the "you" in
>>user has properly >>padded the struct/class to force a size of a multiple of the alignment (this need not be a power of 2)...
.
You are right and thank you for the note!

See attached file:

Illustrates aligned objects with overloads for new, delete, new[], delete[], for base and derived types.
Read notes relating to where and when to use padd.
Code is "AS IS".
Jim Dempsey
*** ignore the .docx file, use the .txt file

Anlagen: 

AnhangGröße
Herunterladen testnew.docx24.02 KB
Herunterladen testnew.txt7.56 KB
www.quickthreadprogramming.com

*** GRIPE ***
Unable to delete attache file

www.quickthreadprogramming.com

>>...Illustrates aligned objects with overloads for new, delete, new[], delete[], for base and derived types...
.
Hi Jim,
Thank you very much and that example looks awesome.
Best regards,
Sergey
.
PS: I've never used a __FUNCSIG__ macro because I didn't know about its existence...

I'd like to make a couple of follow ups.
.
>>...this need not be a power of 2...
.
This is a limitation of '_aligned_offset_malloc_dbg' CRT-function and it always uses IS_2_POW_N( align ) macro. If somebody wants to create an object on any alignment boundary value then a new function could be created based on '_aligned_offset_malloc_dbg' CRT-function but without _VALIDATE_RETURN and IS_2_POW_N macros.

>>...This is a limitation of '_aligned_offset_malloc_dbg' CRT-function and it always uses IS_2_POW_N( align ) macro...
.
Take a look at [ VS InstallDir ]\VC\Crt\Src\dbgheap.c if interested:


...

extern "C" _CRTIMP void * __cdecl _aligned_offset_malloc_dbg(

        size_t size,

        size_t align,

        size_t offset,

        const char * f_name,

        int line_n

        )

{

    uintptr_t ptr, r_ptr, t_ptr;

    _AlignMemBlockHdr *pHdr;
    /* validation section */

    _VALIDATE_RETURN( IS_2_POW_N( align ), EINVAL, NULL );

...

Here is a different way of using the CAlignedObject class:
.
Note: Where N is a next power of two number that is greater than sizeof( CAlignedObject )


	...

	CAlignedObject *pAO = new( N ) CAlignedObject();

	...

>>...PS: I've never used a __FUNCSIG__ macro because I didn't know about its existence...
.
Jim, I have a question: Did you compile the codes with Intel and Microsoft C++ compilers?
.
I had some issues with the __FUNCSIG__ macro.

Just discovered that
.
_aligned_malloc
_aligned_malloc_dbg
_aligned_free
_aligned_free_dbg
.
CRT-functions are NOT supported on Windows Mobile platforms.

Quote:

Sergey Kostrov wrote:

This is a limitation of '_aligned_offset_malloc_dbg' CRT-function and it always uses IS_2_POW_N( align ) macro. If somebody wants to create an object on any alignment boundary value then a new function could be created based on '_aligned_offset_malloc_dbg' CRT-function but without _VALIDATE_RETURN and IS_2_POW_N macros.

The size of the structure need not be a power of 2.
The size of the structure needs to be a multiple of the power of 2 that you require for alignment (e.g. 8-bytes for doubles, 16 -bytes for SSE, or 32-bytes for AVX2, ...)

I tested with Intel C++, I did not test with MSVC

**** Potential gotcha ***

In the new[] operator, the Intel compiler generates a size_t header element containing the count of the elements in the array. Thus the necessitating of creating of the prefix padd in the allocation, and the bung-up (fix-up) of the returned pointer (converse in the delete[] operator).
*** this value may change from compiler vendor to compiler vendor ***
Therfore it is a requirement that you run a verification program, such as the provided test program, then make adjustments (conditional compilations) as required.
You will note that you will need to do this in any event because the VTable information may vary from vendor to vendor. You might consider keeping a verification test in the beginning of the program in the event that a library function (.DLL, .so) returns the new[]. The information (diagnostic) may be more helpful than a GP fault in determining the problem.

Jim Dempsey

www.quickthreadprogramming.com

Quote:

Sergey Kostrov wrote:

Just discovered that
.
_aligned_malloc
_aligned_malloc_dbg
_aligned_free
_aligned_free_dbg
.
CRT-functions are NOT supported on Windows Mobile platforms.

It should be easy enough to overload the missing funcitons.
Jim Dempsey

www.quickthreadprogramming.com

>>>>>>...PS: I've never used a __FUNCSIG__ macro because I didn't know about its existence...
>>>>
>>>>Jim, I have a question: Did you compile the codes with Intel and Microsoft C++ compilers?
>>>>
>>>>I had some issues with the __FUNCSIG__ macro.
>>
>>I tested with Intel C++, I did not test with MSVC

I see. Thanks, Jim. Issues with __FUNCSIG__ macro are detected when I tried to use that macro in a project that has UNICODE support. I'll provide more technical details later.

Sergey, part of the requirements of using an "AS-IS" program example is working out the peculiarities of your compiler+options, typically by use of conditional compile directives. We've probably carried this thread far enough. Code revisions should likely be maintained on some suitable site (sourceforge, stackoverflow, etc...).

Thanks for your contributions.

Jim Dempsey

www.quickthreadprogramming.com

>>...Code revisions should likely be maintained on some suitable site (sourceforge, stackoverflow, etc...)...

No time for all these great web-sites, unfortunately.

Best regards,
Sergey

Hello,

Using the overloaded operator new can not solve all the cases of alignment new. But it might be enough for your case.

We have an existing FeatureRequest for this. But unfortunately it is not completely implemented still. See this proposal on adding this to the standards: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3396.htm 

Once it's supported, we'll let you know.

thanks,

Jennifer

>>...Using the overloaded operator new can not solve all the cases of alignment new...

Jennifer, could you provide a couple of example when it can't be done, please?

This "aligned new" operator feature has been implemented in the 15.0 compiler and update 1 for OS X. The detail can be found at https://software.intel.com/en-us/articles/aligned-operator-new-support-in-intel-c-compiler

Hope you'll like it.

Jennifer

Kommentar hinterlassen

Bitte anmelden, um einen Kommentar hinzuzufügen. Sie sind noch nicht Mitglied? Jetzt teilnehmen