kernel_stats-irix6.x.tcl 7.07 KB
#
# Copyright (C) 1996-1998 by the Board of Trustees
#    of Leland Stanford Junior University.
# 
# This file is part of the SimOS distribution. 
# See LICENSE file for terms of the license. 
#

## 
## kernel_stats.tcl
##
## Breakdown of operating system activity by kernel thread.
## 

timing create kstats
log [timing fields]

###
### thread tracking
###

proc kstatsSwitch args {
    global PROCESS PID KTID CPU M R PARAM

    # Concat process name and kernel thread id
    set args [linsert $args 0 $PROCESS($CPU)-$PID($CPU)]

    if { $PARAM(MACHINE.Count) == 1 } {
        eval timing switch kstats $PID($CPU) $args
    } else {
        eval timing switch kstats $M($CPU)_$PID($CPU) machine$M($CPU) $args
    }

    if ![info exists kstatsThreadState([ktname])] {
        set kstatsThreadState([ktname]) "runq"
    } else {
        timing end kstats $kstatsThreadState([ktname])
    }
}

annotation set simos enter {
    if {$PROCESS($CPU) == "idle"} {
        kstatsSwitch kernel idle
    } elseif {$PROCESS($CPU) == "boot"} {
        kstatsSwitch kernel
    } else {
        set kstatsThreadState([ktname]) "startup"
        kstatsSwitch
    }
}

if { $PARAM(MACHINE.Count) == 1 } {
    proc ktname {} {
        global PID KTID CPU
        return $KTID($CPU)
    }
} else {
    proc ktname {} {
        global M KTID CPU
       	return $M($CPU)_$KTID($CPU)
    }
}

proc kstatsState {id} {
    if [info exists kstatsThreadState($id)] {
        return $kstatsThreadState($id)
    } else {
#        return fork
        return foo
    }
}

annotation set osEvent procexit {
#    timing terminate kstats [ktname]
#    unset kstatsThreadState([ktname])
}


##### WATCH OUT FOR EXEC NOT HAVING A PID

annotation set osEvent switchIn {
    if {$PROCESS($CPU) == "idle"} {
        kstatsSwitch idleproc
    } elseif {$PROCESS($CPU) == "runq"} {
        kstatsSwitch runqproc
    } else {
        kstatsSwitch [kstatsState [ktname]]
    }
}

annotation set osEvent procexit {
    console "PROCEXIT on $CPU - $PID($CPU)\n"
    if { $PARAM(MACHINE.Count) == 1 } {
        timing terminate kstats $PID($CPU)
    } else {
        timing terminate kstats $M($CPU)_$PID($CPU)
    }
}

###
### kernel services
###
annotation set utlb {
    timing start kstats utlb
}

annotation set exc {
    if {[timing current kstats] == "utlb"} {
        timing end kstats utlb
    }

    set exc [expr ($cause >> 2) & 0x1F]

    if {$exc == 0} {
        timing start? kstats intrdisp
    } elseif {$exc == 8} {
        timing start kstats syscall([expr $v0])
    } else {
        timing start? kstats exc($exc)
    }
}

annotation set inst rfe {
    set current [timing current kstats]
    if {$current != "ROOT"} {
        timing end kstats $current
    } else {
        console "KSTATS: CPU $CPU CYCLE $CYCLES: bad rfe pid $PID($CPU) ktid $KTID($CPU) $current\n"
    }
}

annotation set osEvent startIdle {
    timing start kstats idle
}

annotation set osEvent endIdle {
    timing end kstats idle
}

annotation set osEvent startSync {
    timing start kstats sync
}

annotation set osEvent endSync {
    timing end kstats sync
}

##
## page faults
##

annotation set pc kernel::pfault:START {
    timing vector kstats pfault
}

annotation set pc kernel::page_copy:START {
    if {[timing current kstats] == "pfault"} {
        timing vector kstats COW_fault
    }
}

annotation set pc kernel::vfault:START {
    timing vector kstats vfault
}

annotation set pc kernel::page_zero:START {
    if {[timing current kstats] == "vfault"} {
        timing vector kstats demand_zero
    }
}


##
## Interrupts
##

# simscsi_intr, if_etintr, and du_poll all share the interrupt
# dispatch path. There are two ways to charge the overhead to
# routines. 1) We can treat the routines as interrupt handlers in the
# normal way. This leads to simscsi_intr getting charged all the
# dispatch overhead and du_poll getting charged all the return
# overhead. This is what is currently done. 2) We could have a
# level3_intr, do normal start, ends on simscsi_intr, if_etintr, and
# du_poll, and then divide the overhead of level3_intr among the 3 as
# a post processing step. Fortunately the overhead is small enough
# where we do not really care.

#set intr(timein)         1
#set intr(netintr)        2
#set intr(simscsi_intr)   3
#set intr(if_etintr)      3
#set intr(du_poll)        3
#set intr(level4_intr)    4
#set intr(clock)          5
#set intr(cpuintr)        6
#set intr(ackkgclock)     7
#set intr(buserror_intr)  8

#foreach i [array names intr] {
#    annotation set pc kernel:SIMMP.c:$i:START "dointr $i"
#}

#proc dointr {name} {
#    global intr CPU CYCLES
#    set current [timing current kstats] 
#    if {$current == "intrdisp"} {
#        timing vector kstats $name
#    } elseif [info exists intr($current)] {
#        timing end kstats $current
#        timing start kstats $name
#    } else {
#        console "KSTATS: CPU $CPU CYCLE $CYCLES: bad intr: $name current: $current\n"
#    }
#}

################################################################
################################################################

annotation set pc kernel:sema.c:semarmproc:START {
    set ktid [symbol read "kernel::(*(kthread_t*)$a1).k_id"]

    console "KSTATS: semarmproc $ktid\n"
    if {[info exists kstatsThreadState($ktid)] && ($ktid != $KTID($CPU))} {
        if {[timing current kstats $ktid] == $kstatsThread($ktid)} {
            timing end kstats $kstatsThread($ktid) $ktid
            timing start kstats runq $ktid
        } else {
            log "$CYCLES semarmproc special case: thread $ktid\n"
            timing dumpstack kstats $ktid
            log "State after desched will be \"runq\" rather than \"$kstatsThreadState($ktid)\"\n"
        }
        set kstatsThreadState($ktid) "runq"
    }
}

annotation set pc kernel:sema.c:semaaddproc:START {
    set ktid [symbol read "kernel::(*(kthread_t*)$a1).k_id"]
    console "KSTATS: Sema wait $ktid\n"
    if {$kstatsThreadState([ktname]) == "runq" } {
        set kstatsThreadState([ktname]) "semawait"
    }
}

annotation set pc kernel:sema.c:semadq:END {
    set ktid [symbol read "kernel::(*(kthread_t*)$v0).k_id"]
    console "KSTATS: Sema signal $ktid\n"
    if {[info exists kstatsThreadState($ktid)] && ($ktid != $KTID($CPU))} {
        if {[timing current kstats $ktid] == $kstatsThreadState($ktid)} {
            timing end kstats $kstatsThreadState($ktid) $ktid
            timing start kstats runq $ktid
        } else {
            log "$CYCLES semarmproc special case: thread $ktid\n"
            timing dumpstack kstats $ktid
#            log "State after desched will be \"runq\" rather than \"$kstatsThreadState($ktid)\"\n"
       }
        set kstatsThreadState($ktid) "runq"
    }
}

###
### Revise the reason why we're going to be descheduled
###
annotation set pc kernel::ql_entry:START {
#    console "DISK COMMAND!\n"
    set kstatsThreadState([ktname]) diskIO
}

annotation set pc kernel:if_sim.c:ef_transmit:START {
#    console "EF TRANSMIT\n"
    set kstatsThreadState([ktname]) efSend
}

###
### statistics logging
###

annotation set simos exit {
    timing exit kstats
    log [timing dump kstats]
}

annotation set simos sigusr {
    log [timing dump kstats]
}