C tricks
Random collection of C tricks that I found interesting.
Zero size struct members to enforce cache-line grouping of other struct elements
This patch, using the zero length extension, makes sure at compile-time that certain struct elements are located in the same cache line.
1#include <stdio.h>
2
3struct k {
4 int a[0];
5};
6
7int main() { printf("%zu\n", sizeof(struct k)); }
Should print print a 0
. I was aware of the other uses of zero-length arrays for dynamically-sized structs (where those zero-length arrays are put at the last
position of a struct, see the extension for more information about this), but hadn’t seen this trick before.
Using macros, zero-sized arrays are defined on group boundaries:
1#ifndef __cacheline_group_begin
2#define __cacheline_group_begin(GROUP) \
3 __u8 __cacheline_group_begin__##GROUP[0]
4#endif
5
6#ifndef __cacheline_group_end
7#define __cacheline_group_end(GROUP) \
8 __u8 __cacheline_group_end__##GROUP[0]
9#endif
1/* TX readonly hotpath cache lines */
2__cacheline_group_begin(netns_ipv4_read_tx);
3u8 sysctl_tcp_early_retrans;
4u8 sysctl_tcp_tso_win_divisor;
5u8 sysctl_tcp_tso_rtt_log;
6u8 sysctl_tcp_autocorking;
7int sysctl_tcp_min_snd_mss;
8unsigned int sysctl_tcp_notsent_lowat;
9int sysctl_tcp_limit_output_bytes;
10int sysctl_tcp_min_rtt_wlen;
11int sysctl_tcp_wmem[3];
12u8 sysctl_ip_fwd_use_pmtu;
13__cacheline_group_end(netns_ipv4_read_tx);
The macros basically expand to unique group identifiers within a struct (otherwise, a compilation error would happen). These groups can later be used to check if a variable is within a group:
1#ifndef CACHELINE_ASSERT_GROUP_MEMBER
2#define CACHELINE_ASSERT_GROUP_MEMBER(TYPE, GROUP, MEMBER) \
3 BUILD_BUG_ON(!(offsetof(TYPE, MEMBER) >= \
4 offsetofend(TYPE, __cacheline_group_begin__##GROUP) && \
5 offsetofend(TYPE, MEMBER) <= \
6 offsetof(TYPE, __cacheline_group_end__##GROUP)))
7#endif
Or to check a group size:
1#ifndef CACHELINE_ASSERT_GROUP_SIZE
2#define CACHELINE_ASSERT_GROUP_SIZE(TYPE, GROUP, SIZE) \
3 BUILD_BUG_ON(offsetof(TYPE, __cacheline_group_end__##GROUP) - \
4 offsetofend(TYPE, __cacheline_group_begin__##GROUP) > \
5 SIZE)
6#endif
See the patch for more information. The relevance of the patch has nothing to do with this small trick, but I found it to be quite interesting :)