Re: Unaligned access trade-offs for SFrame FRE layout
Steven Rostedt <[email protected]> Mon, 15 Sep 2025 12:04:00 -0400
| Newsgroups | org.kernel.vger.linux-toolchains |
|---|---|
| Message-ID | <[email protected]> |
On Sat, 13 Sep 2025 00:56:34 -0700 Indu Bhagat <[email protected]> wrote: > I think quantifying the performance impact of unaligned accesses for > stack tracing using SFrame sections will be larger experiment which will > be hardware dependent.. > > https://lemire.me/blog/2012/05/31/data-alignment-for-speed-myth-or-reality/ I'm not so sure his example is good enough to show the overhead. So I wrote a much simpler test. I create an array of 1,000,004 unsigned longs and fill it with a simple increment. I then loop over the array and reading at every 5618 increments and modulus it to 1,000,000. I use 5816 because it is a factor of 1,000,004. By incrementing it by this number and modulus it with 1,000,000, then the wrap will go to 1,000,000 + 4. meaning by looping a 1,000,000 times on a 1,000,000 words should hit all of them if they are 4 byte long words or half of them if they are 8 byte words. I time a loop of going over all 1,000,000 numbers and simply adding them. I then report the total time. The test takes an offset to add before reading. Here's my results on two machines: On my workstation: Intel(R) Xeon(R) CPU E5-2620 v4 @ 2.10GHz $ ./aligned-access 0 val = 2296870857426500744 time = 6822 us $ ./aligned-access 1 val = -2296870857426996608 time = 7319 us $ ./aligned-access 2 val = 2296870857426500744 time = 7432 us $ ./aligned-access 3 val = -2296870857426996608 time = 7522 us $ ./aligned-access 4 val = 2296870857426500744 time = 6841 us On my server: Intel(R) Xeon(R) CPU E5-2683 v3 @ 2.00GHz $ ./aligned-access 0 val = 2296870857426500744 time = 7093 us $ ./aligned-access 1 val = -2296870857426996608 time = 6948 us $ ./aligned-access 2 val = 2296870857426500744 time = 6761 us $ ./aligned-access 3 val = -2296870857426996608 time = 7111 us $ ./aligned-access 4 val = 2296870857426500744 time = 6940 us $ ./aligned-access 5 val = -2296870857426996608 time = 6939 us $ ./aligned-access 6 val = 2296870857426500744 time = 6937 us $ ./aligned-access 7 val = -2296870857426996608 time = 7254 us $ ./aligned-access 8 val = 2296870857426500744 time = 6939 us My workstation is a bit older than my server, and it looks like alignment does make a difference. For my server, it didn't show any difference. Thus, it looks like it's only a problem for older machines (on x86). Would be good to see how the performance of this is on arm64 machines. But feel free to try it out yourself. -- Steve
aligned-access.c
(text/x-c++src, 1.9 KB)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
static char *argv0;
static char *get_this_name(void)
{
static char *this_name;
char *arg;
char *p;
if (this_name)
return this_name;
arg = argv0;
p = arg+strlen(arg);
while (p >= arg && *p != '/')
p--;
p++;
this_name = p;
return p;
}
static void usage(void)
{
char *p = get_this_name();
printf("usage: %s [alignement]\n"
" alignment is a number offset\n"
"\n",p);
exit(-1);
}
static void __vdie(const char *fmt, va_list ap, int err)
{
int ret = errno;
char *p = get_this_name();
if (err && errno)
perror(p);
else
ret = -1;
fprintf(stderr, " ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
exit(ret);
}
void die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__vdie(fmt, ap, 0);
va_end(ap);
}
void pdie(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__vdie(fmt, ap, 1);
va_end(ap);
}
static unsigned long long get_time(void)
{
unsigned long long time;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
time = ts.tv_sec * 1000000;
time += ts.tv_nsec / 1000;
return time;
}
#define ARRAY_SIZE 1000000
static void fill_array(void *array)
{
for (int i = 0; i < ARRAY_SIZE; i++) {
*(long *)(array + sizeof(long) * i) = i;
}
}
int main (int argc, char **argv)
{
unsigned long long start, end;
unsigned long long val = 0;
unsigned long long idx, i;
void *array;
int offset;
argv0 = argv[0];
if (argc < 2)
usage();
array = malloc((ARRAY_SIZE + 1) * sizeof(long));
if (!array)
pdie("Allocating array");
fill_array(array);
offset = atoi(argv[1]);
start = get_time();
for (i = 0; i < ARRAY_SIZE; i++) {
idx = (i * 5618) + offset;
idx %= 1000000;
val += *(unsigned long *)(array + idx);
}
end = get_time();
printf("val = %lld\n", val);
printf("time = %lld us\n", end - start);
return 0;
}