162306a36Sopenharmony_ci#!/usr/bin/env perl
262306a36Sopenharmony_ci# This is a POC (proof of concept or piece of crap, take your pick) for reading the
362306a36Sopenharmony_ci# text representation of trace output related to page allocation. It makes an attempt
462306a36Sopenharmony_ci# to extract some high-level information on what is going on. The accuracy of the parser
562306a36Sopenharmony_ci# may vary considerably
662306a36Sopenharmony_ci#
762306a36Sopenharmony_ci# Example usage: trace-pagealloc-postprocess.pl < /sys/kernel/tracing/trace_pipe
862306a36Sopenharmony_ci# other options
962306a36Sopenharmony_ci#   --prepend-parent	Report on the parent proc and PID
1062306a36Sopenharmony_ci#   --read-procstat	If the trace lacks process info, get it from /proc
1162306a36Sopenharmony_ci#   --ignore-pid	Aggregate processes of the same name together
1262306a36Sopenharmony_ci#
1362306a36Sopenharmony_ci# Copyright (c) IBM Corporation 2009
1462306a36Sopenharmony_ci# Author: Mel Gorman <mel@csn.ul.ie>
1562306a36Sopenharmony_ciuse strict;
1662306a36Sopenharmony_ciuse Getopt::Long;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci# Tracepoint events
1962306a36Sopenharmony_ciuse constant MM_PAGE_ALLOC		=> 1;
2062306a36Sopenharmony_ciuse constant MM_PAGE_FREE		=> 2;
2162306a36Sopenharmony_ciuse constant MM_PAGE_FREE_BATCHED	=> 3;
2262306a36Sopenharmony_ciuse constant MM_PAGE_PCPU_DRAIN		=> 4;
2362306a36Sopenharmony_ciuse constant MM_PAGE_ALLOC_ZONE_LOCKED	=> 5;
2462306a36Sopenharmony_ciuse constant MM_PAGE_ALLOC_EXTFRAG	=> 6;
2562306a36Sopenharmony_ciuse constant EVENT_UNKNOWN		=> 7;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci# Constants used to track state
2862306a36Sopenharmony_ciuse constant STATE_PCPU_PAGES_DRAINED	=> 8;
2962306a36Sopenharmony_ciuse constant STATE_PCPU_PAGES_REFILLED	=> 9;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci# High-level events extrapolated from tracepoints
3262306a36Sopenharmony_ciuse constant HIGH_PCPU_DRAINS		=> 10;
3362306a36Sopenharmony_ciuse constant HIGH_PCPU_REFILLS		=> 11;
3462306a36Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT		=> 12;
3562306a36Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT_SEVERE	=> 13;
3662306a36Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT_MODERATE	=> 14;
3762306a36Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT_CHANGED	=> 15;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cimy %perprocesspid;
4062306a36Sopenharmony_cimy %perprocess;
4162306a36Sopenharmony_cimy $opt_ignorepid;
4262306a36Sopenharmony_cimy $opt_read_procstat;
4362306a36Sopenharmony_cimy $opt_prepend_parent;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci# Catch sigint and exit on request
4662306a36Sopenharmony_cimy $sigint_report = 0;
4762306a36Sopenharmony_cimy $sigint_exit = 0;
4862306a36Sopenharmony_cimy $sigint_pending = 0;
4962306a36Sopenharmony_cimy $sigint_received = 0;
5062306a36Sopenharmony_cisub sigint_handler {
5162306a36Sopenharmony_ci	my $current_time = time;
5262306a36Sopenharmony_ci	if ($current_time - 2 > $sigint_received) {
5362306a36Sopenharmony_ci		print "SIGINT received, report pending. Hit ctrl-c again to exit\n";
5462306a36Sopenharmony_ci		$sigint_report = 1;
5562306a36Sopenharmony_ci	} else {
5662306a36Sopenharmony_ci		if (!$sigint_exit) {
5762306a36Sopenharmony_ci			print "Second SIGINT received quickly, exiting\n";
5862306a36Sopenharmony_ci		}
5962306a36Sopenharmony_ci		$sigint_exit++;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if ($sigint_exit > 3) {
6362306a36Sopenharmony_ci		print "Many SIGINTs received, exiting now without report\n";
6462306a36Sopenharmony_ci		exit;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	$sigint_received = $current_time;
6862306a36Sopenharmony_ci	$sigint_pending = 1;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci$SIG{INT} = "sigint_handler";
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci# Parse command line options
7362306a36Sopenharmony_ciGetOptions(
7462306a36Sopenharmony_ci	'ignore-pid'	 =>	\$opt_ignorepid,
7562306a36Sopenharmony_ci	'read-procstat'	 =>	\$opt_read_procstat,
7662306a36Sopenharmony_ci	'prepend-parent' =>	\$opt_prepend_parent,
7762306a36Sopenharmony_ci);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci# Defaults for dynamically discovered regex's
8062306a36Sopenharmony_cimy $regex_fragdetails_default = 'page=([0-9a-f]*) pfn=([0-9]*) alloc_order=([-0-9]*) fallback_order=([-0-9]*) pageblock_order=([-0-9]*) alloc_migratetype=([-0-9]*) fallback_migratetype=([-0-9]*) fragmenting=([-0-9]) change_ownership=([-0-9])';
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci# Dyanically discovered regex
8362306a36Sopenharmony_cimy $regex_fragdetails;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci# Static regex used. Specified like this for readability and for use with /o
8662306a36Sopenharmony_ci#                      (process_pid)     (cpus      )   ( time  )   (tpoint    ) (details)
8762306a36Sopenharmony_cimy $regex_traceevent = '\s*([a-zA-Z0-9-]*)\s*(\[[0-9]*\])\s*([0-9.]*):\s*([a-zA-Z_]*):\s*(.*)';
8862306a36Sopenharmony_cimy $regex_statname = '[-0-9]*\s\((.*)\).*';
8962306a36Sopenharmony_cimy $regex_statppid = '[-0-9]*\s\(.*\)\s[A-Za-z]\s([0-9]*).*';
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cisub generate_traceevent_regex {
9262306a36Sopenharmony_ci	my $event = shift;
9362306a36Sopenharmony_ci	my $default = shift;
9462306a36Sopenharmony_ci	my $regex;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	# Read the event format or use the default
9762306a36Sopenharmony_ci	if (!open (FORMAT, "/sys/kernel/tracing/events/$event/format")) {
9862306a36Sopenharmony_ci		$regex = $default;
9962306a36Sopenharmony_ci	} else {
10062306a36Sopenharmony_ci		my $line;
10162306a36Sopenharmony_ci		while (!eof(FORMAT)) {
10262306a36Sopenharmony_ci			$line = <FORMAT>;
10362306a36Sopenharmony_ci			if ($line =~ /^print fmt:\s"(.*)",.*/) {
10462306a36Sopenharmony_ci				$regex = $1;
10562306a36Sopenharmony_ci				$regex =~ s/%p/\([0-9a-f]*\)/g;
10662306a36Sopenharmony_ci				$regex =~ s/%d/\([-0-9]*\)/g;
10762306a36Sopenharmony_ci				$regex =~ s/%lu/\([0-9]*\)/g;
10862306a36Sopenharmony_ci			}
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	# Verify fields are in the right order
11362306a36Sopenharmony_ci	my $tuple;
11462306a36Sopenharmony_ci	foreach $tuple (split /\s/, $regex) {
11562306a36Sopenharmony_ci		my ($key, $value) = split(/=/, $tuple);
11662306a36Sopenharmony_ci		my $expected = shift;
11762306a36Sopenharmony_ci		if ($key ne $expected) {
11862306a36Sopenharmony_ci			print("WARNING: Format not as expected '$key' != '$expected'");
11962306a36Sopenharmony_ci			$regex =~ s/$key=\((.*)\)/$key=$1/;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (defined shift) {
12462306a36Sopenharmony_ci		die("Fewer fields than expected in format");
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return $regex;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci$regex_fragdetails = generate_traceevent_regex("kmem/mm_page_alloc_extfrag",
13062306a36Sopenharmony_ci			$regex_fragdetails_default,
13162306a36Sopenharmony_ci			"page", "pfn",
13262306a36Sopenharmony_ci			"alloc_order", "fallback_order", "pageblock_order",
13362306a36Sopenharmony_ci			"alloc_migratetype", "fallback_migratetype",
13462306a36Sopenharmony_ci			"fragmenting", "change_ownership");
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cisub read_statline($) {
13762306a36Sopenharmony_ci	my $pid = $_[0];
13862306a36Sopenharmony_ci	my $statline;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (open(STAT, "/proc/$pid/stat")) {
14162306a36Sopenharmony_ci		$statline = <STAT>;
14262306a36Sopenharmony_ci		close(STAT);
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if ($statline eq '') {
14662306a36Sopenharmony_ci		$statline = "-1 (UNKNOWN_PROCESS_NAME) R 0";
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return $statline;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cisub guess_process_pid($$) {
15362306a36Sopenharmony_ci	my $pid = $_[0];
15462306a36Sopenharmony_ci	my $statline = $_[1];
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if ($pid == 0) {
15762306a36Sopenharmony_ci		return "swapper-0";
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if ($statline !~ /$regex_statname/o) {
16162306a36Sopenharmony_ci		die("Failed to math stat line for process name :: $statline");
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci	return "$1-$pid";
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cisub parent_info($$) {
16762306a36Sopenharmony_ci	my $pid = $_[0];
16862306a36Sopenharmony_ci	my $statline = $_[1];
16962306a36Sopenharmony_ci	my $ppid;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if ($pid == 0) {
17262306a36Sopenharmony_ci		return "NOPARENT-0";
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if ($statline !~ /$regex_statppid/o) {
17662306a36Sopenharmony_ci		die("Failed to match stat line process ppid:: $statline");
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	# Read the ppid stat line
18062306a36Sopenharmony_ci	$ppid = $1;
18162306a36Sopenharmony_ci	return guess_process_pid($ppid, read_statline($ppid));
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cisub process_events {
18562306a36Sopenharmony_ci	my $traceevent;
18662306a36Sopenharmony_ci	my $process_pid;
18762306a36Sopenharmony_ci	my $cpus;
18862306a36Sopenharmony_ci	my $timestamp;
18962306a36Sopenharmony_ci	my $tracepoint;
19062306a36Sopenharmony_ci	my $details;
19162306a36Sopenharmony_ci	my $statline;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	# Read each line of the event log
19462306a36Sopenharmony_ciEVENT_PROCESS:
19562306a36Sopenharmony_ci	while ($traceevent = <STDIN>) {
19662306a36Sopenharmony_ci		if ($traceevent =~ /$regex_traceevent/o) {
19762306a36Sopenharmony_ci			$process_pid = $1;
19862306a36Sopenharmony_ci			$tracepoint = $4;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci			if ($opt_read_procstat || $opt_prepend_parent) {
20162306a36Sopenharmony_ci				$process_pid =~ /(.*)-([0-9]*)$/;
20262306a36Sopenharmony_ci				my $process = $1;
20362306a36Sopenharmony_ci				my $pid = $2;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci				$statline = read_statline($pid);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci				if ($opt_read_procstat && $process eq '') {
20862306a36Sopenharmony_ci					$process_pid = guess_process_pid($pid, $statline);
20962306a36Sopenharmony_ci				}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci				if ($opt_prepend_parent) {
21262306a36Sopenharmony_ci					$process_pid = parent_info($pid, $statline) . " :: $process_pid";
21362306a36Sopenharmony_ci				}
21462306a36Sopenharmony_ci			}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci			# Unnecessary in this script. Uncomment if required
21762306a36Sopenharmony_ci			# $cpus = $2;
21862306a36Sopenharmony_ci			# $timestamp = $3;
21962306a36Sopenharmony_ci		} else {
22062306a36Sopenharmony_ci			next;
22162306a36Sopenharmony_ci		}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		# Perl Switch() sucks majorly
22462306a36Sopenharmony_ci		if ($tracepoint eq "mm_page_alloc") {
22562306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_ALLOC}++;
22662306a36Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_free") {
22762306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_FREE}++
22862306a36Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_free_batched") {
22962306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_FREE_BATCHED}++;
23062306a36Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_pcpu_drain") {
23162306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_PCPU_DRAIN}++;
23262306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_DRAINED}++;
23362306a36Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_alloc_zone_locked") {
23462306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED}++;
23562306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_REFILLED}++;
23662306a36Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_alloc_extfrag") {
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci			# Extract the details of the event now
23962306a36Sopenharmony_ci			$details = $5;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci			my ($page, $pfn);
24262306a36Sopenharmony_ci			my ($alloc_order, $fallback_order, $pageblock_order);
24362306a36Sopenharmony_ci			my ($alloc_migratetype, $fallback_migratetype);
24462306a36Sopenharmony_ci			my ($fragmenting, $change_ownership);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci			if ($details !~ /$regex_fragdetails/o) {
24762306a36Sopenharmony_ci				print "WARNING: Failed to parse mm_page_alloc_extfrag as expected\n";
24862306a36Sopenharmony_ci				next;
24962306a36Sopenharmony_ci			}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_ALLOC_EXTFRAG}++;
25262306a36Sopenharmony_ci			$page = $1;
25362306a36Sopenharmony_ci			$pfn = $2;
25462306a36Sopenharmony_ci			$alloc_order = $3;
25562306a36Sopenharmony_ci			$fallback_order = $4;
25662306a36Sopenharmony_ci			$pageblock_order = $5;
25762306a36Sopenharmony_ci			$alloc_migratetype = $6;
25862306a36Sopenharmony_ci			$fallback_migratetype = $7;
25962306a36Sopenharmony_ci			$fragmenting = $8;
26062306a36Sopenharmony_ci			$change_ownership = $9;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci			if ($fragmenting) {
26362306a36Sopenharmony_ci				$perprocesspid{$process_pid}->{HIGH_EXT_FRAG}++;
26462306a36Sopenharmony_ci				if ($fallback_order <= 3) {
26562306a36Sopenharmony_ci					$perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_SEVERE}++;
26662306a36Sopenharmony_ci				} else {
26762306a36Sopenharmony_ci					$perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_MODERATE}++;
26862306a36Sopenharmony_ci				}
26962306a36Sopenharmony_ci			}
27062306a36Sopenharmony_ci			if ($change_ownership) {
27162306a36Sopenharmony_ci				$perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_CHANGED}++;
27262306a36Sopenharmony_ci			}
27362306a36Sopenharmony_ci		} else {
27462306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{EVENT_UNKNOWN}++;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci		# Catch a full pcpu drain event
27862306a36Sopenharmony_ci		if ($perprocesspid{$process_pid}->{STATE_PCPU_PAGES_DRAINED} &&
27962306a36Sopenharmony_ci				$tracepoint ne "mm_page_pcpu_drain") {
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{HIGH_PCPU_DRAINS}++;
28262306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_DRAINED} = 0;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		# Catch a full pcpu refill event
28662306a36Sopenharmony_ci		if ($perprocesspid{$process_pid}->{STATE_PCPU_PAGES_REFILLED} &&
28762306a36Sopenharmony_ci				$tracepoint ne "mm_page_alloc_zone_locked") {
28862306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{HIGH_PCPU_REFILLS}++;
28962306a36Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_REFILLED} = 0;
29062306a36Sopenharmony_ci		}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		if ($sigint_pending) {
29362306a36Sopenharmony_ci			last EVENT_PROCESS;
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cisub dump_stats {
29962306a36Sopenharmony_ci	my $hashref = shift;
30062306a36Sopenharmony_ci	my %stats = %$hashref;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	# Dump per-process stats
30362306a36Sopenharmony_ci	my $process_pid;
30462306a36Sopenharmony_ci	my $max_strlen = 0;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	# Get the maximum process name
30762306a36Sopenharmony_ci	foreach $process_pid (keys %perprocesspid) {
30862306a36Sopenharmony_ci		my $len = length($process_pid);
30962306a36Sopenharmony_ci		if ($len > $max_strlen) {
31062306a36Sopenharmony_ci			$max_strlen = $len;
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	$max_strlen += 2;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	printf("\n");
31662306a36Sopenharmony_ci	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s   %8s %8s %8s   %8s %8s %8s %8s %8s %8s\n",
31762306a36Sopenharmony_ci		"Process", "Pages",  "Pages",      "Pages", "Pages", "PCPU",  "PCPU",   "PCPU",    "Fragment",  "Fragment", "MigType", "Fragment", "Fragment", "Unknown");
31862306a36Sopenharmony_ci	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s   %8s %8s %8s   %8s %8s %8s %8s %8s %8s\n",
31962306a36Sopenharmony_ci		"details", "allocd", "allocd",     "freed", "freed", "pages", "drains", "refills", "Fallback", "Causing",   "Changed", "Severe", "Moderate", "");
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s   %8s %8s %8s   %8s %8s %8s %8s %8s %8s\n",
32262306a36Sopenharmony_ci		"",        "",       "under lock", "direct", "pagevec", "drain", "", "", "", "", "", "", "", "");
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	foreach $process_pid (keys %stats) {
32562306a36Sopenharmony_ci		# Dump final aggregates
32662306a36Sopenharmony_ci		if ($stats{$process_pid}->{STATE_PCPU_PAGES_DRAINED}) {
32762306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_DRAINS}++;
32862306a36Sopenharmony_ci			$stats{$process_pid}->{STATE_PCPU_PAGES_DRAINED} = 0;
32962306a36Sopenharmony_ci		}
33062306a36Sopenharmony_ci		if ($stats{$process_pid}->{STATE_PCPU_PAGES_REFILLED}) {
33162306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_REFILLS}++;
33262306a36Sopenharmony_ci			$stats{$process_pid}->{STATE_PCPU_PAGES_REFILLED} = 0;
33362306a36Sopenharmony_ci		}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		printf("%-" . $max_strlen . "s %8d %10d   %8d %8d   %8d %8d %8d   %8d %8d %8d %8d %8d %8d\n",
33662306a36Sopenharmony_ci			$process_pid,
33762306a36Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_ALLOC},
33862306a36Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED},
33962306a36Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_FREE},
34062306a36Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_FREE_BATCHED},
34162306a36Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_PCPU_DRAIN},
34262306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_DRAINS},
34362306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_REFILLS},
34462306a36Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_ALLOC_EXTFRAG},
34562306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAG},
34662306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAGMENT_CHANGED},
34762306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAGMENT_SEVERE},
34862306a36Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAGMENT_MODERATE},
34962306a36Sopenharmony_ci			$stats{$process_pid}->{EVENT_UNKNOWN});
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cisub aggregate_perprocesspid() {
35462306a36Sopenharmony_ci	my $process_pid;
35562306a36Sopenharmony_ci	my $process;
35662306a36Sopenharmony_ci	undef %perprocess;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	foreach $process_pid (keys %perprocesspid) {
35962306a36Sopenharmony_ci		$process = $process_pid;
36062306a36Sopenharmony_ci		$process =~ s/-([0-9])*$//;
36162306a36Sopenharmony_ci		if ($process eq '') {
36262306a36Sopenharmony_ci			$process = "NO_PROCESS_NAME";
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_ALLOC} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC};
36662306a36Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_ALLOC_ZONE_LOCKED} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED};
36762306a36Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_FREE} += $perprocesspid{$process_pid}->{MM_PAGE_FREE};
36862306a36Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_FREE_BATCHED} += $perprocesspid{$process_pid}->{MM_PAGE_FREE_BATCHED};
36962306a36Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_PCPU_DRAIN} += $perprocesspid{$process_pid}->{MM_PAGE_PCPU_DRAIN};
37062306a36Sopenharmony_ci		$perprocess{$process}->{HIGH_PCPU_DRAINS} += $perprocesspid{$process_pid}->{HIGH_PCPU_DRAINS};
37162306a36Sopenharmony_ci		$perprocess{$process}->{HIGH_PCPU_REFILLS} += $perprocesspid{$process_pid}->{HIGH_PCPU_REFILLS};
37262306a36Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_ALLOC_EXTFRAG} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC_EXTFRAG};
37362306a36Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAG} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAG};
37462306a36Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAGMENT_CHANGED} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_CHANGED};
37562306a36Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAGMENT_SEVERE} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_SEVERE};
37662306a36Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAGMENT_MODERATE} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_MODERATE};
37762306a36Sopenharmony_ci		$perprocess{$process}->{EVENT_UNKNOWN} += $perprocesspid{$process_pid}->{EVENT_UNKNOWN};
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cisub report() {
38262306a36Sopenharmony_ci	if (!$opt_ignorepid) {
38362306a36Sopenharmony_ci		dump_stats(\%perprocesspid);
38462306a36Sopenharmony_ci	} else {
38562306a36Sopenharmony_ci		aggregate_perprocesspid();
38662306a36Sopenharmony_ci		dump_stats(\%perprocess);
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci# Process events or signals until neither is available
39162306a36Sopenharmony_cisub signal_loop() {
39262306a36Sopenharmony_ci	my $sigint_processed;
39362306a36Sopenharmony_ci	do {
39462306a36Sopenharmony_ci		$sigint_processed = 0;
39562306a36Sopenharmony_ci		process_events();
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		# Handle pending signals if any
39862306a36Sopenharmony_ci		if ($sigint_pending) {
39962306a36Sopenharmony_ci			my $current_time = time;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci			if ($sigint_exit) {
40262306a36Sopenharmony_ci				print "Received exit signal\n";
40362306a36Sopenharmony_ci				$sigint_pending = 0;
40462306a36Sopenharmony_ci			}
40562306a36Sopenharmony_ci			if ($sigint_report) {
40662306a36Sopenharmony_ci				if ($current_time >= $sigint_received + 2) {
40762306a36Sopenharmony_ci					report();
40862306a36Sopenharmony_ci					$sigint_report = 0;
40962306a36Sopenharmony_ci					$sigint_pending = 0;
41062306a36Sopenharmony_ci					$sigint_processed = 1;
41162306a36Sopenharmony_ci				}
41262306a36Sopenharmony_ci			}
41362306a36Sopenharmony_ci		}
41462306a36Sopenharmony_ci	} while ($sigint_pending || $sigint_processed);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cisignal_loop();
41862306a36Sopenharmony_cireport();
419