Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there performance issues when using pragma pack(1)?

Tags:

c

gcc

Our headers use #pragma pack(1) around most of our structs (used for net and file I/O). I understand that it changes the alignment of structs from the default of 8 bytes, to an alignment of 1 byte.

Assuming that everything is run in 32-bit Linux (perhaps Windows too), is there any performance hit that comes from this packing alignment?

I'm not concerned about portability for libraries, but more with compatibility of file and network I/O with different #pragma packs, and performance issues.

like image 968
Nicolas Avatar asked Oct 17 '11 12:10

Nicolas


People also ask

What does #pragma pack 1 mean?

When you use #pragma pack(1) , this changes the default structure packing to byte packing, removing all padding bytes normally inserted to preserve alignment.

Why do you use #pragma pack 1 explain it with an example?

The #pragma pack directive cannot increase the alignment of a member, but rather can decrease the alignment. For example, for a member with data type of short , a #pragma pack(1) directive would cause that member to be packed in the structure on a 1-byte boundary, while a #pragma pack(4) directive would have no effect.

What does pragma pack do?

#pragma pack(push[, n ]) pushes the current alignment setting on an internal stack and then optionally sets the new alignment. #pragma pack(pop) restores the alignment setting to the one saved at the top of the internal stack (and removes that stack entry).

How can structure padding be reduced?

In Structure, sometimes the size of the structure is more than the size of all structures members because of structure padding. Note: But what actual size of all structure member is 13 Bytes. So here total 3 bytes are wasted. So, to avoid structure padding we can use pragma pack as well as an attribute.


1 Answers

Memory access is fastest when it can take place at word-aligned memory addresses. The simplest example is the following struct (which @Didier also used):

struct sample {
   char a;
   int b;
};

By default, GCC inserts padding, so a is at offset 0, and b is at offset 4 (word-aligned). Without padding, b isn't word-aligned, and access is slower.

How much slower?

  • For 32-bit x86, according to the Intel 64 and IA32 Architectures Software Developer's Manual:
    The processor requires two memory accesses to make an unaligned memory access; aligned accesses require only one memory access. A word or doubleword operand that crosses a 4-byte boundary or a quadword operand that crosses an 8-byte boundary is considered unaligned and requires two separate memory bus cycles for access.
    As with most performance questions, you'd have to benchmark your application to see how much of an issue this is in practice.
  • According to Wikipedia, x86 extensions like SSE2 require word alignment.
  • Many other architectures require word alignment (and will generate SIGBUS errors if data structures aren't word-aligned).

Regarding portability: I assume that you're using #pragma pack(1) so that you can send structs across the wire and to and from disk without worrying about different compilers or platforms packing structs differently. This is valid, however, there are a couple of issues to keep in mind:

  • This does nothing to handle big endian versus little endian issues. You can handle these by calling the htons family of functions on any ints, unsigned, etc. in your structs.
  • In my experience, working with packed, serializable structs in application code isn't a lot of fun. They're very difficult to modify and extend without breaking backwards compatibility, and as already noted, there are performance penalties. Consider transferring your packed, serializable structs' contents into equivalent non-packed, extensible structs for processing, or consider using a full-fledged serialization library like Protocol Buffers (which has C bindings).
like image 156
Josh Kelley Avatar answered Oct 21 '22 17:10

Josh Kelley