cache line locking on AMD x86_64 utilising L3 CAT pseudo-locking
26

Configure Feed

Select the types of activity you want to include in your feed.

icepick / src / main.c
7.7 kB 259 lines
1#define _GNU_SOURCE 2#include "internal.h" 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <getopt.h> 7 8static void usage(const char *prog) 9{ 10 fprintf(stderr, 11 "usage: %s <command> [options]\n\n" 12 "commands:\n" 13 " topology show cache topology and cat capabilities\n" 14 " lock lock a memory region into l3 cache\n" 15 " unlock release a locked region\n" 16 " status show current clos configuration\n" 17 " bench run latency benchmark\n\n" 18 "use '%s <command> --help' for command-specific options.\n", 19 prog, prog); 20} 21 22static size_t parse_size(const char *str) 23{ 24 char *end; 25 size_t val = strtoul(str, &end, 10); 26 if (*end == 'K' || *end == 'k') 27 val *= 1024; 28 else if (*end == 'M' || *end == 'm') 29 val *= 1024 * 1024; 30 else if (*end == 'G' || *end == 'g') 31 val *= 1024 * 1024 * 1024; 32 return val; 33} 34 35static int cmd_topology(int argc, char **argv) 36{ 37 (void)argc; 38 (void)argv; 39 40 icepick_topology_t *topo; 41 int ret = icepick_discover_topology(&topo); 42 if (ret < 0) { 43 fprintf(stderr, "failed to discover topology: %s\n", 44 icepick_strerror(ret)); 45 return 1; 46 } 47 48 printf("l3 cache:\n"); 49 printf(" total size: %zu mb\n", 50 icepick_topology_l3_size(topo) / (1024 * 1024)); 51 printf(" ways: %u\n", icepick_topology_l3_ways(topo)); 52 printf(" per-way size: %zu kb\n", 53 icepick_topology_way_size(topo) / 1024); 54 printf(" ccx count: %u\n\n", icepick_topology_ccx_count(topo)); 55 56 printf("cat configuration:\n"); 57 printf(" supported: %s\n", 58 icepick_topology_cat_supported(topo) ? "yes" : "no"); 59 printf(" max clos: %u\n\n", icepick_topology_max_clos(topo)); 60 61 size_t max_lockable = (icepick_topology_l3_ways(topo) - 1) * 62 icepick_topology_way_size(topo); 63 printf("maximum lockable: %zu mb (%u ways, reserving 1 for system)\n", 64 max_lockable / (1024 * 1024), icepick_topology_l3_ways(topo) - 1); 65 66 icepick_free_topology(topo); 67 return 0; 68} 69 70static int cmd_lock(int argc, char **argv) 71{ 72 size_t size = 0; 73 unsigned clos = 1; 74 int numa = -1; 75 bool verify = false; 76 bool huge = true; 77 78 static struct option long_options[] = { 79 {"size", required_argument, 0, 's'}, 80 {"clos", required_argument, 0, 'c'}, 81 {"numa", required_argument, 0, 'n'}, 82 {"verify", no_argument, 0, 'v'}, 83 {"no-huge", no_argument, 0, 'H'}, 84 {"help", no_argument, 0, 'h'}, 85 {0, 0, 0, 0} 86 }; 87 88 int opt; 89 while ((opt = getopt_long(argc, argv, "s:c:n:vHh", long_options, NULL)) != -1) { 90 switch (opt) { 91 case 's': size = parse_size(optarg); break; 92 case 'c': clos = atoi(optarg); break; 93 case 'n': numa = atoi(optarg); break; 94 case 'v': verify = true; break; 95 case 'H': huge = false; break; 96 case 'h': 97 printf("usage: icepick lock [options]\n\n" 98 "options:\n" 99 " -s, --size SIZE region size (e.g., 4M, 2048K)\n" 100 " -c, --clos ID clos id to use (1-15, default: 1)\n" 101 " -n, --numa NODE numa node (default: any)\n" 102 " -v, --verify verify lock after priming\n" 103 " -H, --no-huge don't use huge pages\n"); 104 return 0; 105 default: 106 return 1; 107 } 108 } 109 110 if (size == 0) { 111 fprintf(stderr, "error: --size is required\n"); 112 return 1; 113 } 114 115 icepick_topology_t *topo; 116 int ret = icepick_discover_topology(&topo); 117 if (ret < 0) { 118 fprintf(stderr, "failed to discover topology: %s\n", 119 icepick_strerror(ret)); 120 return 1; 121 } 122 123 printf("allocating region:\n"); 124 printf(" requested: %zu kb\n", size / 1024); 125 126 icepick_config_t cfg = { 127 .size = size, 128 .clos_id = clos, 129 .numa_node = numa, 130 .huge_pages = huge, 131 .verify = verify 132 }; 133 134 icepick_region_t *region; 135 ret = icepick_lock(topo, &cfg, &region); 136 if (ret < 0) { 137 fprintf(stderr, "lock failed: %s\n", icepick_strerror(ret)); 138 icepick_free_topology(topo); 139 return 1; 140 } 141 142 printf(" allocated: %zu kb\n", icepick_region_size(region) / 1024); 143 printf(" address: %p\n", icepick_region_ptr(region)); 144 printf(" clos: %u\n\n", icepick_region_clos(region)); 145 146 if (verify) { 147 icepick_latency_stats_t stats; 148 icepick_verify(region, &stats); 149 printf("verification:\n"); 150 printf(" mean latency: %lu ns\n", stats.mean_ns); 151 printf(" p99 latency: %lu ns\n", stats.p99_ns); 152 printf(" status: %s\n\n", 153 stats.mean_ns <= 50 ? "locked" : "warning - latency high"); 154 } 155 156 printf("region locked. press enter to unlock and exit...\n"); 157 getchar(); 158 159 icepick_unlock(region); 160 icepick_free_topology(topo); 161 printf("region unlocked.\n"); 162 163 return 0; 164} 165 166static int cmd_status(int argc, char **argv) 167{ 168 (void)argc; 169 (void)argv; 170 171 icepick_topology_t *topo; 172 int ret = icepick_discover_topology(&topo); 173 if (ret < 0) { 174 fprintf(stderr, "failed to discover topology: %s\n", 175 icepick_strerror(ret)); 176 return 1; 177 } 178 179 printf("clos configuration:\n"); 180 printf(" clos 0: 0x%04x (system default)\n", clos_get_default_mask()); 181 182 for (unsigned i = 1; i < icepick_topology_max_clos(topo); i++) { 183 if (clos_table[i].allocated) 184 printf(" clos %u: 0x%04x (allocated)\n", i, clos_table[i].way_mask); 185 } 186 187 icepick_free_topology(topo); 188 return 0; 189} 190 191static int cmd_bench(int argc, char **argv) 192{ 193 size_t size = 1024 * 1024; 194 size_t iterations = 1000000; 195 196 static struct option long_options[] = { 197 {"size", required_argument, 0, 's'}, 198 {"iterations", required_argument, 0, 'i'}, 199 {"help", no_argument, 0, 'h'}, 200 {0, 0, 0, 0} 201 }; 202 203 int opt; 204 while ((opt = getopt_long(argc, argv, "s:i:h", long_options, NULL)) != -1) { 205 switch (opt) { 206 case 's': size = parse_size(optarg); break; 207 case 'i': iterations = strtoul(optarg, NULL, 10); break; 208 case 'h': 209 printf("usage: icepick bench [options]\n\n" 210 "options:\n" 211 " -s, --size SIZE region size (default: 1M)\n" 212 " -i, --iterations NUM iteration count (default: 1000000)\n"); 213 return 0; 214 default: 215 return 1; 216 } 217 } 218 219 icepick_topology_t *topo; 220 int ret = icepick_discover_topology(&topo); 221 if (ret < 0) { 222 fprintf(stderr, "failed to discover topology: %s\n", 223 icepick_strerror(ret)); 224 return 1; 225 } 226 227 ret = bench_compare(topo, size, iterations); 228 icepick_free_topology(topo); 229 return ret < 0 ? 1 : 0; 230} 231 232int main(int argc, char **argv) 233{ 234 if (argc < 2) { 235 usage(argv[0]); 236 return 1; 237 } 238 239 const char *cmd = argv[1]; 240 argc--; 241 argv++; 242 243 if (strcmp(cmd, "topology") == 0) 244 return cmd_topology(argc, argv); 245 if (strcmp(cmd, "lock") == 0) 246 return cmd_lock(argc, argv); 247 if (strcmp(cmd, "status") == 0) 248 return cmd_status(argc, argv); 249 if (strcmp(cmd, "bench") == 0) 250 return cmd_bench(argc, argv); 251 if (strcmp(cmd, "--help") == 0 || strcmp(cmd, "-h") == 0) { 252 usage(argv[0]); 253 return 0; 254 } 255 256 fprintf(stderr, "unknown command: %s\n", cmd); 257 usage(argv[0]); 258 return 1; 259}