【问题标题】:Determine if an allocation via malloc() is backed by a huge page确定通过 malloc() 进行的分配是否由大页面支持
【发布时间】:2014-08-26 05:00:24
【问题描述】:

我非常了解transparent hugepages 的工作原理,并且任何分配,例如由malloc 执行的分配,都可以通过大页面来满足。

我想知道的是,在分配后是否可以进行任何检查(可能是启发式的)以确定内存是否由大页面支持。

【问题讨论】:

  • 我猜你可以在/proc/中使用一些[pseudo-]文件;也许在/proc/self/maps 中可以看到巨大的地图 ....
  • proc(5) 提到/proc/self/smaps 有AnonHugePages 和VmFlags: ht ...
  • 为了将来参考,即使在具有大量 RAM 的机器上,我发现 echo always > /sys/kernel/mm/transparent_hugepage/defrag(在 /etc/rc.local 或其他中)在大分配的实际页数方面有很大的不同如果您没有专门使用madvise(MADV_HUGEPAGE),最终会变成 2M 大页面(在/proc/PID/smaps 中)。使用 defrag=always,几乎所有可以使用大页面的分配确实使用大页面。 (所以这可能是一个好主意,除非您的工作负载涉及大量映射/取消映射而不触及大部分内存,尤其是有足够的 RAM 以降低碎片整理成本。)

标签: c++ linux performance x86 huge-pages


【解决方案1】:

您可以通过在@中查找“pfn”(页框号)来确定任何页面的确切状态,包括它是否由透明(或非透明)大页面支持987654324@ 文件。您可以通过读取进程的 /proc/$PID/pagemap 文件来获取页面的 pfn,该文件由虚拟地址索引。

不幸的是,pagemap1 中的 pfn 值和整个 /proc/kpageflags 文件都只能由 root 用户访问。不过,如果您至少可以在您感兴趣的测试或基准测试场景中以 root 身份运行您的流程,那么这很有效。

我写了一个small library called page-info 为你做相关的解析。给它一定的内存范围,它会返回每个页面的信息,包括它是否存在于内存中、是否由大页面支持等。

例如,以sudo ./page-info-test THP 运行包含的测试进程会得到以下输出:

PAGE_SIZE = 4096, PID = 18868
       size memset       FLAG     SET   UNSET UNAVAIL
   0.25 MiB BEFORE        THP       0       1      64
   0.25 MiB AFTER         THP       0      65       0
   0.50 MiB BEFORE        THP       0       1     128
   0.50 MiB AFTER         THP       0     129       0
   1.00 MiB BEFORE        THP       0       1     256
   1.00 MiB AFTER         THP       0     257       0
   2.00 MiB BEFORE        THP       0       1     512
   2.00 MiB AFTER         THP       0     513       0
   4.00 MiB BEFORE        THP       0       1    1024
   4.00 MiB AFTER         THP     512     513       0
   8.00 MiB BEFORE        THP       0       1    2048
   8.00 MiB AFTER         THP    1536     513       0
  16.00 MiB BEFORE        THP       0       1    4096
  16.00 MiB AFTER         THP    3584     513       0
  32.00 MiB BEFORE        THP       0       1    8192
  32.00 MiB AFTER         THP    7680     513       0
  64.00 MiB BEFORE        THP       0       1   16384
  64.00 MiB AFTER         THP   15872     513       0
 128.00 MiB BEFORE        THP       0       1   32768
 128.00 MiB AFTER         THP   32256     513       0
 256.00 MiB BEFORE        THP       0       1   65536
 256.00 MiB AFTER         THP   65024     513       0
 512.00 MiB BEFORE        THP       0       1  131072
 512.00 MiB AFTER         THP  124416    6657       0
1024.00 MiB BEFORE        THP       0       1  262144
1024.00 MiB AFTER         THP       0  262145       0
DONE

UNAVAIL 列表示没有可用的映射信息 - 通常是因为该页面从未被访问过,因此根本没有任何页面支持。您可以看到,对于这些“较大”的分配,在分配之后只映射了一个页面,因为我们没有触及内存。

AFTER 行是在整个分配上调用memset() 后的相同信息,这会导致所有页面都被物理分配。在这里,我们可以看到透明大页不支持任何分配,直到我们达到 4 MiB 的分配,此时每个分配的大部分都由 THP 支持,除了 513 个页面(结果位于分配区域的边缘)。在 512 MiB 时,系统开始用尽可用的大页面,但仍满足大部分分配,但在 1024 MiB 时,整个分配都满足小页面。

这个库还没有准备好生产所以不要将它用于任何关键的事情(例如,一些失败只是调用exit())。欢迎投稿。


1 大约从内核 4.0 开始,在此之前,非 root 用户进程可以访问 pfn。从 4.0 到 4.1 左右,整个 pagemap 都禁止非 root 进程使用,但此后该文件再次可用,但 pfn 被屏蔽(它将始终显示为零)。

【讨论】:

  • 您可以通过在/proc/self/smaps 中找到它的条目并检查AnonHugePages: 是否与Rss: 匹配来检查您的整个映射是否使用anon hugepages(向下舍入为2M 的倍数) .这不能告诉你哪个部分没有使用大页面,但是对于正在运行的进程的手动外部检查,它几乎可以告诉你你想知道什么。
  • 我也看过这种方法,但它非常有限,除非你想知道“这个程序是否主要使用大页面”,因为它适用于整个映射。例如,malloc 经常创建满足许多分配的大型映射。如果您正在做自己的映射,或者使用malloc 分配超过分配器中“仅mmap 整个分配”阈值的大区域,它确实工作得很好,因此它可能是非根的合理回退过程。我想知道一个特定的缓冲区是否实际上分配有大页面。
  • smaps 技术的一个改进是在触摸所有页面之前和之后查看包含您感兴趣的区域的映射。如果这导致映射中分配的页面增长,您可以通过增量确定它们是什么类型的页面。显然,这在多线程程序中不太可靠。类似的东西是suggested here。
  • 在我的用例中,分配足够大,以至于 glibc 为 malloc / posix_memalign() 分配单独的 mmap。 (对 2M 和更大的分配使用 2M 对齐似乎是一个好主意,让它可以使用至少一个大页面。)
  • 我用自包含代码编写了一个教程来检查这一点:mazzo.li/posts/check-huge-page.html
【解决方案2】:

传统的大页面和透明大页面 (THP) 之间存在差异。在 THP 的情况下,应用程序可以在没有任何开发人员支持(mmap、shmget 等)或系统管理员干预的情况下使用大页面。

在代码中,恐怕没有直接的方法来检查这个。但是,如果您知道 sizeof() 分配的数据结构或缓冲区,则值得使用以下命令 grepping 并检查系统上的 THP 使用情况。在运行您的应用程序时,这种使用量应该会增加:

# grep AnonHugePages /proc/meminfo
AnonHugePages:   2648064 kB

【讨论】:

    猜你喜欢
    • 2010-10-29
    • 2022-11-07
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    • 2021-03-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多