cache line locking on AMD x86_64 utilising L3 CAT pseudo-locking
1#define _GNU_SOURCE
2#include "internal.h"
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sched.h>
7
8int bench_compare(icepick_topology_t *topo, size_t size, size_t iterations)
9{
10 printf("running latency benchmark...\n\n");
11 printf("configuration:\n");
12 printf(" region size: %zu kb\n", size / 1024);
13 printf(" iterations: %zu\n", iterations);
14 printf(" access pattern: sequential, 64-byte stride\n\n");
15
16 void *unlocked_ptr;
17 int ret = region_alloc(size, -1, true, &unlocked_ptr);
18 if (ret < 0) {
19 ret = region_alloc(size, -1, false, &unlocked_ptr);
20 if (ret < 0) {
21 fprintf(stderr, "failed to allocate unlocked region: %s\n",
22 icepick_strerror(ret));
23 return ret;
24 }
25 }
26
27 icepick_latency_stats_t unlocked_stats;
28 ret = icepick_bench(unlocked_ptr, size, iterations, &unlocked_stats);
29 region_free(unlocked_ptr, size);
30
31 if (ret < 0) {
32 fprintf(stderr, "unlocked benchmark failed: %s\n", icepick_strerror(ret));
33 return ret;
34 }
35
36 printf("results (unlocked, clos 0):\n");
37 printf(" mean latency: %lu ns\n", unlocked_stats.mean_ns);
38 printf(" std deviation: %lu ns\n", unlocked_stats.stddev_ns);
39 printf(" p50: %lu ns\n", unlocked_stats.p50_ns);
40 printf(" p99: %lu ns\n", unlocked_stats.p99_ns);
41 printf(" p99.9: %lu ns\n\n", unlocked_stats.p999_ns);
42
43 icepick_config_t cfg = {
44 .size = size,
45 .clos_id = 1,
46 .numa_node = -1,
47 .huge_pages = true,
48 .verify = false
49 };
50
51 icepick_region_t *locked_region;
52 ret = icepick_lock(topo, &cfg, &locked_region);
53 if (ret < 0) {
54 fprintf(stderr, "failed to lock region: %s\n", icepick_strerror(ret));
55 fprintf(stderr, "(locked benchmark skipped)\n");
56 return 0;
57 }
58
59 icepick_latency_stats_t locked_stats;
60 ret = icepick_bench(icepick_region_ptr(locked_region),
61 icepick_region_size(locked_region),
62 iterations, &locked_stats);
63
64 printf("results (locked, clos 1):\n");
65 printf(" mean latency: %lu ns\n", locked_stats.mean_ns);
66 printf(" std deviation: %lu ns\n", locked_stats.stddev_ns);
67 printf(" p50: %lu ns\n", locked_stats.p50_ns);
68 printf(" p99: %lu ns\n", locked_stats.p99_ns);
69 printf(" p99.9: %lu ns\n\n", locked_stats.p999_ns);
70
71 icepick_unlock(locked_region);
72
73 if (ret == 0 && unlocked_stats.mean_ns > 0 && locked_stats.mean_ns > 0) {
74 printf("improvement:\n");
75 printf(" mean: %.1fx faster\n",
76 (double)unlocked_stats.mean_ns / locked_stats.mean_ns);
77 printf(" p99: %.1fx faster\n",
78 (double)unlocked_stats.p99_ns / locked_stats.p99_ns);
79 if (unlocked_stats.stddev_ns > 0 && locked_stats.stddev_ns > 0)
80 printf(" jitter: %.1fx reduction\n",
81 (double)unlocked_stats.stddev_ns / locked_stats.stddev_ns);
82 }
83
84 return 0;
85}