custom-allocators
Custom allocator skill for memory allocation strategies. Use when implementing…
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology, binding processes with numactl, using libnuma API, building NUMA-aware data structures, or measuring remote access penalties. Activates on queries about numactl, libnuma, NUMA topology,
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill numa-programming --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/numa-programmingContext preview
The summary Claude sees to decide when to auto-load this skill.
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology, binding processes with numactl, using libnuma API, building NUMA-aware data structures, or measuring remote access penalties. Activates on queries about numactl, libnuma, NUMA topology,
name: numa-programming description: NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology, binding processes with numactl, using libnuma API, building NUMA-aware data structures, or measuring remote access penalties. Activates on queries about numactl, libnuma, NUMA topology, mbind, lstopo, or remote memory access.
Guide agents through NUMA-aware programming: topology detection with `numactl` and sysfs, libnuma API (`numa_alloc_onnode`, `mbind`, `set_mempolicy`), process binding with `numactl`, NUMA-aware data structures, remote access diagnosis with `perf stat`, and `lstopo` visualization.
# Hardware topology summary numactl --hardware # Detailed topology with distances lstopo --of console # sysfs nodes ls /sys/devices/system/node/ cat /sys/devices/system/node/node0/meminfo cat /sys/devices/system/node/node0/cpulist
Typical output:
available: 2 nodes (0-1) node 0 cpus: 0-15 node 0 size: 65536 MB node 1 cpus: 16-31 node 1 size: 65536 MB node distances: node 0 1 0: 10 21 1: 21 10
Distance 10 = local, higher = remote (cross-socket).
# Bind to node 0 CPUs and memory numactl --cpunodebind=0 --membind=0 ./myapp # Interleave memory across all nodes numactl --interleave=all ./myapp # Preferred node (fallback if full) numactl --preferred=0 ./myapp # Show process NUMA policy numactl --show cat /proc/self/numa_maps
#include <numa.h>
#include <numaif.h>
#include <stdio.h>
int main(void) {
if (numa_available() < 0) {
fprintf(stderr, "NUMA not available\n");
return 1;
}
int node = numa_node_of_cpu(0);
printf("CPU 0 on node %d\n", node);
// Allocate on specific node
size_t size = 1024 * 1024 * 1024;
void *mem = numa_alloc_onnode(size, 0);
if (!mem) return 1;
// Bind existing memory
unsigned long nodemask = 1UL << 0;
mbind(mem, size, MPOL_BIND, &nodemask, sizeof(nodemask) * 8, 0);
numa_free(mem, size);
return 0;
}gcc -o numa_test numa_test.c -lnuma
| API | Purpose | |-----|---------| | `numa_alloc_onnode` | Allocate on specific node | | `numa_alloc_local` | Allocate on current CPU's node | | `mbind` | Set policy on existing mapping | | `set_mempolicy` | Default policy for subsequent allocs | | `move_pages` | Migrate pages to target node |
// Per-node freelist — avoids cross-node synchronization
#define MAX_NODES 8
struct per_node_pool {
void *free_list[MAX_NODES];
int node_count;
};
void *pool_alloc_numa(struct per_node_pool *p) {
int node = numa_node_of_cpu(sched_getcpu());
void *blk = p->free_list[node];
if (blk) {
p->free_list[node] = *(void **)blk;
return blk;
}
return numa_alloc_onnode(BLOCK_SIZE, node);
}Pin threads to cores on the same node as their pool.
# Pin thread 0 to CPU 0 (node 0), allocate on node 0 numactl --cpunodebind=0 --membind=0 ./worker --id 0 numactl --cpunodebind=1 --membind=1 ./worker --id 1
#include <pthread.h> #include <sched.h> cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(target_cpu, &cpuset); pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
# Cache misses often spike with remote memory
perf stat -e cache-misses,cache-references,node-load-misses \
numactl --cpunodebind=0 --membind=1 ./myapp
# Compare local vs remote binding
perf stat numactl --cpunodebind=0 --membind=0 ./myapp
perf stat numactl --cpunodebind=0 --membind=1 ./myapp# NUMA hit/miss stats (if available) perf stat -e node-loads,node-load-misses,node-stores ./myapp
// Microbenchmark: touch 1GB on local vs remote node
clock_t start = clock();
for (size_t i = 0; i < size; i += 4096)
sum += ((char *)mem)[i];Expect 1.5–3x slowdown for remote access depending on interconnect (QPI/UPI/Infinity Fabric).
# Graphical (if X11) lstopo # Text with memory/PCI lstopo --of ascii # Export for documentation lstopo file.png
Shows: NUMA nodes, cores, caches, PCI devices — essential for DPDK NIC placement.
Poor scaling on multi-socket? ├── Check numactl --hardware ├── Verify thread and memory on same node ├── perf stat node-load-misses ├── Remote misses high? │ ├── numactl --membind=local │ └── Per-node data partitioning └── Still slow → memory bandwidth bound; reduce sharing
| Symptom | Cause | Fix | |---------|-------|-----| | OOM on one node despite free RAM elsewhere | MPOL_BIND too strict | Use `--preferred` or interleave | | 2x slower after scaling threads | Remote memory access | `numactl --membind` matching CPU node | | Inconsistent benchmark results | OS migrated pages | `mbind` MPOL_BIND; mlock if needed | | DPDK NIC on wrong socket | PCI far from CPU | `lstopo`; bind EAL to local socket | | libnuma not found | Package not installed | `apt install libnuma-dev` | | First-touch policy surprise | Alloc on node 0, run on node 1 | Allocate from bound thread |
A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.
Repo: mohitmishra786/low-level-dev-skills
Custom allocator skill for memory allocation strategies. Use when implementing…
AF_XDP skill for high-performance XDP sockets. Use when creating AF_XDP sockets, configuring…
DPDK skill for userspace packet I/O. Use when initializing EAL, configuring PMD drivers,…
io_uring skill for Linux async I/O. Use when building high-performance servers with liburing,…
Bare-metal ADC and DAC skill. Use when configuring analog sampling, DMA-driven ADC,…
Bare-metal startup skill for reset-to-main bring-up. Use when writing startup code, vector…