Thread: How to guarantee alignment with malloc and or new?

  1. #1
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251

    Post How to guarantee alignment with malloc and or new?

    How can I impose alignment of data wit malloc and / or new?
    Guess
    Code:
    if (sizeof(data)%alignment)
       data=(data*)malloc(alignment*(sizeof(data)/alignment)+alignment)
    else data=(data*)malloc(sizeof(data));
    ??


    With new??
    Last edited by mynickmynick; 08-26-2008 at 07:58 AM.

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    The only way to guarantee alignment is by doing such alignment yourself. In new [for non-POD types], you'd have to first allocate a sufficiently large buffer and then use placement new to allocate an object in that buffer.

    However, malloc() itself is guaranteed to give you an alignment to at least 8 bytes. What sort of alignment are you trying to achieve.

    By the way, sizeof(data) % alignment is not meaningful - if you want to align a 128 byte structure to 128 byte alignment, that's by no means guaranteed by your test. You have to take the return value from malloc, cast it to an integer-type of sufficient size to hold an pointer and do math to check if it's aligned, and if not, align it. For 2^n alignment, you can do:
    Code:
    void *malloc_aligned(size_t size)
    {
       void *ptr = malloc(size + alignment-1);
       if (!ptr) return NULL;
       ptr = (void *)(((IntPtr_t)(ptr) + alignment-1) & ~alignment;
    }
    Note that you must keep the original pointer if you want to call free as well.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    What type of alignment do you require?

    I've done tests with malloc previously, and it appears to me, on my Mac, that the minimum amount of storage that the system would return to be was 16 bytes, even if I requested 1 byte. And, it was always aligned to a x'10' boundary.

    See this sample:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char* argv[]){
    	int i ; 
    	char * pointers[50] ; 
    	
    	for (i = 0 ; i < 50 ; i++) { 
    		pointers[i] = malloc(i) ; 
    		printf("malloc(&#37;d bytes) address is %p\n", i, pointers[i] );
    	} 
    	
    	for (i = 0 ; i < 50 ; i++) { 
    		free(pointers[i]) ; 
    	} 
    	
        return 0;
    }
    For the new operator, I expect the compiler to worry about, and properly provide for, alignment.

    If you want other alignment, then that's easy too.

    Let's say you want to obtain 4096 bytes of storage to have the address end with 3 zeros, like 45AE000. Then, get 4096 + 4095 and then round your pointer when it gets returned:

    char * ptr_rounded ;
    char * ptr = malloc(4096+4095) ;
    ptr_rounded = ((ptr >> 3) << 3) ;
    Last edited by Dino; 08-26-2008 at 08:08 AM. Reason: typo
    Mainframe assembler programmer by trade. C coder when I can.

  4. #4
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    yes sorry my example was not correct at all
    If you say malloc() aligns at least to 8 bytes boundaries it's enough for my multithread worries I guess. But it doesn't cope with cache matters.

    For new I didn't get what happens?

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by mynickmynick View Post
    yes sorry my example was not correct at all
    If you say malloc() aligns at least to 8 bytes boundaries it's enough for my multithread worries I guess. But it doesn't cope with cache matters.

    For new I didn't get what happens?
    Well, first of all, cache-alignment (to cache-lines) is a slightly different matter - since you then have to take into account the difference between to calls to malloc [for example MS Visual Studio .Net allocates 64-bytes apart for small objects].

    I wouldn't worry about cache-line boundaries for now. [In fact, I wouldn't worry about multithread problems either because two allocations on two different threads will absolutely certainly cover more than 8 bytes of overhead anyways - except perhaps on 16-bit processors, but those won't be multicore - and probably not much of cache either, so no problem].

    In the case of new, when you call new, you are asking for two things:
    1. The memory to be allocated.
    2. The constructor to be called.

    Since the constructor is called for the original address of the data, you can't later change the pointer address and still expect things to work. To work around that, you'd have to use something called placement new, which is a call to new with a "buffer" passed to the new function for the memory to be used.

    Google for "Placement new" and you'll find some information (or look it up in Stroustrup or similar - beginner C++ may not cover it).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Quote Originally Posted by matsp View Post
    Since the constructor is called for the original address of the data, you can't later change the pointer address and still expect things to work. To work around that, you'd have to use something called placement new, which is a call to new with a "buffer" passed to the new function for the memory to be used.

    Google for "Placement new" and you'll find some information (or look it up in Stroustrup or similar - beginner C++ may not cover it).

    --
    Mats
    Ok
    I'll have a look

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Dino View Post

    Let's say you want to obtain 4096 bytes of storage to have the address end with 3 zeros, like 45AE000. Then, get 4096 + 4095 and then round your pointer when it gets returned:

    char * ptr_rounded ;
    char * ptr = malloc(4096+4095) ;
    ptr_rounded = ((ptr >> 3) << 3) ;
    Of course, that's missing a few casts, and you really need to shift 12 bits each way - or use the add/and-trick that I suggested above - the latter is probably a whole one or two clock-cycles faster - that must be, hmm, about 0.05% of the total time of malloc, so clearly worth doing ;-) [Actually, some code does this sort of thing quite a lot, such as MMU code that aligns an input address to page-boundary].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    Yes, 12 bits. Yes, casts. That's what I get for typing off the top of my head (I was thinking 3 nibbles). Yes, AND would work just as well too. Thanks.
    Mainframe assembler programmer by trade. C coder when I can.

  9. #9
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    malloc is not guaranteed to give any n of bytes alignment, but it is guaranteed to give an alignment suitable for any objects.

  10. #10
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    alignment is not guaranteed at any interval on any machine, although that is dependant on the implimentation of malloc and the memory manager library.

    The only way to guarantee alignment with portable code is by manually aligning by overallocation.

    on windows you can use _aligned_malloc ()
    Last edited by abachler; 08-26-2008 at 07:07 PM.

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    As robwhit says, you should be able to allocate any type of object with correct alignment, which generally means at least 8-byte alignment (or rather, suitably aligned to the largest type of "long long", "double", "long", or "char *" [and all other standard types - but the former are most likely to be the longest])

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  12. #12
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Last edited by mynickmynick; 08-27-2008 at 02:26 AM.

  13. #13
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yes, but that is specific to glibc - which like many C libraries, have special functions that allocate aligned memory. But it's not portable to other compilers. Of course, you can hide such functions by adding your own wrapper [which may be a inline or #define macro in many cases].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  14. #14
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Quote Originally Posted by matsp View Post
    Google for "Placement new" and you'll find some information (or look it up in Stroustrup or similar - beginner C++ may not cover it).

    --
    Mats
    Thank you but this placement new doesn't seem to be very handy
    cause you have to allocate some buffer manually before

  15. #15
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by mynickmynick View Post
    Thank you but this placement new doesn't seem to be very handy
    cause you have to allocate some buffer manually before
    There are two ways to achieve aligned new - placement new with a pre-aligned buffer and implement a class-specific new/delete pair. In both cases, you will be allocating memory separately, but in the class-specific new/delete you can hide the fact from a user of the classs.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed