#!/usr/bin/perl

# Author: Andrew Theurer
#
# usage: proc-interrupts-postprocess <dir>  dir = directory where proc-interrupts.txt can be found
#
# The purpose of this script is to
# -output the chart data in JSON format (proc-interrupts.js)
# -output html file (proc-interrupts.html) with embedded javascript, using d3.js libraries
#
# The input file that this scripts processes must be in the format which is generated by proc-interrupts-datalog

use strict;
use warnings;

use lib $ENV{'pbench_lib_dir'};
no lib ".";
use GenData qw(gen_data);

my $dir=$ARGV[0];
my $timestamp;
my $timestamp_ms;
my $line;
my $cpu;
my @cpulist;
my $int;
my %interrupt_count;
my %int_rate; # per int log of ints/second
my %total_int_rate; # per int log of ints/second
my $this_int_rate;
my $count_diff;
my $duration;
my $count;
my $last_timestamp_ms;
my $last_count;
my $i;
my %graph_type;
my %graph_threshold;

open(INTERRUPTS_TXT, "$dir/proc-interrupts-stdout.txt") || die "could not find $dir/proc-interrupts-stdout.txt\n";
while (my $line = <INTERRUPTS_TXT>) {
	chomp $line;
	# timestamp: 1394048617.043209234
	#            CPU0       CPU1       CPU2       CPU3       
	#   0:         25          0          0          0   IO-APIC-edge      timer
	#   1:         10          0          0          0   IO-APIC-edge      i8042
	# NMI:          0          0          0          0   Non-maskable interrupts
	# LOC:      48687      45068      40188      65602   Local timer interrupts
	# SPU:          0          0          0          0   Spurious interrupts

	if ( $line =~ /^timestamp:\s(\d+\.\d+)/ ) {
		$timestamp = $1;
		$timestamp_ms = 1000 * $timestamp;
		next;
	}
	# this line describes how many CPUs we have
	if ($line =~ /\s+(CPU\d+\s*)+/) {
		$line =~ s/^\D+//;
		$line =~ s/\D+$//;
		@cpulist = split(/\D+CPU/, $line);
		next;
	}

	# this line contains counts for a specific IRQ, broken down by CPU
	if ($line =~ s/\s*(\w+):// ) {
		$int = "$1";
                # the anchored (at both ends) match makes sure that
                # only numbers match here; things like "IPI0" (which
                # happens on aarch64 e.g.) don't match.
		if ($int =~ /^\d+$/) {
			$int = sprintf "%03d", $int;
		}
		my %cpuvals;
		if ($int =~ /(ERR|MIS)/) {
			$line =~ s/\s+(\d+)//;
			$count = $1;
			for $cpu (@cpulist) {
				$cpuvals{$cpu} = $count;
			}
		} else {
			for $cpu (@cpulist) {
				$line =~ s/\s+(\d+)//;
				$count = $1;
				$cpuvals{$cpu} = $count;
			}
		}
		$line =~ s/\s+//;
		$line =~ s/,/ /g;
		$line =~ s/\s+/_/g;
		my $desc = "$line";
		if ($desc ne "") {
			$desc = "_" . $desc;
		}
		$int = "IRQ_" . $int . $desc;
		for $cpu (@cpulist) {
			my $newcpu = sprintf "CPU_%03d", $cpu;
			$interrupt_count{$int}{$newcpu}{$timestamp_ms} = $cpuvals{$cpu};
		}
	}
}
close(INTERRUPTS_TXT);

# We want to have two graph types:
# -graphs which plots interrupt rates for interrupts deliver to only a specific CPU.  Each series is a int-rate for for a different IRQ but only from this CPU
# -graphs which plot a specific IRQ and each series is a int-rate for the same IRQ, but a different CPU
for $int (sort keys %interrupt_count) {
	for $cpu (sort keys %{ $interrupt_count{$int} }) {
		$last_count = 0;
		$last_timestamp_ms = 0;
		for $timestamp_ms (sort {$a<=>$b} keys %{ $interrupt_count{$int}{$cpu} } ) {
			$count = $interrupt_count{$int}{$cpu}{$timestamp_ms};
			if ($last_timestamp_ms != 0) {
				$count_diff = $count - $last_count;
				$duration = ($timestamp_ms - $last_timestamp_ms)/1000;
				$this_int_rate = $count_diff / $duration;
				$int_rate{"proc-interrupts-by-irq"}{$int}{$cpu}{$timestamp_ms} = $this_int_rate;
				$int_rate{"proc-interrupts-by-cpu"}{$cpu}{$int}{$timestamp_ms} = $this_int_rate;
			}
			$last_count = $count;
			$last_timestamp_ms = $timestamp_ms;
		} # for each $timestamp
	} # for each $cpu
} # for each $int

my $label;
my $graph;
foreach $graph (keys %int_rate) {
	foreach $label (keys %{ $int_rate{$graph}} ) {
		$graph_type{$graph}{$label} = "stackedAreaChart";
		$graph_threshold{$graph}{$label} = 100; # don't graph any interrupt lower than 100/sec
	}
}
gen_data(\%int_rate, \%graph_type, \%graph_threshold, $dir);
