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
2
3
4
5
6
7
#include <stdio.h>
struct k {
int a[0];
};
int 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
2
3
4
5
6
7
8
9
#ifndef __cacheline_group_begin
#define __cacheline_group_begin(GROUP) \
__u8 __cacheline_group_begin__##GROUP[0]
#endif
#ifndef __cacheline_group_end
#define __cacheline_group_end(GROUP) \
__u8 __cacheline_group_end__##GROUP[0]
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
/* TX readonly hotpath cache lines */
__cacheline_group_begin(netns_ipv4_read_tx);
u8 sysctl_tcp_early_retrans;
u8 sysctl_tcp_tso_win_divisor;
u8 sysctl_tcp_tso_rtt_log;
u8 sysctl_tcp_autocorking;
int sysctl_tcp_min_snd_mss;
unsigned int sysctl_tcp_notsent_lowat;
int sysctl_tcp_limit_output_bytes;
int sysctl_tcp_min_rtt_wlen;
int sysctl_tcp_wmem[3];
u8 sysctl_ip_fwd_use_pmtu;
__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
2
3
4
5
6
7
#ifndef CACHELINE_ASSERT_GROUP_MEMBER
#define CACHELINE_ASSERT_GROUP_MEMBER(TYPE, GROUP, MEMBER) \
BUILD_BUG_ON(!(offsetof(TYPE, MEMBER) >= \
offsetofend(TYPE, __cacheline_group_begin__##GROUP) && \
offsetofend(TYPE, MEMBER) <= \
offsetof(TYPE, __cacheline_group_end__##GROUP)))
#endif
Or to check a group size:
1
2
3
4
5
6
#ifndef CACHELINE_ASSERT_GROUP_SIZE
#define CACHELINE_ASSERT_GROUP_SIZE(TYPE, GROUP, SIZE) \
BUILD_BUG_ON(offsetof(TYPE, __cacheline_group_end__##GROUP) - \
offsetofend(TYPE, __cacheline_group_begin__##GROUP) > \
SIZE)
#endif
See the patch for more information. The relevance of the patch has nothing to do with this small trick, but it is the first time I have seen this trick.