#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static std::set page_set; static size_t GB (1024*1024*1024); static size_t GBDEC(1000*1000*1000); //#define SEQUENTIAL //#define RANDOM //#define MAXPAGES ( 1.0*GBDEC/PAGE_SIZE) #define MAXPAGES (60.0*GBDEC/PAGE_SIZE) #ifndef MAXPAGES # define MAXPAGES std::numeric_limits::max() # define FREEPAGES (1.0*GBDEC/PAGE_SIZE) #endif static void stat(const char *msg) { printf("%s: %zu=%zuGBDEC\n",msg,page_set.size(),page_set.size()*PAGE_SIZE/GBDEC); } static void eatmem() { while (page_set.size()(page)); *pagecast=0x55; const auto successpair(page_set.insert(pagecast)); assert(successpair.second); } stat("MAXPAGES"); } static void freemem() { #ifdef FREEPAGES for (size_t pageno=0;pageno(*it)); int err; err=munmap(page,PAGE_SIZE); assert(!err); } stat("freemem"); #endif } class Dimm { public: const uint64_t from,to_excl; Dimm(uint64_t from_,uint64_t to_excl_):from(from_),to_excl(to_excl_) {} bool contains(volatile uint8_t *const page) const { const uint64_t addr(reinterpret_cast(page)); return from<=addr&&addr dimms; static ssize_t dimmno_get_nocache(volatile uint8_t *const page) { for (auto it=dimms.cbegin();it!=dimms.cend();++it) { const auto &dimm(*it); if (dimm.contains(page)) { #if defined SEQUENTIAL static size_t seq=0; ++seq; seq%=dimms.size(); // return ((it-dimms.cbegin())&~3)+(seq%4); return seq; #elif defined RANDOM return random()%dimms.size(); #else return it-dimms.cbegin(); // return dimms.size()-1-(it-dimms.cbegin()); // return ((it-dimms.cbegin())&~3)+(random()%4); #endif } } //printf("Cannot find a DIMM for: %p\n",page); return -1; } static ssize_t dimmno_get(volatile uint8_t *const page) { static ssize_t cache_dimmno(0); if (cache_dimmno==-1||!dimms[cache_dimmno].contains(page)) cache_dimmno=dimmno_get_nocache(page); return cache_dimmno; } static size_t dimmno_to_cpuno(size_t dimmno) { return 2*dimmno; //return dimmno*std::thread::hardware_concurrency()/dimms.size(); } static std::vector> dimmno_to_pages; static void readmap() { std::vector pagemapvec; volatile uint8_t *const page_set_front(*page_set. cbegin()); volatile uint8_t *const page_set_back (*page_set.crbegin()); { const int fd(open("/proc/self/pagemap",O_RDONLY)); assert(fd!=-1); pagemapvec.resize((page_set_back-page_set_front)/PAGE_SIZE+1); const size_t count(pagemapvec.size()*sizeof(uint64_t)); const ssize_t got(pread(fd,pagemapvec.data(),count,uintptr_t(page_set_front)/PAGE_SIZE*sizeof(uint64_t))); assert(size_t(got)==count); int err; err=close(fd); assert(!err); } dimmno_to_pages.resize(dimms.size()); size_t bad_pfn_mask(0); size_t bad_dimmno(0); for (auto &it:page_set) { volatile uint8_t *const page(it); const uint64_t pagemapval(pagemapvec[(page-page_set_front)/PAGE_SIZE]); //printf("%p=0x%016lx\n",page,pagemapval); // vm/pagemap.txt const uint64_t pfn_mask((1ULL<<55)-1); // Bits 0-54 page frame number (PFN) if present if ((pagemapval&~pfn_mask)!=0x8600000000000000) { ++bad_pfn_mask; continue; } const uint64_t pfn(pagemapval&pfn_mask); const auto pfn_page(reinterpret_cast(pfn*PAGE_SIZE)); const ssize_t dimmno(dimmno_get(pfn_page)); if (dimmno==-1) { ++bad_dimmno; continue; } auto successpair(dimmno_to_pages[dimmno].insert(page)); assert(successpair.second); } printf("bad_pfn_mask: %zu\n",bad_pfn_mask); printf("bad_dimmno: %zu\n",bad_dimmno ); for (size_t dimmno=0;dimmno &pages(dimmno_to_pages[dimmno]); volatile size_t sum=0; for (volatile uint8_t *const page:pages) for (size_t offset=0;offset threads; for (size_t dimmno=0;dimmno(end-start).count()); } static uint64_t strtouint64(const std::string &str) { static_assert(sizeof(long)==sizeof(uint64_t),"!64-bit"); char *end; const long l(strtol(str.c_str(),&end,0/*base*/)); assert(l>=0); assert(*end==0); return l; } static void dmidecode() { FILE *const f(popen("dmidecode -q -t 20","r")); assert(f); ssize_t dimmno(-1); const auto uint64max(std::numeric_limits::max()); uint64_t dimm_start(uint64max),dimm_end(uint64max); char *linep(nullptr); size_t linen(0); for (;;) { errno=0; const ssize_t got(getline(&linep,&linen,f)); if (got==-1) { assert_perror(errno); break; } assert(got>=0); assert(size_t(got)==strlen(linep)); std::string line(linep); if (got==0) break; assert(line.back()=='\n'); line.erase(line.length()-1); if (line=="Memory Device Mapped Address") { assert(dimmno==-1||dimm_end!=uint64max); ++dimmno; dimm_start=dimm_end=uint64max; continue; } { const std::string start_str("\tStarting Address: "); if (line.substr(0,start_str.length())==start_str) { assert(dimmno>=0); assert(dimm_start==uint64max); dimm_start=strtouint64(line.substr(start_str.length())); assert(dimm_start!=uint64max); continue; } } { const std::string end_str("\tEnding Address: "); if (line.substr(0,end_str.length())==end_str) { assert(dimmno>=0); assert(dimm_end==uint64max); dimm_end=strtouint64(line.substr(end_str.length())); assert(dimm_end!=uint64max); assert(dimm_start!=uint64max); if (dimm_start>=2*GB) dimm_start+=2*GB; if (dimm_end>=2*GB) dimm_end+=2*GB; dimms.push_back(Dimm(dimm_start,dimm_end)); continue; } } } free(linep); int err; err=fclose(f); assert(!err); } int main() { setbuf(stdout,NULL); dmidecode(); eatmem(); freemem(); readmap(); runthreads(); }