1 #include <unordered_set>
17 static std::set<volatile uint8_t *> page_set;
19 static size_t GB (1024*1024*1024);
20 static size_t GBDEC(1000*1000*1000);
25 //#define MAXPAGES ( 1.0*GBDEC/PAGE_SIZE)
26 #define MAXPAGES (60.0*GBDEC/PAGE_SIZE)
28 # define MAXPAGES std::numeric_limits<size_t>::max()
29 # define FREEPAGES (1.0*GBDEC/PAGE_SIZE)
32 static void stat(const char *msg) {
33 printf("%s: %zu=%zuGBDEC\n",msg,page_set.size(),page_set.size()*PAGE_SIZE/GBDEC);
36 static void eatmem() {
37 while (page_set.size()<MAXPAGES) {
38 void *const page(mmap(nullptr/*addr*/,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED|MAP_POPULATE,-1/*fd*/,0/*offset*/));
39 if (page==MAP_FAILED) {
45 printf("ulimit -l?\n");
46 stat(strerror(errno));
49 const auto pagecast(static_cast<volatile uint8_t *>(page));
51 const auto successpair(page_set.insert(pagecast));
52 assert(successpair.second);
57 static void freemem() {
59 for (size_t pageno=0;pageno<FREEPAGES;++pageno) {
60 const auto it(page_set.begin());
61 if (it==page_set.end()) {
62 printf("freemem: Not enough memory\n");
65 const auto page(const_cast<uint8_t *>(*it));
67 err=munmap(page,PAGE_SIZE);
76 const uint64_t from,to_excl;
77 Dimm(uint64_t from_,uint64_t to_excl_):from(from_),to_excl(to_excl_) {}
78 bool contains(volatile uint8_t *const page) const {
79 const uint64_t addr(reinterpret_cast<uint64_t>(page));
80 return from<=addr&&addr<to_excl;
84 static std::vector<Dimm> dimms;
86 static ssize_t dimmno_get_nocache(volatile uint8_t *const page) {
87 for (auto it=dimms.cbegin();it!=dimms.cend();++it) {
88 const auto &dimm(*it);
89 if (dimm.contains(page)) {
90 #if defined SEQUENTIAL
94 // return ((it-dimms.cbegin())&~3)+(seq%4);
97 return random()%dimms.size();
99 return it-dimms.cbegin();
100 // return dimms.size()-1-(it-dimms.cbegin());
101 // return ((it-dimms.cbegin())&~3)+(random()%4);
105 //printf("Cannot find a DIMM for: %p\n",page);
109 static ssize_t dimmno_get(volatile uint8_t *const page) {
110 static ssize_t cache_dimmno(0);
111 if (cache_dimmno==-1||!dimms[cache_dimmno].contains(page))
112 cache_dimmno=dimmno_get_nocache(page);
116 static size_t dimmno_to_cpuno(size_t dimmno) {
118 //return dimmno*std::thread::hardware_concurrency()/dimms.size();
121 static std::vector<std::unordered_set<volatile uint8_t *>> dimmno_to_pages;
123 static void readmap() {
124 std::vector<uint64_t> pagemapvec;
125 volatile uint8_t *const page_set_front(*page_set. cbegin());
126 volatile uint8_t *const page_set_back (*page_set.crbegin());
127 { const int fd(open("/proc/self/pagemap",O_RDONLY));
129 pagemapvec.resize((page_set_back-page_set_front)/PAGE_SIZE+1);
130 const size_t count(pagemapvec.size()*sizeof(uint64_t));
131 const ssize_t got(pread(fd,pagemapvec.data(),count,uintptr_t(page_set_front)/PAGE_SIZE*sizeof(uint64_t)));
132 assert(size_t(got)==count);
137 dimmno_to_pages.resize(dimms.size());
138 size_t bad_pfn_mask(0);
139 size_t bad_dimmno(0);
140 for (auto &it:page_set) {
141 volatile uint8_t *const page(it);
142 const uint64_t pagemapval(pagemapvec[(page-page_set_front)/PAGE_SIZE]);
143 //printf("%p=0x%016lx\n",page,pagemapval);
145 const uint64_t pfn_mask((1ULL<<55)-1); // Bits 0-54 page frame number (PFN) if present
146 if ((pagemapval&~pfn_mask)!=0x8600000000000000) {
150 const uint64_t pfn(pagemapval&pfn_mask);
151 const auto pfn_page(reinterpret_cast<volatile uint8_t *>(pfn*PAGE_SIZE));
152 const ssize_t dimmno(dimmno_get(pfn_page));
157 auto successpair(dimmno_to_pages[dimmno].insert(page));
158 assert(successpair.second);
160 printf("bad_pfn_mask: %zu\n",bad_pfn_mask);
161 printf("bad_dimmno: %zu\n",bad_dimmno );
162 for (size_t dimmno=0;dimmno<dimmno_to_pages.size();++dimmno) {
163 const Dimm &dimm(dimms[dimmno]);
164 const size_t cpuno(dimmno_to_cpuno(dimmno));
165 printf("DIMM %2zu, CPU %2zu: 0x%10" PRIx64 "-0x%10" PRIx64 "=%2g-%2gGB: %7zu pages\n",dimmno,cpuno,
166 dimm.from,dimm.to_excl,dimm.from/double(GB),dimm.to_excl/double(GB),
167 dimmno_to_pages[dimmno].size());
171 static void runthread(size_t dimmno) {
172 const std::unordered_set<volatile uint8_t *> &pages(dimmno_to_pages[dimmno]);
173 volatile size_t sum=0;
174 for (volatile uint8_t *const page:pages)
175 for (size_t offset=0;offset<PAGE_SIZE;offset+=64/8) // 64-bit FSB?
179 static void runthreads() {
180 const auto start(std::chrono::system_clock::now());
181 for (size_t loops=0;loops<10;++loops) {
182 std::vector<std::thread> threads;
183 for (size_t dimmno=0;dimmno<dimmno_to_pages.size();++dimmno) {
184 threads.push_back(std::thread(runthread,dimmno));
185 std::thread &thread(threads.back());
186 const size_t cpuno(dimmno_to_cpuno(dimmno));
187 cpu_set_t *const cpuset(CPU_ALLOC(cpuno+1));
189 size_t const cpuset_size(CPU_ALLOC_SIZE(cpuno+1));
190 CPU_ZERO_S(cpuset_size,cpuset);
191 CPU_SET_S(cpuno,cpuset_size,cpuset);
192 auto native(thread.native_handle());
194 err=pthread_setaffinity_np(native,cpuset_size,cpuset);
198 for (std::thread &thread:threads)
201 const auto end (std::chrono::system_clock::now());
202 printf("%zu ms\n",std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count());
205 static uint64_t strtouint64(const std::string &str) {
206 static_assert(sizeof(long)==sizeof(uint64_t),"!64-bit");
208 const long l(strtol(str.c_str(),&end,0/*base*/));
214 static void dmidecode() {
215 FILE *const f(popen("dmidecode -q -t 20","r"));
218 const auto uint64max(std::numeric_limits<uint64_t>::max());
219 uint64_t dimm_start(uint64max),dimm_end(uint64max);
220 char *linep(nullptr);
224 const ssize_t got(getline(&linep,&linen,f));
226 assert_perror(errno);
230 assert(size_t(got)==strlen(linep));
231 std::string line(linep);
234 assert(line.back()=='\n');
235 line.erase(line.length()-1);
236 if (line=="Memory Device Mapped Address") {
237 assert(dimmno==-1||dimm_end!=uint64max);
239 dimm_start=dimm_end=uint64max;
242 { const std::string start_str("\tStarting Address: ");
243 if (line.substr(0,start_str.length())==start_str) {
245 assert(dimm_start==uint64max);
246 dimm_start=strtouint64(line.substr(start_str.length()));
247 assert(dimm_start!=uint64max);
251 { const std::string end_str("\tEnding Address: ");
252 if (line.substr(0,end_str.length())==end_str) {
254 assert(dimm_end==uint64max);
255 dimm_end=strtouint64(line.substr(end_str.length()));
256 assert(dimm_end!=uint64max);
257 assert(dimm_start!=uint64max);
258 if (dimm_start>=2*GB)
262 dimms.push_back(Dimm(dimm_start,dimm_end));