18c2ecf20Sopenharmony_ci#!/usr/bin/env perl
28c2ecf20Sopenharmony_ci# This is a POC (proof of concept or piece of crap, take your pick) for reading the
38c2ecf20Sopenharmony_ci# text representation of trace output related to page allocation. It makes an attempt
48c2ecf20Sopenharmony_ci# to extract some high-level information on what is going on. The accuracy of the parser
58c2ecf20Sopenharmony_ci# may vary considerably
68c2ecf20Sopenharmony_ci#
78c2ecf20Sopenharmony_ci# Example usage: trace-pagealloc-postprocess.pl < /sys/kernel/debug/tracing/trace_pipe
88c2ecf20Sopenharmony_ci# other options
98c2ecf20Sopenharmony_ci#   --prepend-parent	Report on the parent proc and PID
108c2ecf20Sopenharmony_ci#   --read-procstat	If the trace lacks process info, get it from /proc
118c2ecf20Sopenharmony_ci#   --ignore-pid	Aggregate processes of the same name together
128c2ecf20Sopenharmony_ci#
138c2ecf20Sopenharmony_ci# Copyright (c) IBM Corporation 2009
148c2ecf20Sopenharmony_ci# Author: Mel Gorman <mel@csn.ul.ie>
158c2ecf20Sopenharmony_ciuse strict;
168c2ecf20Sopenharmony_ciuse Getopt::Long;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci# Tracepoint events
198c2ecf20Sopenharmony_ciuse constant MM_PAGE_ALLOC		=> 1;
208c2ecf20Sopenharmony_ciuse constant MM_PAGE_FREE		=> 2;
218c2ecf20Sopenharmony_ciuse constant MM_PAGE_FREE_BATCHED	=> 3;
228c2ecf20Sopenharmony_ciuse constant MM_PAGE_PCPU_DRAIN		=> 4;
238c2ecf20Sopenharmony_ciuse constant MM_PAGE_ALLOC_ZONE_LOCKED	=> 5;
248c2ecf20Sopenharmony_ciuse constant MM_PAGE_ALLOC_EXTFRAG	=> 6;
258c2ecf20Sopenharmony_ciuse constant EVENT_UNKNOWN		=> 7;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci# Constants used to track state
288c2ecf20Sopenharmony_ciuse constant STATE_PCPU_PAGES_DRAINED	=> 8;
298c2ecf20Sopenharmony_ciuse constant STATE_PCPU_PAGES_REFILLED	=> 9;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci# High-level events extrapolated from tracepoints
328c2ecf20Sopenharmony_ciuse constant HIGH_PCPU_DRAINS		=> 10;
338c2ecf20Sopenharmony_ciuse constant HIGH_PCPU_REFILLS		=> 11;
348c2ecf20Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT		=> 12;
358c2ecf20Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT_SEVERE	=> 13;
368c2ecf20Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT_MODERATE	=> 14;
378c2ecf20Sopenharmony_ciuse constant HIGH_EXT_FRAGMENT_CHANGED	=> 15;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cimy %perprocesspid;
408c2ecf20Sopenharmony_cimy %perprocess;
418c2ecf20Sopenharmony_cimy $opt_ignorepid;
428c2ecf20Sopenharmony_cimy $opt_read_procstat;
438c2ecf20Sopenharmony_cimy $opt_prepend_parent;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci# Catch sigint and exit on request
468c2ecf20Sopenharmony_cimy $sigint_report = 0;
478c2ecf20Sopenharmony_cimy $sigint_exit = 0;
488c2ecf20Sopenharmony_cimy $sigint_pending = 0;
498c2ecf20Sopenharmony_cimy $sigint_received = 0;
508c2ecf20Sopenharmony_cisub sigint_handler {
518c2ecf20Sopenharmony_ci	my $current_time = time;
528c2ecf20Sopenharmony_ci	if ($current_time - 2 > $sigint_received) {
538c2ecf20Sopenharmony_ci		print "SIGINT received, report pending. Hit ctrl-c again to exit\n";
548c2ecf20Sopenharmony_ci		$sigint_report = 1;
558c2ecf20Sopenharmony_ci	} else {
568c2ecf20Sopenharmony_ci		if (!$sigint_exit) {
578c2ecf20Sopenharmony_ci			print "Second SIGINT received quickly, exiting\n";
588c2ecf20Sopenharmony_ci		}
598c2ecf20Sopenharmony_ci		$sigint_exit++;
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if ($sigint_exit > 3) {
638c2ecf20Sopenharmony_ci		print "Many SIGINTs received, exiting now without report\n";
648c2ecf20Sopenharmony_ci		exit;
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	$sigint_received = $current_time;
688c2ecf20Sopenharmony_ci	$sigint_pending = 1;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci$SIG{INT} = "sigint_handler";
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci# Parse command line options
738c2ecf20Sopenharmony_ciGetOptions(
748c2ecf20Sopenharmony_ci	'ignore-pid'	 =>	\$opt_ignorepid,
758c2ecf20Sopenharmony_ci	'read-procstat'	 =>	\$opt_read_procstat,
768c2ecf20Sopenharmony_ci	'prepend-parent' =>	\$opt_prepend_parent,
778c2ecf20Sopenharmony_ci);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci# Defaults for dynamically discovered regex's
808c2ecf20Sopenharmony_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])';
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci# Dyanically discovered regex
838c2ecf20Sopenharmony_cimy $regex_fragdetails;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci# Static regex used. Specified like this for readability and for use with /o
868c2ecf20Sopenharmony_ci#                      (process_pid)     (cpus      )   ( time  )   (tpoint    ) (details)
878c2ecf20Sopenharmony_cimy $regex_traceevent = '\s*([a-zA-Z0-9-]*)\s*(\[[0-9]*\])\s*([0-9.]*):\s*([a-zA-Z_]*):\s*(.*)';
888c2ecf20Sopenharmony_cimy $regex_statname = '[-0-9]*\s\((.*)\).*';
898c2ecf20Sopenharmony_cimy $regex_statppid = '[-0-9]*\s\(.*\)\s[A-Za-z]\s([0-9]*).*';
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cisub generate_traceevent_regex {
928c2ecf20Sopenharmony_ci	my $event = shift;
938c2ecf20Sopenharmony_ci	my $default = shift;
948c2ecf20Sopenharmony_ci	my $regex;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	# Read the event format or use the default
978c2ecf20Sopenharmony_ci	if (!open (FORMAT, "/sys/kernel/debug/tracing/events/$event/format")) {
988c2ecf20Sopenharmony_ci		$regex = $default;
998c2ecf20Sopenharmony_ci	} else {
1008c2ecf20Sopenharmony_ci		my $line;
1018c2ecf20Sopenharmony_ci		while (!eof(FORMAT)) {
1028c2ecf20Sopenharmony_ci			$line = <FORMAT>;
1038c2ecf20Sopenharmony_ci			if ($line =~ /^print fmt:\s"(.*)",.*/) {
1048c2ecf20Sopenharmony_ci				$regex = $1;
1058c2ecf20Sopenharmony_ci				$regex =~ s/%p/\([0-9a-f]*\)/g;
1068c2ecf20Sopenharmony_ci				$regex =~ s/%d/\([-0-9]*\)/g;
1078c2ecf20Sopenharmony_ci				$regex =~ s/%lu/\([0-9]*\)/g;
1088c2ecf20Sopenharmony_ci			}
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	# Verify fields are in the right order
1138c2ecf20Sopenharmony_ci	my $tuple;
1148c2ecf20Sopenharmony_ci	foreach $tuple (split /\s/, $regex) {
1158c2ecf20Sopenharmony_ci		my ($key, $value) = split(/=/, $tuple);
1168c2ecf20Sopenharmony_ci		my $expected = shift;
1178c2ecf20Sopenharmony_ci		if ($key ne $expected) {
1188c2ecf20Sopenharmony_ci			print("WARNING: Format not as expected '$key' != '$expected'");
1198c2ecf20Sopenharmony_ci			$regex =~ s/$key=\((.*)\)/$key=$1/;
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (defined shift) {
1248c2ecf20Sopenharmony_ci		die("Fewer fields than expected in format");
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return $regex;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci$regex_fragdetails = generate_traceevent_regex("kmem/mm_page_alloc_extfrag",
1308c2ecf20Sopenharmony_ci			$regex_fragdetails_default,
1318c2ecf20Sopenharmony_ci			"page", "pfn",
1328c2ecf20Sopenharmony_ci			"alloc_order", "fallback_order", "pageblock_order",
1338c2ecf20Sopenharmony_ci			"alloc_migratetype", "fallback_migratetype",
1348c2ecf20Sopenharmony_ci			"fragmenting", "change_ownership");
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cisub read_statline($) {
1378c2ecf20Sopenharmony_ci	my $pid = $_[0];
1388c2ecf20Sopenharmony_ci	my $statline;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (open(STAT, "/proc/$pid/stat")) {
1418c2ecf20Sopenharmony_ci		$statline = <STAT>;
1428c2ecf20Sopenharmony_ci		close(STAT);
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if ($statline eq '') {
1468c2ecf20Sopenharmony_ci		$statline = "-1 (UNKNOWN_PROCESS_NAME) R 0";
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return $statline;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cisub guess_process_pid($$) {
1538c2ecf20Sopenharmony_ci	my $pid = $_[0];
1548c2ecf20Sopenharmony_ci	my $statline = $_[1];
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if ($pid == 0) {
1578c2ecf20Sopenharmony_ci		return "swapper-0";
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if ($statline !~ /$regex_statname/o) {
1618c2ecf20Sopenharmony_ci		die("Failed to math stat line for process name :: $statline");
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	return "$1-$pid";
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cisub parent_info($$) {
1678c2ecf20Sopenharmony_ci	my $pid = $_[0];
1688c2ecf20Sopenharmony_ci	my $statline = $_[1];
1698c2ecf20Sopenharmony_ci	my $ppid;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if ($pid == 0) {
1728c2ecf20Sopenharmony_ci		return "NOPARENT-0";
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if ($statline !~ /$regex_statppid/o) {
1768c2ecf20Sopenharmony_ci		die("Failed to match stat line process ppid:: $statline");
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	# Read the ppid stat line
1808c2ecf20Sopenharmony_ci	$ppid = $1;
1818c2ecf20Sopenharmony_ci	return guess_process_pid($ppid, read_statline($ppid));
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cisub process_events {
1858c2ecf20Sopenharmony_ci	my $traceevent;
1868c2ecf20Sopenharmony_ci	my $process_pid;
1878c2ecf20Sopenharmony_ci	my $cpus;
1888c2ecf20Sopenharmony_ci	my $timestamp;
1898c2ecf20Sopenharmony_ci	my $tracepoint;
1908c2ecf20Sopenharmony_ci	my $details;
1918c2ecf20Sopenharmony_ci	my $statline;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	# Read each line of the event log
1948c2ecf20Sopenharmony_ciEVENT_PROCESS:
1958c2ecf20Sopenharmony_ci	while ($traceevent = <STDIN>) {
1968c2ecf20Sopenharmony_ci		if ($traceevent =~ /$regex_traceevent/o) {
1978c2ecf20Sopenharmony_ci			$process_pid = $1;
1988c2ecf20Sopenharmony_ci			$tracepoint = $4;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci			if ($opt_read_procstat || $opt_prepend_parent) {
2018c2ecf20Sopenharmony_ci				$process_pid =~ /(.*)-([0-9]*)$/;
2028c2ecf20Sopenharmony_ci				my $process = $1;
2038c2ecf20Sopenharmony_ci				my $pid = $2;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci				$statline = read_statline($pid);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci				if ($opt_read_procstat && $process eq '') {
2088c2ecf20Sopenharmony_ci					$process_pid = guess_process_pid($pid, $statline);
2098c2ecf20Sopenharmony_ci				}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci				if ($opt_prepend_parent) {
2128c2ecf20Sopenharmony_ci					$process_pid = parent_info($pid, $statline) . " :: $process_pid";
2138c2ecf20Sopenharmony_ci				}
2148c2ecf20Sopenharmony_ci			}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci			# Unnecessary in this script. Uncomment if required
2178c2ecf20Sopenharmony_ci			# $cpus = $2;
2188c2ecf20Sopenharmony_ci			# $timestamp = $3;
2198c2ecf20Sopenharmony_ci		} else {
2208c2ecf20Sopenharmony_ci			next;
2218c2ecf20Sopenharmony_ci		}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		# Perl Switch() sucks majorly
2248c2ecf20Sopenharmony_ci		if ($tracepoint eq "mm_page_alloc") {
2258c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_ALLOC}++;
2268c2ecf20Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_free") {
2278c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_FREE}++
2288c2ecf20Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_free_batched") {
2298c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_FREE_BATCHED}++;
2308c2ecf20Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_pcpu_drain") {
2318c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_PCPU_DRAIN}++;
2328c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_DRAINED}++;
2338c2ecf20Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_alloc_zone_locked") {
2348c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED}++;
2358c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_REFILLED}++;
2368c2ecf20Sopenharmony_ci		} elsif ($tracepoint eq "mm_page_alloc_extfrag") {
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci			# Extract the details of the event now
2398c2ecf20Sopenharmony_ci			$details = $5;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci			my ($page, $pfn);
2428c2ecf20Sopenharmony_ci			my ($alloc_order, $fallback_order, $pageblock_order);
2438c2ecf20Sopenharmony_ci			my ($alloc_migratetype, $fallback_migratetype);
2448c2ecf20Sopenharmony_ci			my ($fragmenting, $change_ownership);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci			if ($details !~ /$regex_fragdetails/o) {
2478c2ecf20Sopenharmony_ci				print "WARNING: Failed to parse mm_page_alloc_extfrag as expected\n";
2488c2ecf20Sopenharmony_ci				next;
2498c2ecf20Sopenharmony_ci			}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{MM_PAGE_ALLOC_EXTFRAG}++;
2528c2ecf20Sopenharmony_ci			$page = $1;
2538c2ecf20Sopenharmony_ci			$pfn = $2;
2548c2ecf20Sopenharmony_ci			$alloc_order = $3;
2558c2ecf20Sopenharmony_ci			$fallback_order = $4;
2568c2ecf20Sopenharmony_ci			$pageblock_order = $5;
2578c2ecf20Sopenharmony_ci			$alloc_migratetype = $6;
2588c2ecf20Sopenharmony_ci			$fallback_migratetype = $7;
2598c2ecf20Sopenharmony_ci			$fragmenting = $8;
2608c2ecf20Sopenharmony_ci			$change_ownership = $9;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci			if ($fragmenting) {
2638c2ecf20Sopenharmony_ci				$perprocesspid{$process_pid}->{HIGH_EXT_FRAG}++;
2648c2ecf20Sopenharmony_ci				if ($fallback_order <= 3) {
2658c2ecf20Sopenharmony_ci					$perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_SEVERE}++;
2668c2ecf20Sopenharmony_ci				} else {
2678c2ecf20Sopenharmony_ci					$perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_MODERATE}++;
2688c2ecf20Sopenharmony_ci				}
2698c2ecf20Sopenharmony_ci			}
2708c2ecf20Sopenharmony_ci			if ($change_ownership) {
2718c2ecf20Sopenharmony_ci				$perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_CHANGED}++;
2728c2ecf20Sopenharmony_ci			}
2738c2ecf20Sopenharmony_ci		} else {
2748c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{EVENT_UNKNOWN}++;
2758c2ecf20Sopenharmony_ci		}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		# Catch a full pcpu drain event
2788c2ecf20Sopenharmony_ci		if ($perprocesspid{$process_pid}->{STATE_PCPU_PAGES_DRAINED} &&
2798c2ecf20Sopenharmony_ci				$tracepoint ne "mm_page_pcpu_drain") {
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{HIGH_PCPU_DRAINS}++;
2828c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_DRAINED} = 0;
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		# Catch a full pcpu refill event
2868c2ecf20Sopenharmony_ci		if ($perprocesspid{$process_pid}->{STATE_PCPU_PAGES_REFILLED} &&
2878c2ecf20Sopenharmony_ci				$tracepoint ne "mm_page_alloc_zone_locked") {
2888c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{HIGH_PCPU_REFILLS}++;
2898c2ecf20Sopenharmony_ci			$perprocesspid{$process_pid}->{STATE_PCPU_PAGES_REFILLED} = 0;
2908c2ecf20Sopenharmony_ci		}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		if ($sigint_pending) {
2938c2ecf20Sopenharmony_ci			last EVENT_PROCESS;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cisub dump_stats {
2998c2ecf20Sopenharmony_ci	my $hashref = shift;
3008c2ecf20Sopenharmony_ci	my %stats = %$hashref;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	# Dump per-process stats
3038c2ecf20Sopenharmony_ci	my $process_pid;
3048c2ecf20Sopenharmony_ci	my $max_strlen = 0;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	# Get the maximum process name
3078c2ecf20Sopenharmony_ci	foreach $process_pid (keys %perprocesspid) {
3088c2ecf20Sopenharmony_ci		my $len = length($process_pid);
3098c2ecf20Sopenharmony_ci		if ($len > $max_strlen) {
3108c2ecf20Sopenharmony_ci			$max_strlen = $len;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	$max_strlen += 2;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	printf("\n");
3168c2ecf20Sopenharmony_ci	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s   %8s %8s %8s   %8s %8s %8s %8s %8s %8s\n",
3178c2ecf20Sopenharmony_ci		"Process", "Pages",  "Pages",      "Pages", "Pages", "PCPU",  "PCPU",   "PCPU",    "Fragment",  "Fragment", "MigType", "Fragment", "Fragment", "Unknown");
3188c2ecf20Sopenharmony_ci	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s   %8s %8s %8s   %8s %8s %8s %8s %8s %8s\n",
3198c2ecf20Sopenharmony_ci		"details", "allocd", "allocd",     "freed", "freed", "pages", "drains", "refills", "Fallback", "Causing",   "Changed", "Severe", "Moderate", "");
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s   %8s %8s %8s   %8s %8s %8s %8s %8s %8s\n",
3228c2ecf20Sopenharmony_ci		"",        "",       "under lock", "direct", "pagevec", "drain", "", "", "", "", "", "", "", "");
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	foreach $process_pid (keys %stats) {
3258c2ecf20Sopenharmony_ci		# Dump final aggregates
3268c2ecf20Sopenharmony_ci		if ($stats{$process_pid}->{STATE_PCPU_PAGES_DRAINED}) {
3278c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_DRAINS}++;
3288c2ecf20Sopenharmony_ci			$stats{$process_pid}->{STATE_PCPU_PAGES_DRAINED} = 0;
3298c2ecf20Sopenharmony_ci		}
3308c2ecf20Sopenharmony_ci		if ($stats{$process_pid}->{STATE_PCPU_PAGES_REFILLED}) {
3318c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_REFILLS}++;
3328c2ecf20Sopenharmony_ci			$stats{$process_pid}->{STATE_PCPU_PAGES_REFILLED} = 0;
3338c2ecf20Sopenharmony_ci		}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci		printf("%-" . $max_strlen . "s %8d %10d   %8d %8d   %8d %8d %8d   %8d %8d %8d %8d %8d %8d\n",
3368c2ecf20Sopenharmony_ci			$process_pid,
3378c2ecf20Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_ALLOC},
3388c2ecf20Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED},
3398c2ecf20Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_FREE},
3408c2ecf20Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_FREE_BATCHED},
3418c2ecf20Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_PCPU_DRAIN},
3428c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_DRAINS},
3438c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_PCPU_REFILLS},
3448c2ecf20Sopenharmony_ci			$stats{$process_pid}->{MM_PAGE_ALLOC_EXTFRAG},
3458c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAG},
3468c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAGMENT_CHANGED},
3478c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAGMENT_SEVERE},
3488c2ecf20Sopenharmony_ci			$stats{$process_pid}->{HIGH_EXT_FRAGMENT_MODERATE},
3498c2ecf20Sopenharmony_ci			$stats{$process_pid}->{EVENT_UNKNOWN});
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cisub aggregate_perprocesspid() {
3548c2ecf20Sopenharmony_ci	my $process_pid;
3558c2ecf20Sopenharmony_ci	my $process;
3568c2ecf20Sopenharmony_ci	undef %perprocess;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	foreach $process_pid (keys %perprocesspid) {
3598c2ecf20Sopenharmony_ci		$process = $process_pid;
3608c2ecf20Sopenharmony_ci		$process =~ s/-([0-9])*$//;
3618c2ecf20Sopenharmony_ci		if ($process eq '') {
3628c2ecf20Sopenharmony_ci			$process = "NO_PROCESS_NAME";
3638c2ecf20Sopenharmony_ci		}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_ALLOC} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC};
3668c2ecf20Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_ALLOC_ZONE_LOCKED} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED};
3678c2ecf20Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_FREE} += $perprocesspid{$process_pid}->{MM_PAGE_FREE};
3688c2ecf20Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_FREE_BATCHED} += $perprocesspid{$process_pid}->{MM_PAGE_FREE_BATCHED};
3698c2ecf20Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_PCPU_DRAIN} += $perprocesspid{$process_pid}->{MM_PAGE_PCPU_DRAIN};
3708c2ecf20Sopenharmony_ci		$perprocess{$process}->{HIGH_PCPU_DRAINS} += $perprocesspid{$process_pid}->{HIGH_PCPU_DRAINS};
3718c2ecf20Sopenharmony_ci		$perprocess{$process}->{HIGH_PCPU_REFILLS} += $perprocesspid{$process_pid}->{HIGH_PCPU_REFILLS};
3728c2ecf20Sopenharmony_ci		$perprocess{$process}->{MM_PAGE_ALLOC_EXTFRAG} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC_EXTFRAG};
3738c2ecf20Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAG} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAG};
3748c2ecf20Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAGMENT_CHANGED} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_CHANGED};
3758c2ecf20Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAGMENT_SEVERE} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_SEVERE};
3768c2ecf20Sopenharmony_ci		$perprocess{$process}->{HIGH_EXT_FRAGMENT_MODERATE} += $perprocesspid{$process_pid}->{HIGH_EXT_FRAGMENT_MODERATE};
3778c2ecf20Sopenharmony_ci		$perprocess{$process}->{EVENT_UNKNOWN} += $perprocesspid{$process_pid}->{EVENT_UNKNOWN};
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cisub report() {
3828c2ecf20Sopenharmony_ci	if (!$opt_ignorepid) {
3838c2ecf20Sopenharmony_ci		dump_stats(\%perprocesspid);
3848c2ecf20Sopenharmony_ci	} else {
3858c2ecf20Sopenharmony_ci		aggregate_perprocesspid();
3868c2ecf20Sopenharmony_ci		dump_stats(\%perprocess);
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci# Process events or signals until neither is available
3918c2ecf20Sopenharmony_cisub signal_loop() {
3928c2ecf20Sopenharmony_ci	my $sigint_processed;
3938c2ecf20Sopenharmony_ci	do {
3948c2ecf20Sopenharmony_ci		$sigint_processed = 0;
3958c2ecf20Sopenharmony_ci		process_events();
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		# Handle pending signals if any
3988c2ecf20Sopenharmony_ci		if ($sigint_pending) {
3998c2ecf20Sopenharmony_ci			my $current_time = time;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci			if ($sigint_exit) {
4028c2ecf20Sopenharmony_ci				print "Received exit signal\n";
4038c2ecf20Sopenharmony_ci				$sigint_pending = 0;
4048c2ecf20Sopenharmony_ci			}
4058c2ecf20Sopenharmony_ci			if ($sigint_report) {
4068c2ecf20Sopenharmony_ci				if ($current_time >= $sigint_received + 2) {
4078c2ecf20Sopenharmony_ci					report();
4088c2ecf20Sopenharmony_ci					$sigint_report = 0;
4098c2ecf20Sopenharmony_ci					$sigint_pending = 0;
4108c2ecf20Sopenharmony_ci					$sigint_processed = 1;
4118c2ecf20Sopenharmony_ci				}
4128c2ecf20Sopenharmony_ci			}
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci	} while ($sigint_pending || $sigint_processed);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cisignal_loop();
4188c2ecf20Sopenharmony_cireport();
419