linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Keiichi KII <k-keiichi@bx.jp.nec.com>
To: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Cc: Keiichi KII <k-keiichi@bx.jp.nec.com>,
	Ingo Molnar <mingo@elte.hu>,
	"linux-mm@kvack.org" <linux-mm@kvack.org>,
	Tom Zanussi <tzanussi@gmail.com>,
	"riel@redhat.com" <riel@redhat.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Fr??d??ric Weisbecker <fweisbec@gmail.com>,
	Wu Fengguang <fengguang.wu@intel.com>,
	"BA, Moussa" <Moussa.BA@numonyx.com>
Subject: [RFC PATCH -tip 5/5] perf tools: scripts for continuous pagecache monitoring
Date: Mon, 18 Jul 2011 17:40:03 -0400	[thread overview]
Message-ID: <4E24A833.2090208@bx.jp.nec.com> (raw)
In-Reply-To: <4E24A61D.4060702@bx.jp.nec.com>

From: Keiichi Kii <k-keiichi@bx.jp.nec.com>

The "continuous pagecache monitoring" is implemented based on
"pagecache tracepoints" and the trace stream scripting support
in perf tools.

To monitor dynamic changes for pagecaches,
we can run "perf script pagecachetop {file|process}".
ex) perf script pagecachetop file
    => monitor pagecache behavior on the basis of file

This tool shows two types of the output.

o One is to show pagecache behavior on the basis of "file"

pagecache behavior per file (time:20207, interval:10)

                         find        hit    cache      add   remove  proc
                file    count      ratio pages(B) pages(B) pages(B) count
-------------------- -------- ---------- -------- -------- -------- -----
            Packages    32813    100.00%    69.5M        0        0     1
190919419ab3582cb090    30677    100.00%    37.6M        0        0     1
2d3f2307106003b599d2    10715    100.00%    17.0M        0        0     1
29fe4f91d89bab54d355     5545    100.00%     7.1M        0        0     1
c5ee54fd83797583e6c2     1823    100.00%     2.6M        0        0     1
        libc-2.13.so      830    100.00%     1.2M        0        0     9
            __db.003      540    100.00%     1.3M        0        0     1
8faff879329920b2638a      439    100.00%     1.4M        0        0     1
1b695937ce00a8c305ee      352    100.00%     1.5M        0        0     1
 libpython2.7.so.1.0      330    100.00%     1.5M        0        0     1
                bash      283    100.00%   828.0K        0        0     6
         ld.so.cache      227    100.00%   116.0K        0        0     5
        .zsh_history      196    100.00%   772.0K        0        0     1
fdc15d6feaec65abbfae      196    100.00%   464.0K        0        0     1
3b316befdc0469fa84b7      192    100.00%   324.0K        0        0     1

o The other is to show pagecache behaviors on the basis of "process"

pagecache behavior per process (time:20160, interval:10)

                         find        hit      add   remove  file
             process    count      ratio pages(B) pages(B) count
-------------------- -------- ---------- -------- -------- -----
            yum-9006    97210     99.25%    99.9M        0    40
           xmms-7768       43    100.00%   128.0K        0     1
          crond-1307        8    100.00%        0        0     1
       rsyslogd-7194        1    100.00%        0        0     1

Signed-off-by: Keiichi Kii <k-keiichi@bx.jp.nec.com>
---

 tools/perf/scripts/perl/bin/pagecachetop-record |    3 
 tools/perf/scripts/perl/bin/pagecachetop-report |   21 ++
 tools/perf/scripts/perl/pagecachetop.pl         |  292 +++++++++++++++++++++++
 3 files changed, 316 insertions(+), 0 deletions(-)
 create mode 100644 tools/perf/scripts/perl/bin/pagecachetop-record
 create mode 100644 tools/perf/scripts/perl/bin/pagecachetop-report
 create mode 100644 tools/perf/scripts/perl/pagecachetop.pl


diff --git a/tools/perf/scripts/perl/bin/pagecachetop-record b/tools/perf/scripts/perl/bin/pagecachetop-record
new file mode 100644
index 0000000..2c05539
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/pagecachetop-record
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+perf record -D -e filemap:find_get_page -e filemap:add_to_page_cache -e filemap:remove_from_page_cache -e mm:dump_inode --filter "nrpages>10" $@
diff --git a/tools/perf/scripts/perl/bin/pagecachetop-report b/tools/perf/scripts/perl/bin/pagecachetop-report
new file mode 100644
index 0000000..62c54bb
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/pagecachetop-report
@@ -0,0 +1,21 @@
+#!/bin/bash
+# description: continuous pagecache monitoring per file
+
+for i in "$@"
+do
+    if expr match "$i" "-" > /dev/null; then
+        break
+    fi
+    n_args=$(( $n_args + 1 ))
+done
+
+if [ "$n_args" -eq 1 ] ; then
+    mode=$1
+    shift
+else
+    echo "usage: pagecachetop {file|process}"
+    echo $@
+    exit
+fi
+
+perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/pagecachetop.pl $mode
diff --git a/tools/perf/scripts/perl/pagecachetop.pl b/tools/perf/scripts/perl/pagecachetop.pl
new file mode 100644
index 0000000..ec77f89
--- /dev/null
+++ b/tools/perf/scripts/perl/pagecachetop.pl
@@ -0,0 +1,292 @@
+#!/usr/bin/perl -w
+# (C) 2011, Keiichi Kii <k-keiichi@bx.jp.nec.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+# pagecache top
+#
+# Periodically display system-wide pagecache activity focusing on
+# process or file. If "process" arg is specified, it displays
+# pagecache behavior per each process. If "file" arg is specified,
+# it displays pagecache behavior per each file.
+
+use 5.010000;
+use strict;
+use warnings;
+
+use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
+use lib "./Perf-Trace-Util/lib";
+use Perf::Trace::Core;
+use Perf::Trace::Context;
+use Perf::Trace::Util;
+use File::Basename qw/basename/;
+
+my %files;
+my %processes;
+my $interval = 10;
+my $pre_print_time = 0;
+my $print_limit = 20;
+my $debugfs_mountpoint;
+my $mode = shift;
+
+sub trace_begin {
+    $debugfs_mountpoint = find_debugfs_mntpt();
+}
+
+sub find_debugfs_mntpt() {
+    my $path = "";
+    open my $fh, "<", "/proc/mounts"
+        or die "Can't open /proc/mounts: $!";
+    while (my $l = <$fh>) {
+        if ($l =~ /debugfs/) {
+            $path = (split(/\s/, $l))[1];
+        }
+    }
+    close($fh);
+    return $path;
+}
+
+sub mm::dump_inode {
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+        $common_pid, $common_comm,
+        $ino, $size, $nrpages, $age, 
+        $state, $dev, $file) = @_;
+
+    my $f = get_file($dev, $ino);
+    return if !$f;
+
+    $$f{path} = $file;
+    $$f{cache} = $nrpages;
+}
+
+sub filemap::remove_from_page_cache {
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+        $common_pid, $common_comm,
+        $s_dev, $i_ino, $offset) = @_;
+
+    my $s = get_stat($common_pid, $common_comm, $s_dev, $i_ino);
+    return if !$s;
+
+    $$s{remove}++;
+    print_check($common_secs);
+}
+
+sub filemap::add_to_page_cache {
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+        $common_pid, $common_comm,
+        $s_dev, $i_ino, $offset) = @_;
+
+    my $s = get_stat($common_pid, $common_comm, $s_dev, $i_ino);
+    return if !$s;
+
+    $$s{add}++;
+    print_check($common_secs);
+}
+
+sub filemap::find_get_page {
+    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
+        $common_pid, $common_comm,
+        $s_dev, $i_ino, $offset, $page) = @_;
+
+    my $s = get_stat($common_pid, $common_comm, $s_dev, $i_ino);
+    return if !$s;
+
+    $$s{find}++;
+    if ($page != 0) {
+        $$s{hit}++;
+    }
+
+    print_check($common_secs);
+}
+
+sub get_file {
+    my ($dev, $inode) = @_;
+
+    return if major($dev) == 0;
+
+    if (!defined($files{$dev.":".$inode})) {
+        $files{$dev.":".$inode} = init_file($dev, $inode);
+    }
+
+    return $files{$dev.":".$inode};
+}
+
+sub get_stat {
+    my ($pid, $cmd, $dev, $inode) = @_;
+    my %stat = (find => 0, hit => 0, add => 0, remove => 0);
+
+    return if major($dev) == 0;
+
+    if (!defined($processes{$pid})) {
+        $processes{$pid} = init_process($pid, $cmd);
+    }
+    if (!defined($files{$dev.":".$inode})) {
+        $files{$dev.":".$inode} = init_file($dev, $inode);
+    }
+    if (!defined($processes{$pid}{file}{$dev.":".$inode})) {
+        $files{$dev.":".$inode}{process}{$pid} = \%stat;
+        $processes{$pid}{file}{$dev.":".$inode} = \%stat;
+        return \%stat;
+    }
+    return $files{$dev.":".$inode}{process}{$pid};
+}
+
+sub init_file() {
+    my ($dev, $inode) = @_;
+    my %f;
+
+    $f{path} = major($dev).":".minor($dev).",".$inode;
+    $f{cache} = 0;
+    $f{stat} = {find => 0, hit => 0, add => 0, remove => 0};
+    $f{process} = {};
+
+    return \%f;
+}
+
+sub init_process() {
+    my ($pid, $cmd) = @_;
+    my %p;
+
+    $p{name} = $cmd."-".$pid;
+    $p{stat} = {find => 0, hit => 0, add => 0, remove => 0};
+    $p{file} = {};
+
+    return \%p;
+}
+
+sub print_check() {
+    my $cur_sec = shift;
+
+    if ($pre_print_time == 0) {
+        $pre_print_time = $cur_sec;
+        return
+    }
+    if ($cur_sec - $pre_print_time > $interval) {
+        dump_fs_pagecache("/");
+        clear_term();
+        if ($mode eq "file") {
+            print_files($cur_sec);
+        } elsif ($mode eq "process") {
+            print_processes($cur_sec);
+        }
+        clear_stats();
+        $pre_print_time = $cur_sec;
+    }
+}
+
+sub clear_stats {
+    foreach my $f (values %files) {
+        $$f{stat} = {find => 0, hit => 0, add => 0, remove => 0};
+        $$f{process} = ();
+    }
+    %processes = ();
+}
+
+sub minor {
+    my $dev = shift;
+    return $dev & ((1 << 20) - 1);
+}
+
+sub major {
+    my $dev = shift;
+    return $dev >> 20;
+}
+
+sub print_files {
+    my $cur_sec = shift;
+    my $i = 0;
+
+    foreach my $f (values %files) {
+        foreach my $s (values %{$$f{process}}) {
+            add_stat($$f{stat}, $s);
+        }
+    }
+
+    printf "pagecache behavior per file (time:%d, interval:%d)\n\n"
+        ,$cur_sec, $interval;
+    printf("%20s %8s %10s %8s %8s %8s %5s\n",
+           "", "find", "hit", "cache", "add", "remove", "proc");
+    printf("%20s %8s %10s %8s %8s %8s %5s\n", "file", "count", "ratio",
+           "pages(B)", "pages(B)", "pages(B)", "count");
+    printf("%20s %8s %10s %8s %8s %8s %5s\n",
+           '-'x20, '-'x8, '-'x10, '-'x8, '-'x8, '-'x8, '-'x5);
+    foreach my $f (sort {$$b{stat}{find} <=> $$a{stat}{find}} values %files) {
+        $i++;
+        my $pcount = scalar(keys(%{$$f{process}}));
+        if ($pcount != 0) {
+            printf("%20s %8s %9.2f%% %8s %8s %8s %5d\n",
+                   substr(basename($$f{path}), 0, 20),
+                   $$f{stat}{find},
+                   ($$f{stat}{find} == 0) ?
+                   0 : $$f{stat}{hit} / $$f{stat}{find} * 100,
+                   ($$f{cache} != 0) ? convert_unit($$f{cache} * 4096): "N/A",
+                   convert_unit($$f{stat}{add} * 4096),
+                   convert_unit($$f{stat}{remove} * 4096),
+                   $pcount);
+        }
+        last if $i >= $print_limit;
+    }
+}
+
+sub print_processes {
+    my $cur_sec = shift;
+    my $i = 0;
+
+    foreach my $p (values %processes) {
+        foreach my $s (values %{$$p{file}}) {
+            add_stat($$p{stat}, $s);
+        }
+    }
+
+    printf "pagecache behavior per process (time:%d, interval:%d)\n\n"
+        ,$cur_sec, $interval;
+    printf("%20s %8s %10s %8s %8s %5s\n",
+           "", "find", "hit", "add", "remove", "file");
+    printf("%20s %8s %10s %8s %8s %5s\n", "process", "count", "ratio",
+           "pages(B)", "pages(B)", "count");
+    printf("%20s %8s %10s %8s %8s %5s\n",
+           '-'x20, '-'x8, '-'x10, '-'x8, '-'x8, '-'x5);
+    foreach my $p (sort {$$b{stat}{find} <=> $$a{stat}{find}} values %processes) {
+        $i++;
+        my $fcount = scalar(keys(%{$$p{file}}));
+        if ($fcount != 0) {
+            printf("%20s %8s %9.2f%% %8s %8s %5d\n",
+                   substr(basename($$p{name}), 0, 20),
+                   $$p{stat}{find},
+                   ($$p{stat}{find} == 0) ?
+                   0 : $$p{stat}{hit} / $$p{stat}{find} * 100,
+                   convert_unit($$p{stat}{add} * 4096),
+                   convert_unit($$p{stat}{remove} * 4096),
+                   $fcount);
+        }
+        last if $i >= $print_limit;
+    }
+}
+
+my @unit = ("K", "M", "G", "T");
+sub convert_unit() {
+    my $size = shift;
+
+     for (my $i=$#unit; $i >= 0; $i--) {
+        if (abs($size) >= 1024 ** ($i+1)) {
+            return sprintf("%.1f%s", $size/1024 ** ($i+1) , $unit[$i]);
+        }
+    }
+    return $size
+}
+
+sub dump_fs_pagecache() {
+    my $path = shift;
+    open my $fh, ">", "$debugfs_mountpoint/tracing/objects/mm/pages/walk-fs"
+        or die "Can't open tracing/objects/mm/pages/walk-fs: $!";
+    print $fh "$path\n";
+    close($fh);
+}
+
+sub add_stat {
+    my ($s1, $s2) = @_;
+
+    $$s1{find} += $$s2{find};
+    $$s1{hit} += $$s2{hit};
+    $$s1{add} += $$s2{add};
+    $$s1{remove} += $$s2{remove};
+}


--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  parent reply	other threads:[~2011-07-18 21:40 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-18 21:31 [RFC PATCH -tip 0/5] perf tools: " Keiichi KII
2011-07-18 21:33 ` [RFC PATCH -tip 1/5] perf tools: handle '-' and '*' in trace parsing Keiichi KII
2011-07-18 21:34 ` [RFC PATCH -tip 2/5] tracing/mm: add header event for object collections Keiichi KII
2011-07-29  9:55   ` Mel Gorman
2011-07-18 21:36 ` [RFC PATCH -tip 3/5] perf tools: scripts for pagecache snapshooting Keiichi KII
2011-07-18 21:38 ` [RFC PATCH -tip 4/5] tracepoints: add tracepoints for pagecache Keiichi KII
2011-07-29 10:06   ` Mel Gorman
2011-07-18 21:40 ` Keiichi KII [this message]
2011-07-21  7:01 ` [RFC PATCH -tip 0/5] perf tools: pagecache monitoring Ingo Molnar
2011-07-29  0:28   ` Keiichi KII
2011-07-29  9:14 ` Mel Gorman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4E24A833.2090208@bx.jp.nec.com \
    --to=k-keiichi@bx.jp.nec.com \
    --cc=Moussa.BA@numonyx.com \
    --cc=fengguang.wu@intel.com \
    --cc=fweisbec@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mingo@elte.hu \
    --cc=riel@redhat.com \
    --cc=rostedt@goodmis.org \
    --cc=tzanussi@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox