#!/usr/local/bin/perl

# This file converts from the raw HP srt format to the simple ascii format
# we've been using for simulations.  Based on a script from 
# douglis@research.panasonic.com.
# Sriram R, David K
# $Id: srt-extract,v 2.0 94/07/17 18:33:47 dfk Exp $

# CHANGE THE FOLLOWING LINE TO THE DIRECTORY THAT INCLUDES sprite-option.pl.
unshift(@INC, "/usr/local/lib/perl"); 
require "ctime.pl";		# standard perl library file
require "sprite-option.pl";	# inherited from sprite; bundled with this file

$debugging = 0;			# enables debugging
$maxrecs = -1;			# limit number of output records if != -1
                                # info about statistics

# comes from option.pl

$optFlags = $OPT_OPTIONS_FIRST | $OPT_ALLOW_CLUSTERING | $OPT_NO_SPACE;

@options = (
    $OPT_NIL, $OPT_DOC, $OPT_NIL, 
	"Usage: srt-extract [options] [file]",
    "D", $OPT_TRUE, *debugging, "Debug",
    "M", $OPT_INT, *maxrecs, "Maximum number of records to output"
);
&Opt_Parse(*ARGV, @options, $optFlags);

$rec = 0;

printf("Max records to output: %d\n", $maxrecs) if $debugging;

# open input file if arg specified
open (STDIN, $ARGV[0]) || die "Can't open $ARGV[0]: $!\n"
    if $ARGV[0];

# skip past header--very simple test...
while ((($ch = getc(STDIN)) ne  "") && ($ch ne "")) {
    printf(STDERR "%s", $ch) if $debugging > 1;
}

# sectorno  sec  start     stop     size    write? metadata? sync?
format STDOUT = 
@>>>>>>>> @>>>>>>> @>>>>>> @>>>>>>>> @>>>>> @> @> @>
$sectno, $sec, $starttime, $stoptime, $size, $write_op, $meta, $synch
.

# loop, reading all records
# trace formats are described in the C++ files, mostly tr_shortIO.C 
# and tr_header.H.  
while (1) {
    $len = read(STDIN, $data, 16); # Read the header
    if ($len == 0) { goto done };
    ($size, $version, $type, $sec, $usec) = unpack('NnnNN', $data); 

    die "Bad size, record " . $rec . "\n" if $size - 16 > 40;
    $len = read(STDIN, $data, $size-16); # Read the rest of the record
    die "Error parsing input, record " . $rec . "\n" if $len != $size - 16;

    # limit to version==4.
    if ($type == 1 && $version == 4) {
	($start, $stop, $size, $sectno, $devno, $driverType, 
	 $cylno, $ioflags, $info, $queueLen) = unpack('N10', $data);
	
	printf(STDERR "SRI_ALERT: \t %d %d %d %d %d %d %d\n",
	       $devno, $diskno, $driverType, $sectno, $start, $stop, $size) 
	    if $debugging; 

	# determination of whether operation is for read, or is metadata, 

	# based on documentation in tr_shortIO.C and tr_ioinfo.H.    
	# We assume it is data if it has type 1 or 0 and refer to it
	# as "metadata" otherwise (even if it is swap, or whatever.)
	$write_op = (~$ioflags) & 1;
	$meta = &metadata($info); 

	# unless otherwise marked explicitly synchronous, let it be asynch
	# note we do not care about the ASYNC bit
	#  TRB_SYNC = 0x01000000
	#  TRB_ASYNC = 0x100
	if ($ioflags & 0x01000000) {
	    $synch = 1;
	} else {
	    $synch = 0;		# default asynchronous
	}
	
	$diskno = (($devno >> 8) &0xff);

# We only pick out the stuff from disk 6, which we know is a 97560 on snake
# and we toss out the really long-time requests (those > 100 msec), because
# they may be thermal-recalibration periods...

	if (($driverType == 5) && ($diskno == 6) && ($stop - $start < 100000)){

# And we convert the 4 time values into three, in sec/usec of start time
# (with usec < 1000000) and sec/usec of finish time.  This will enable us
# to use a 2-key sort to sort output by start time later.
	    
	    $starttime = $usec + $start;
	    $stoptime = $usec + $stop;

	    $seconds = int($starttime / 1000000.);
	    $sec += $seconds;
	    $starttime -= $seconds * 1000000.;
	    $stoptime -= $seconds * 1000000.;
	    write; 
	}
    }

    $rec++;
    last if ($maxrecs > 0 && $rec >= $maxrecs);
}

done: ;

sub metadata {
    local($type) = @_;
    local($buf_shift, $buf_mask, $regular_data, $buftype) = (16, 0x0000000f, 1);
    $buftype = ($type >> $buf_shift) & $buf_mask;
#    printf("&metadata(%x) called. buftype %x\n", $type, $buftype) if $debugging;
    return(0) if ($buftype == $regular_data || $buftype == 0);
    return(1);
}
# last page is for gnuemacs.

# Local Variables:
# mode:perl
# End:
