#!/usr/bin/perl

$slice = 20;	# seconds
while (<>) {
    @curr = split;
    if ($curr[0] =~ /cpu\d/) {
	$sched_cnt += $curr[7];
	next;
    }
    next if (/^$/);
    if ($curr[0] eq "version") {
	if ($curr[1] != 1) {
	    die "Version mismatch. Update this tool.\n";
	}
	next;
    }
    #
    # format of line in /proc/schedstat
    #
    # tag 1 2 3 4 5 6 7 8 9 10 11 12
    #
    # tag is "cpuN" or "cpu".  Right now, we ignore "cpuN" lines (this tool
    # doesn't collate per-cpu statistics, although it would be trivial to
    # do so.)
    #
    # version == 1
    # NOTE: the active queue is considered empty if it has only one process
    #	in it, since obviously the process calling sched_yield is that process.
    #
    # First four are sched_yield statistics:
    #     1) # of times both the active and the expired queue were empty
    #     2) # of times just the active queue was empty
    #     3) # of times just the expired queue was empty
    #     4) # of times sched_yield() was called
    #
    # Next two are schedule() statistics:
    #     5) # of times the active queue had at least one other process on it.
    #     6) # of times we switched to the expired queue and reused it
    #     7) # of times schedule() was called
    #
    # Last five are statistics dealing with load balancing:
    #     8) # of times load_balance was called at an idle tick
    #     9) # of times load_balance was called from schedule()
    #	 10) # of times load_balance was called
    #	 11) sum of imbalances discovered (if any) with each call to
    #        load_balance
    #	 12) # of times load_balance was called when we did not find a
    #        "busiest" queue
    #
    $curr[7] = $sched_cnt;
    foreach $i (1..12) {
	$diff[$i] = $curr[$i] - $prev[$i];
    }

    print "@curr\n";
    printf "%02d:%02d:%02d--------------------------------------------------------------\n",
	$tick*$slice/3600, ($tick*$slice/60)%60, ($tick*$slice)%60;

    printf "    %7d          sys_sched_yield()\n", $diff[4];
    printf "    %7d(%6.2f%%) found (only) active queue empty on current cpu\n",
	$diff[2]-$diff[1], $diff[4] ? (100*($diff[2]-$diff[1])/$diff[4]) : 0;
    printf "    %7d(%6.2f%%) found (only) expired queue empty on current cpu\n",
	$diff[3], $diff[4] ? (100*$diff[3]/$diff[4]) : 0;
    printf "    %7d(%6.2f%%) found both queues empty on current cpu\n",
	$diff[1], $diff[4] ? (100*$diff[1]/$diff[4]) : 0;
    printf "    %7d(%6.2f%%) found neither queue empty on current cpu\n\n",
	$diff[4]-($diff[3]+$diff[2]),
	$diff[4] ? 100*($diff[4]-($diff[3]+$diff[2]))/$diff[4] : 0;

    printf "    %7d          schedule()\n", $diff[7];
    printf "    %7d(%6.2f%%) switched active and expired queues\n",
	$diff[6], $diff[7] ? (100*$diff[6]/$diff[7]) : 0;
    printf "    %7d(%6.2f%%) used existing active queue\n\n",
	$diff[5]-$diff[6], $diff[7] ? (100*($diff[5]-$diff[6])/$diff[7]) : 0;

    printf "    %7d          load_balance()\n", $diff[10];
    printf "    %7d(%6.2f%%) called while idle\n", $diff[8],
	100*$diff[8]/$diff[10];
    printf "    %7d(%6.2f%%) called while busy\n", $diff[10] - $diff[8],
	100*($diff[10] - $diff[8])/$diff[10];
    printf "    %7d(%6.2f%%) called from schedule()\n", $diff[9],
	100*$diff[9]/$diff[10];
    printf "             %7d no \"busiest\" queue found\n",$diff[12];
    if ($diff[10]-$diff[12]) {
	$imbalance = $diff[11] / ($diff[10]-$diff[12]);
	if ($imbalance < 10) {
	    printf "             %7.3f average imbalance (over %d)\n",
		$imbalance, $diff[10]-$diff[12];
	} elsif ($imbalance < 100) {
	    printf "            %8.2f average imbalance (over %d)\n",
		$imbalance, $diff[10]-$diff[12];
	} else {
	    printf "           %9.1f average imbalance (over %d)\n",
		$imbalance, $diff[10]-$diff[12];
	}
    }
    else {
	printf "                     no imbalances\n";
    }
    printf("\n");
    @prev = @curr;
    $tick++;
}
