#
# timer_top.pl
#
# Timer Top: gets timers info exported by kernel in /proc/top_info and
# organizes and shows useful info in the screen. Its main purpose is to
# test the dynamic tick patch by Tony Lindgren and Tuukka Tikkanen.
# Idea is to evolve this in order to get more useful info
# It needs the System.map file to be in the same directory
#
# Copyright (C) 2005 Insituto Nokia de Tecnologia - INdT - Manaus
# Written by Daniel Petrini <daniel.petrini@indt.org.br> and
#            Ilias Biris <ilias.biris@indt.org.br>
#
# With some code from pmstats-0.2 by Tony Lindgren
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
# 
#!/usr/bin/perl

open (INFILE, "System.map") || die ("cannot open file\n");

my ($interval) = $ARGV[0];

if ($interval eq "") {
    printf("Usage: %s interval_in_seconds\n", $0);	
    exit(1);
}

%sys_map_lines=();
%top_lines=();
%numb_func=();
%diff_time=();

while(<INFILE>) {
    chomp $_;
    if( $_ ne "" ) {
	$sys_map_line = substr($_, 0, 8);	
	$sys_map_lines{$sys_map_line}=substr($_, 10, length($_));
    }
}
close(INFILE);


sub read_top_info {

    open (INFILE2, "/proc/top_info") || die ("cannot open file\n");

    while(<INFILE2>){
	if( $_ !~ m/^Function\scounter/ ){
	    $func_top = substr( $_, 0, 8);
	    $numb_top = substr( $_, 9, 8);
	    if( $sys_map_lines{$func_top} ne "" ){
		# Check if there is variation for that timer function
		if ( ($numb_top) != ($numb_func{$func_top})  ) {
		    $top_lines{$func_top} = $sys_map_lines{$func_top};
		    $diff_time{$func_top} = $numb_top - $numb_func{$func_top};	#Get the difference
		    $numb_func{$func_top} = $numb_top;
	    	} else {
		    $top_lines{$func_top} = "";
		} 
	    }
	}
    }
    close(INFILE2);
}

# 
# Based in code from pmstats-0.2 from Tony Lindgren
#
sub read_timer_ticks() {
    my $buf = "";
    open(INFILE3, "/proc/interrupts") or die "Could not open file\n";
    while (<INFILE3>) {
	# It looks for the string 'timer' ...
	if ($_ =~ m/timer/ ) { 
	    $_ =~ s/ +/ /g;
	    my ($tag, $val) = split(": ", $_ );
	    $tag =~ s/ +//g;
	    ($val) = split(" ", $val);
	    close (INFILE3);
	    return($val);
	}
    }
    close (INFILE3);
    return 0;
}

#
# Main routine. Refresh screen every $interval seconds
#
while (1) {

    read_top_info();

    system("clear");

    print "Timer Top v0.9.2 \n";

    my $ticks = read_timer_ticks();
    my $delta_ticks = ($ticks - $last_ticks) / $interval;
    if ($last_ticks == 0) {
	$delta_ticks = 0; 
    }
    $last_ticks = $ticks;

    printf "Ticks: %d HZ\n", $delta_ticks;
    print "Address      Count   Freq(Hz)   Function\n";

    while(($item, $value) = each(%top_lines)) {
	if ( $top_lines{$item} ne "" ) {
	    chomp ($numb_func{$item});
	    printf "%s|%10s|%9.2f|%s\n", $item, $numb_func{$item}, $diff_time{$item}/$interval, $value;
	}
    }
    sleep $interval;
}
