Linux(非透明)每个进程的大页面记帐

Linux(非透明)每个进程的大页面记帐

我最近将一些 Java 应用程序转换为使用 Linux 手动配置的大页面运行,如下所述这里。我指出“手动配置”,因为它们不是 透明大页面,这给了我们一些性能问题

所以现在,我在系统上运行了大约 10 个 tomcat,我想知道每个 tomcat 使用了多少内存。

/proc/meminfo我可以按照所述获取摘要信息Linux 大页面使用情况统计

但是我找不到任何可以告诉我每个进程的实际大页面使用情况的工具。

我仔细查看了一下/proc/pid/numa_stat,发现了一些有趣的信息,这些信息让我看到了这一令人恶心的事情:

function pshugepage () {
    HUGEPAGECOUNT=0
    for num in `grep 'anon_hugepage.*dirty=' /proc/$@/numa_maps | awk '{print $6}' | sed 's/dirty=//'` ; do
        HUGEPAGECOUNT=$((HUGEPAGECOUNT+num))
    done
    echo process $@ using $HUGEPAGECOUNT huge pages
}

或者用 perl 写成这样:

sub counthugepages {
    my $pid=$_[0];
    open (NUMAMAPS, "/proc/$pid/numa_maps") || die "can't open numa_maps";
    my $HUGEPAGECOUNT=0;
    while (my $line=<NUMAMAPS>) {
        next unless ($line =~ m{ huge }) ;
        next unless ($line =~ m{dirty=});
        chomp $line;
        $line =~ s{.*dirty=}{};
        $line =~ s{\s.*$}{};
        $HUGEPAGECOUNT+=$line;
    }
    close NUMAMAPS;
    # we want megabytes out, but we counted 2-megabyte hugepages
    return ($HUGEPAGECOUNT*2);
}

它给我的数字是合理的,但我并不确信这种方法是否正确。

环境是四 CPU 戴尔、64GB RAM、RHEL6.3、Oracle JDK 1.7.x(截至 20130728 年的最新版本)

答案1

更新:Red Hat 现在推荐这种方法对于 RHEL5/6 上的进程大页面记帐:

grep -B 11 'KernelPageSize:     2048 kB' /proc/[PID]/smaps \
   | grep "^Size:" \
   | awk 'BEGIN{sum=0}{sum+=$2}END{print sum/1024}'

我在 procps-ng 开发人员邮件列表中询问了这个问题。他们告诉我:

几个月前,procps-ng/pmap 工具中引入了 hugepage 支持(开关 -XX、-C、-c、-N、-n 应该允许您配置和显示正在运行的内核支持的任何条目)。

我在 Fedora 19 上使用 procps-3.3.8 对此进行了一些实验。我认为它没有给我提供我在问题中所建议的内容中没有得到的任何信息,但至少它具有权威的光环。

FWIW我最终得到以下结果:

.pmaprc 文件包含:

[Fields Display]
Size
Rss
Pss
Referenced
AnonHugePages
KernelPageSize
Mapping

[Mapping]
ShowPath

然后我使用以下命令来提取大页面信息:

pmap -c [process id here] | egrep 'Add|2048'

在 grep 中,“Add”用于标题行。“2048”将抓取内核页面大小为 2048 的任何内容,即大页面。它还将抓取不相关的内容。

以下是一些示例输出:

     Address    Size   Rss   Pss Referenced AnonHugePages KernelPageSize Mapping
    ed800000   22528     0     0          0             0           2048 /anon_hugepage (deleted)
    f7e00000   88064     0     0          0             0           2048 /anon_hugepage (deleted)
    fd400000   45056     0     0          0             0           2048 /anon_hugepage (deleted)
7f3753dff000    2052  2048  2048       2048          2048              4 [stack:1674]
7f3759000000    4096     0     0          0             0           2048 /anon_hugepage (deleted)
7f3762d68000    2048     0     0          0             0              4 /usr/lib64/libc-2.17.so
7f376339b000    2048     0     0          0             0              4 /usr/lib64/libpthread-2.17.so

我们只关心 kernelPageSize 为 2048 的行。

我认为它告诉我,我已经在大页面中分配了 159744 KB(22528+88064+45056+4096)的 RAM。我告诉 Java 为其堆使用 128M,并且它有一些其他内存池,因此这是一个合理的数字。Rss & Referenced 0 不太合理,但是测试 Java 程序非常简单,因此它也是合理的。

它与我从上面的 perl 代码片段中获得的数字不一致,因为 perl 只搜索“脏”页面 - 那些实际被使用过的页面。或者是因为 perl 本身就是错误的,我不知道。

我还在一台 RHEL6 机器上尝试了 procps 3.3.9,其中有一些活动的 tomcat 使用了大量大页面内存。Rss 和 Referenced 列全部为 0。这很可能是内核的错误,而不是 procps 的错误,我不知道。

答案2

改进的 perl 脚本

#!/usr/bin/perl
#
sub counthugepages {
    my $pid=$_[0];
    open (NUMAMAPS, "/proc/$pid/numa_maps") || die "can't open numa_maps";
    my $HUGEPAGECOUNT=0;
    while (<NUMAMAPS>) {
        if (/huge.*dirty=(\d+)/) {
          $HUGEPAGECOUNT+=$1;
        }
    }
    close NUMAMAPS;
    return ($HUGEPAGECOUNT);
}

printf "%d huge pages\n",counthugepages($ARGV[0]);

相关内容