From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  7-JUN-1989 10:15
To:	MRGATE::"ARISIA::EVERHART"
Subj:	TIME_IN_MODES.MAR

Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Wed,  7 JUN 89 06:00:48 PDT
Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Wed, 7 Jun 89 05:36:58 PDT
Received: by ucbvax.Berkeley.EDU (5.61/1.36)
	id AA14660; Wed, 7 Jun 89 05:21:49 -0700
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 7 Jun 89 01:01:10 GMT
From: leah!rpi!crdgw1!ge-dab!peora!ucf-cs!morris@csd4.milw.wisc.edu  (Carl Morris)
Organization: Univ. of Central Florida, Orlando
Subject: TIME_IN_MODES.MAR
Message-Id: <1084@ucf-cs.UCF.EDU>
References: no, stinking, references!)
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

I don't have a multiprocessor V5 node yet, can someone with one try running
this and see if they get a display for each running processor?  Replies as
to what happens would be greatly appreciated.

                                   Thanks - Carl

=================== cut after this line ===================
; ...   Title:          Time_In_Modes.mar
; 
; ...   Version:        V1.0-000
;
; ...   Facility:       System utility
;
; ...   Abstract:       This routine displays the time spent in each mode
;                       as well as the idle time for each active cpu.
;
; ...   Environment:    N/A
;
; ...   Author:         Carl Morris
;                       P.O. Box 930
;                       Apopka, FL 32704
;
; ...   Date:           03-Jun-1989
;
; ...   Modified by:
;
;-----------------------------------------------------------------------------
;
;

        .title  Time_in_Modes
        .ident  'V1.0-000'
 
        .library                'sys$library:lib.mlb'
 
        .link                   'sys$system:sysdef.stb' /selective_search, -
                                'sys$system:sys.stb'    /selective_search, -
                                'sys$library:vaxcrtl'   /library
 
        $cpudef
        $ssdef
 
 
null                    = 0                     ; null terminator for C strings
crlf                    = 10                    ; CRLF value for C format string

max_len                 = 80                    ; length of string buffer
 
cpu_number_offset       = 4                     ; cpu # passed at 4(ap)
 
kernel_offset           = 0                     ; 1st longword
executive_offset        = 4                     ; 2nd longword
supervisor_offset       = 8                     ; 3rd longword
user_offset             = 12                    ; 4th longword
interrupt_offset        = 16                    ; 5th longword
compatibility_offset    = 20                    ; 6th longword
busy_wait_offset        = 24                    ; 7th longword
idle_offset             = 28                    ; 8th longword
 
 
.macro  check_status -                          ; macro to check status
                status_var=r0,?ok
        blbs    status_var,ok                   ; ok if low bit is set
        $exit_s status_var                      ; exit with bad status
ok:                                             ; come here if ok
.endm
 
 
                                                ; macro to calculate and print
                                                ; the time in mode string
.macro  calc_and_print_time -
                time_src, -                     ; longword 10ms tick count
                format_string, -                ; C language format string addr
                ?nonzero
        cvtld   time_src,float_time             ; convert to floating and divide
        divd2   float_cpu,float_time            ;  by total to get percentage
        emul    #-100000,time_src,#0,quad_time  ; multiply to get 100ns ticks
        bbs     #63,quad_time,nonzero           ; is value nonzero? then branch
        movq    #^xffffffffffffffff,quad_time   ; move a delta format zero in
nonzero:                                        ; come here if nonzero
 
        movw    #max_len,faodesc                ; set length of dest string
        $fao_s  ctrstr=time_desc, -             ; format a time
                outbuf=faodesc, -               ; dest buffer
                outlen=faodesc, -               ; length buffer
                p1=#quad_time                   ; quadword to convert
        check_status                            ; check if success
 
        movzwl  faodesc,r0                      ; get string length
        movb    #null,string[r0]                ; null terminate string
 
        movd    float_time,-(sp)                ; push d float
        pushab  string                          ; push time string addr
        pushab  format_string                   ; push format string addr
        calls   #4,g^printf                     ; call printf()
.endm
 

        .psect  user$code       pic,exe,nowrt,long
 
        .entry  main,^m<>                       ; program mainline
 
                                                ; print banner line with time
        movw    #max_len,faodesc                ; set output buffer length
        $fao_s  ctrstr=banner_str, -            ; format banner 
                outbuf=faodesc, -               ; output buffer
                outlen=faodesc, -               ; output length
                p1=#0                           ; use current time
        check_status                            ; check if success
        pushab  faodesc                         ; string to output
        calls   #1,g^lib$put_output             ; print string
        check_status                            ; check if success
 
        clrl    r10                             ; init index
        movl    g^smp$gl_active_cpus,r9         ; get active cpu mask
10$:    ffs     #0,#32,r9,r8                    ; find next active cpu
        beql    20$                             ; no more? leave...
        bbsc    r8,r9,15$                       ; clear the found bit
15$:    pushl   r8                              ; push number of this cpu
        calls   #1,do_cpu                       ; print cpu stats
        brb     10$                             ; do next cpu
 
20$:    movl    #ss$_normal,r0                  ; success status
        ret
 
 
        .entry  do_cpu,^m<r2,r3,r4,r5>          ; print cpu stats
                                  
        movl    cpu_number_offset(ap),r0        ; get cpu number to do
        movl    g^smp$gl_cpu_data[r0],r1        ; get cpu data addr
 
                                                ; assume that the null cpu value
                                                ; is right after seven other
                                                ; longwords in the cpu-specific
                                                ; data structure, if so then we
                                                ; can use one movc3 to get all
                                                ; the data
        assume  cpu$l_nullcpu eq <cpu$l_kernel + 28>
 
        movc3   #<cpu$s_kernel+4>, -            ; get data from per-cpu database
                cpu$l_kernel(r1),cpu_data
 
        pushl   cpu_number_offset(ap)           ; push cpu number
        pushab  cpu_str                         ; push format string
        calls   #2,g^printf                     ; print cpu number
 
        moval   cpu_data,r5                     ; get addr of cpu_data vector
        subl2   idle_offset(r5), -              ; subtract idle time from 
                interrupt_offset(r5)            ; interrupt stack time so it
                                                ; won't be counted twice
 
                                                ; sum up times, this will give
        movl    idle_offset(r5),cpu_summary     ; the total uptime for this 
        addl2   kernel_offset(r5),cpu_summary   ; cpu
        addl2   executive_offset(r5),cpu_summary
        addl2   supervisor_offset(r5),cpu_summary
        addl2   user_offset(r5),cpu_summary
        addl2   interrupt_offset(r5),cpu_summary
        addl2   compatibility_offset(r5),cpu_summary
        addl2   busy_wait_offset(r5),cpu_summary
 
        cvtld   cpu_summary,float_cpu           ; save total as float, divide by
        divd2   #^f100.0,float_cpu              ;  100, we will divide the other
                                                ;  times by this value to obtain
                                                ;  percentages of total time
 
 
        calc_and_print_time -                   ; print idle time
                idle_offset(r5),idle_str
 
        calc_and_print_time -                   ; print kernel mode time
                kernel_offset(r5),kernel_str
 
        calc_and_print_time -                   ; print exececutive mode time
                executive_offset(r5),executive_str
 
        calc_and_print_time -                   ; print superviser mode time
                supervisor_offset(r5),supervisor_str
 
        calc_and_print_time -                   ; print user mode time
                user_offset(r5),user_str
 
        calc_and_print_time -                   ; print interrupt stack time
                interrupt_offset(r5),interrupt_str
 
        calc_and_print_time -                   ; print compatibility mode time
                compatibility_offset(r5),compatibility_str
 
        calc_and_print_time -                   ; print busy wait time
                busy_wait_offset(r5),busy_wait_str
 
        calc_and_print_time -                   ; print total time
                cpu_summary,total_str
 
        ret                                     ; return to caller
 
 
        .psect  user$data       pic,long,noexe,rd,wrt
 
banner_str:                                     ; banner $fao control string
        .ascid  "Time in processor modes !23%D!/"
                
cpu_str:                                        ; cpu number C format string
        .ascii  "CPU %2d:                          Elapsed           Percent"
        .byte   crlf,crlf,null
 
idle_str:                                       ; idle time C format string
        .ascii  "    Idle time:             %s        %6.2f%%"
        .byte   crlf,null
 
kernel_str:
        .ascii  "    Kernel mode:           %s        %6.2f%%"
        .byte   crlf,null
 
executive_str:
        .ascii  "    Executive mode:        %s        %6.2f%%"
        .byte   crlf,null
 
supervisor_str:
        .ascii  "    Supervisor mode:       %s        %6.2f%%"
        .byte   crlf,null
 
user_str:
        .ascii  "    User mode:             %s        %6.2f%%"
        .byte   crlf,null
 
interrupt_str:
        .ascii  "    Interrupt stack:       %s        %6.2f%%"
        .byte   crlf,null
 
compatibility_str:
        .ascii  "    Compatibility mode:    %s        %6.2f%%"
        .byte   crlf,null
 
busy_wait_str:
        .ascii  "    Busy wait:             %s        %6.2f%%"
        .byte   crlf,crlf,null
 
total_str:
        .ascii  "    Total time:            %s        %6.2f%%"
        .byte   crlf,crlf,crlf,null
 
time_desc:
        .ascid  "!16%D"
 
faodesc:
        .word           MAX_LEN
        .word           0
        .address        string
 
string:
        .blkb           MAX_LEN
 
cpu_data:
        .blkb           <cpu$s_kernel+4>
 
cpu_summary:
        .blkl           1
 
float_cpu:
        .d_floating     0
 
float_time:
        .d_floating     0
 
quad_time:
        .blkq           1
 
        .end    main

