Post

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.

This post is licensed under CC BY 4.0 by the author.