我想知道大文件的哪一部分缓存在内存中。我为此使用了fincore的一些代码,它是这样工作的:文件被映射,然后fincore循环访问地址空间并用mincore检查页面,但是由于文件大小(数TB),它非常长(数分钟) )。

有没有办法在使用过的RAM页面上循环?这样会更快,但是这意味着我应该从某个地方获取使用过的页面的列表...但是,我找不到一个方便的系统调用来允许这样做。

代码如下:

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
/* } */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/sysinfo.h>


void
fincore(char *filename) {
   int fd;
   struct stat st;

   struct sysinfo info;
   if (sysinfo(& info)) {
    perror("sysinfo");
    return;
   }

   void *pa = (char *)0;
   char *vec = (char *)0;
   size_t pageSize = getpagesize();
   register size_t pageIndex;

   fd = open(filename, 0);
   if (0 > fd) {
      perror("open");
      return;
   }

   if (0 != fstat(fd, &st)) {
      perror("fstat");
      close(fd);
      return;
   }

   pa = mmap((void *)0, st.st_size, PROT_NONE, MAP_SHARED, fd, 0);
   if (MAP_FAILED == pa) {
      perror("mmap");
      close(fd);
      return;
   }

   /* vec = calloc(1, 1+st.st_size/pageSize); */
   /* 2.2 sec for 8 TB */
   vec = calloc(1, (st.st_size+pageSize-1)/pageSize);
   if ((void *)0 == vec) {
      perror("calloc");
      close(fd);
      return;
   }

    /* 48 sec for 8 TB */
   if (0 != mincore(pa, st.st_size, vec)) {
      fprintf(stderr, "mincore(%p, %lu, %p): %s\n",
              pa, (unsigned long)st.st_size, vec, strerror(errno));
      free(vec);
      close(fd);
      return;
   }

   /* handle the results */
   /* 2m45s for 8 TB */
   for (pageIndex = 0; pageIndex <= st.st_size/pageSize; pageIndex++) {
      if (vec[pageIndex]&1) {
         printf("%zd\n", pageIndex);
      }
   }

   free(vec);
   vec = (char *)0;

   munmap(pa, st.st_size);
   close(fd);

   return;
}

int main(int argc, char *argv[]) {
    fincore(argv[1]);

    return 0;
}

最佳答案

对于悲观的情况,当所有或几乎所有页面确实都在RAM中时,表示列表所需的信息量比位图高得多-每个条目至少64位对1位。如果有这样的API,则在查询约20亿页时,您将必须准备好在答复中获得16 GB的数据。此外,处理可变长度结构(例如列表)比处理固定长度数组要复杂得多,因此库函数(尤其是低级系统函数)倾向于避免麻烦。

我也不太确定实现方式(在这种情况下,操作系统如何与TLB和Co交互),但由于(由于大小不同,填充位图的速度可能比创建列表更快)(即使不考虑大小差异)从中提取信息的操作系统和硬件级别的结构。

如果您不关心非常精细的粒度,则可以看看/proc/<PID>/smaps。对于每个映射区域,它都会显示一些统计信息,包括将多少内存加载到内存中(Rss字段)。如果出于调试目的,您使用单独的mmap()调用映射了文件的某些区域(除了用于执行实际任务的主映射),您可能会在smaps中获得单独的条目,因此可以看到这些区域的单独统计信息。几乎可以肯定的是,如果不破坏系统,就无法进行数十亿次的映射,但是如果文件结构合理,也许只有几十个精心挑选的区域具有单独的统计信息可以帮助您找到所需的答案。

08-16 23:21