From a020069295b5dff3223fffde3ac080e729e9417b Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Sat, 19 Dec 2015 11:15:51 +0100 Subject: [PATCH] +src/memchannel.C --- src/memchannel.C | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 src/memchannel.C diff --git a/src/memchannel.C b/src/memchannel.C new file mode 100644 index 0000000..ac79d41 --- /dev/null +++ b/src/memchannel.C @@ -0,0 +1,280 @@ +#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(); +} -- 1.8.3.1