#include #include #include #include #include #include #include #include #include #define MEMSIZE (100*1024*1024) #define COUNT (MEMSIZE / sizeof(pt_entry_t)) #define __ATOMIC_PTR_CHECK(x) /* derp */ #define __BEGIN_ATOMIC_LOAD(p, v) \ __typeof__(*(p)) v = *(p) #define __END_ATOMIC_LOAD(v) \ v #define __DO_ATOMIC_STORE(p, v) \ *p = v #define atomic_load_relaxed(p) \ ({ \ const volatile __typeof__(*(p)) *__al_ptr = (p); \ __ATOMIC_PTR_CHECK(__al_ptr); \ __BEGIN_ATOMIC_LOAD(__al_ptr, __al_val); \ __END_ATOMIC_LOAD(__al_val); \ }) #define atomic_store_relaxed(p,v) \ ({ \ volatile __typeof__(*(p)) *__as_ptr = (p); \ __typeof__(*(p)) __as_val = (v); \ __ATOMIC_PTR_CHECK(__as_ptr); \ __DO_ATOMIC_STORE(__as_ptr, __as_val); \ }) typedef unsigned long pt_entry_t; struct cpu_info { pt_entry_t *ci_svs_updir; } _cpu_info; struct pmap { pt_entry_t *pm_pdir; } _pmap; static inline pt_entry_t svs_pte_atomic_read(struct pmap *pmap, size_t idx) { /* * XXX: We don't have a basic atomic_fetch_64 function? */ return atomic_cas_64(&pmap->pm_pdir[idx], 666, 666); } void copy_atomic(struct cpu_info *ci, struct pmap *pmap) { pt_entry_t pte; int i; /* User slots. */ for (i = 0; i < COUNT; i++) { pte = svs_pte_atomic_read(pmap, i); ci->ci_svs_updir[i] = pte; } } void copy_relaxed(struct cpu_info *ci, struct pmap *pmap) { pt_entry_t pte; int i; /* User slots. */ for (i = 0; i < COUNT; i++) { pte = atomic_load_relaxed(&pmap->pm_pdir[i]); atomic_store_relaxed(&ci->ci_svs_updir[i], pte); } } void copy_memcpy(struct cpu_info *ci, struct pmap *pmap) { memcpy(ci->ci_svs_updir, pmap->pm_pdir, MEMSIZE); } uint64_t gethrtime(void) { struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); return tp.tv_sec * 1000000000LL + tp.tv_nsec; } void testit(const char *name, void (*func)(struct cpu_info *, struct pmap *)) { uint64_t t; t = -gethrtime(); (*func)(&_cpu_info, &_pmap); t += gethrtime(); printf("%s\t%fMB per second\n", name, 100000000000.0 / t); } int main(int argc, char **argv) { size_t pgsz; off_t idx; printf("alloc\n"); _pmap.pm_pdir = mmap(NULL, MEMSIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (_pmap.pm_pdir == NULL) err(EXIT_FAILURE, "mmap 1"); _cpu_info.ci_svs_updir = mmap(NULL, MEMSIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (_cpu_info.ci_svs_updir == NULL) err(EXIT_FAILURE, "mmap 1"); pgsz = getpagesize(); printf("fault\n"); for (idx = 0; idx < COUNT; idx += pgsz / sizeof(pt_entry_t)) { _pmap.pm_pdir[idx] = 0; } for (idx = 0; idx < COUNT; idx += pgsz / sizeof(pt_entry_t)) { _cpu_info.ci_svs_updir[idx] = 0; } printf("run\n"); testit("atomic", copy_atomic); testit("relaxed", copy_relaxed); testit("memcpy", copy_memcpy); return 0; }