# test for checking monotonic timer (PR3916)
set test "gtod"
if {![installtest_p]} { untested $test; continue }

set wd [pwd]
set filename "$srcdir/$subdir/gtod.c"

target_compile $filename $wd/gtod executable ""

# Return the absolute difference between num1 and num2
proc abs_diff { num1 num2 } {
    if {$num1 > $num2} {
	return [expr $num1 - $num2]
    }
    return [expr $num2 - $num1]
}

# We're looking for lines in the following format:
#
#   :00 1336494634008794 appl
#   :00 1336494634008971 kern
#   :00 1336494634009194 prog
#   :01 1336494634009196 appl
#   :01 1336494634009199 kern
#   :01 1336494634009203 prog
#   ...
#
# The lines should be in the order 'appl', 'kern', and 'prog', but we
# don't insist on it.  If systemtap's time is a bit ahead of the
# kernel's real time, the 'kern' line can appear first. The first
# number, the count, must match on each of the 3 lines.

for {set i 0} { $i < 3 } {incr i } {
    if {$i == 0} {
	# non interval (check timer drift in short range)
	set test "gtod (short range)"
	spawn $srcdir/$subdir/gtod.sh $srcdir/$subdir/gtod.stp $wd/gtod
    } elseif {$i == 1} {
	# 10ms interval (check timer drift in middle range)
	set test "gtod (10ms interval)"
	spawn $srcdir/$subdir/gtod.sh $srcdir/$subdir/gtod.stp $wd/gtod 10000
    } else {
	# 100ms interval (calm down processors and CPU freq might be
	# changed)
	set test "gtod (100ms interval)"
	spawn $srcdir/$subdir/gtod.sh $srcdir/$subdir/gtod.stp $wd/gtod 100000
    }

    # 'ok' is the number of passes
    set ok 0

    # 'iteration_num' contains the current iteration number for each
    # of the 3 sets of lines
    set iteration_num(appl) -1
    set iteration_num(kern) -1
    set iteration_num(prog) -1

    # 'us_time' contains the reported time for each of the 3 sets of lines
    set us_time(appl) 0
    set us_time(kern) 0
    set us_time(prog) 0

    # 'max_diff' is used to remember the maximum difference between
    # systemtap's time and the kernel's time
    set max_diff 0

    # 'variance' is the maximum number of microseconds difference
    # between systemtap's time and the kernel's time that we'll accept
    set variance 500

    expect {
	-timeout 120

	# We found a 'appl|kern|prog' line
	-re {^\:([0-9]+) ([0-9]+) (appl|kern|prog)\r\n} {
	    set type $expect_out(3,string)
	    set iteration_num($type) $expect_out(1,string)
	    set us_time($type) $expect_out(2,string)

	    # If we've seen all the lines for this iteration, check
	    # the times.
	    if {$iteration_num(appl) == $iteration_num(kern) \
		    && $iteration_num(kern) == $iteration_num(prog)} {
		set appl_diff [abs_diff $us_time(appl) $us_time(kern)]
		set prog_diff [abs_diff $us_time(prog) $us_time(kern)]
		if {$appl_diff < $variance && $prog_diff < $variance} {
		    incr ok
		} else {
		    verbose -log "difference of ($appl_diff, $prog_diff) for iteration $iteration_num(kern) is too large"
		}
		if {$appl_diff > $max_diff} { set max_diff $appl_diff }
		if {$prog_diff > $max_diff} { set max_diff $prog_diff }
	    }
	    exp_continue
	}

	timeout { fail "$test (timeout)" }
	eof { }
    }
    catch {close}; catch {wait}
    if {$max_diff > 0} {
	verbose -log "maximum time difference was $max_diff us"
    }
    if {$ok == 100} { pass "$test ($ok)" } { fail "$test ($ok)" }
}

exec rm -f $wd/gtod


