#!/usr/bin/perl
#
# This is a basic script that takes a stream of data from ftrace
# that presumably has stack traces and dumps the frequency of call
# stacks that triggered each event
use strict;
use Getopt::Long;
use Data::Dumper;

my $filtered;
my $filtered_regex;
my $restricted;
my $opt_filter;
my $opt_filter_regex;
my $opt_restrict;

my %filter;
my %filter_regex;
my %restrict;

GetOptions(
	'filter=s'   		=> \$opt_filter,
	'filter-regex=s'	=> \$opt_filter_regex,
	'restrict=s'		=> \$opt_restrict,
	);

if ($opt_filter ne "") {
	$filtered = 1;
	%filter = map { $_,1 } split(/,/, $opt_filter);
}

if ($opt_filter_regex ne "") {
	$filtered_regex = 1;
	%filter_regex = map { $_,1 } split(/,/, $opt_filter_regex);
}

if ($opt_restrict ne "") {
	$restricted = 1;
	%restrict = map { $_,1 } split(/,/, $opt_restrict);
}

# Read the raw output of the script
my $line;
my %unique_event_counts;
my $trace = "";
my $reading = 0;

while (!eof(STDIN)) {
	my $line = <STDIN>;
	next if $line =~ /No such file or directory/;
	next if $line =~ /\[LOST/;

	# Watch for the beginning of an event
	if ($line =~ /^.*\[[0-9]{3}\] /) {
		next if $line =~ /<stack trace>/;
		$line =~ s/.*[0-9]://;
		$line =~ s/page=[0-9a-f]*/page=xxx/;
		$line =~ s/pfn=[0-9]*/pfn=xxx/;

		my $event = $line;

		if ($trace ne "") {
			$unique_event_counts{$trace}++;
		}

		$reading = 0;
		if ($filtered || $restricted) {
			my @elements = split /\s+/, $event;
			$elements[1] =~ s/:$//;
			next if $restricted && $restrict{$elements[1]} != 1;
			next if $filtered && $filter{$elements[1]} == 1;
			if ($filtered_regex) {
				my $break = 0;
				foreach my $pattern (keys %filter_regex) {
					if ($event =~ /$pattern/) {
						$break = 1;
						last;
					}
				}
				next if $break;
			}
		}

		$trace = "$event\n";
		$reading = 1;
		next;
	}
	next if !$reading;
	$trace .= $line;
}

# Dump the unique traces
foreach my $trace (sort {$unique_event_counts{$b} <=> $unique_event_counts{$a}} keys %unique_event_counts) {
	if ($ENV{MONITOR_LOG} ne "") {
		printf OUTPUT "Event count:		%8d\n", $unique_event_counts{$trace};
		print  OUTPUT "$trace\n";
	} else {
		printf "Event count:		%8d\n", $unique_event_counts{$trace};
		print "$trace\n";
	}
}
