From:	SMTP%"RELAY-INFO-VAX@CRVAX.SRI.COM" 20-SEP-1993 09:20:34.82
To:	EVERHART
CC:	
Subj:	Re: How to calculate Idle CPU time from a program

From: jeh@cmkrnl.com
X-Newsgroups: comp.os.vms
Subject: Re: How to calculate Idle CPU time from a program
Message-Id: <1993Sep15.204426.2719@cmkrnl.com>
Date: 15 Sep 93 20:44:26 PDT
Organization: Kernel Mode Systems, San Diego, CA
Lines: 147
To: Info-VAX@kl.sri.com
X-Gateway-Source-Info: USENET

In article <1993Sep15.205207.21481@mprgate.mpr.ca>, hamm@magellan.mpr.ca (Rob Hamm) writes:
> As the subject says, I need to calculate the idle time on a CPU from inside
> a Pascal program. If monitor had a callable interface that would suffice, 
> but is there some other way? 
> 
> Also, how is the idle time on a CPU calculated by monitor?

It isn't.  It's simply read from the exec.  The hardware interval timer 
interrupt service routine simply increments one of several counters in the
per-CPU data structure according to the mode the CPU was in before the 
interrupt, and also bumps the counter for idle time if no process is current
on that CPU.  

Following is a Macro procedure, callable from a HLL, to obtain this data.
I'm also including a short Fortran program to demonstrate its use.

To build and link:

	Clip the fortran into a.for
	Clip the macro (.title .... .end) into gmt.mar
	$ fortran a
	$ macro gmt
	$ link a+gmt
	$ run a

the eight counter values will be displayed.  

To calculate idle time as a percentage of total time, add the eight counter
values together to get the total time, then divide that into the idle time. 

Oddly, fetching this stuff doesn't seem to require that you be in either exec
or kernel mode... 

	--- Jamie Hanrahan, Kernel Mode Systems, San Diego CA
drivers, internals, networks, applications, and training for VMS and Windows NT
uucp 'g' protocol guru and release coordinator, VMSnet (DECUS uucp) W.G., and 
Chair, Programming and Internals Working Group, U.S. DECUS VMS Systems SIG 
Internet:  jeh@cmkrnl.com (JH645)  Uucp: uunet!cmkrnl!jeh  CIS: 74140,2055

C	fortran program to demonstrate use of get_mode_times().

	integer*4 ticks(8)
	call get_mode_times(ticks)
	type *, ticks
	end

	.TITLE	GET_MODE_TIMES

;++
; GET_MODE_TIMES -- collect CPU mode (and other) tick counters from 
;	CPU databases.  Works correctly on SMP systems.  Does not 
;	bother to synchronize with clock interrupts (since we are 
;	only reading the data; the worst that can happen is that we'll
;	be off by one tick here or there)
;
; Synopsis:
;	unsigned long			returns completion status (SS$_NORMAL)
;	 get_mode_times(
;		unsigned long timearray[]
;	 );
;
; Outputs:
;	timearray	- an array of (at least) eight unsigned longs.  The 
;			array elements will receive the tick counts in the
;			following order:
;		[0]	kernel mode
;		[1]	exec mode
;		[2]	supervisor mode
;		[3]	user mode
;		[4]	interrupt stack
;		[5]	compatibility mode
;		[6]	spinLock wait
;		[7]	null, ie idle, time
;			Each tick represents 0.01 seconds. 
;
; Author:
;	Jamie Hanrhan, Kernel Mode Systems (jeh@cmkrnl.com)
;
;	thanks to Carl Morris (ucf-cs!morris) who first (to my 
;	knowledge) posted the code for stepping through the  
;	CPU$ structures on comp.os.vms / info-vax.
;--

	.LIBRARY "SYS$LIBRARY:LIB"
	$CPUDEF
	.LINK	"SYS$SYSTEM:SYS.STB" /SELECTIVE_SEARCH

	.ENTRY	GET_MODE_TIMES, ^M<R2, R3, R4, R5>

	MOVL	4(AP), R2

	; there don't seem to be predefined symbols for all of these offsets.  
	; The first five are actually derived from K=0, E=1, etc., and 
	; (creatively) Istack = 4, in the PSL.  The rest were apparently
	; chosen arbitrarily.  We don't actually use any of the symbols
	; except ITICKS and NTICKS. 

KTICKS = 0
ETICKS = 4
STICKS = 8
UTICKS = 12
ITICKS = 16
CTICKS = 20
LTICKS = 24
NTICKS = 28

	; zero them all

	MOVL	R2, R1
	.IRP	MODE, <K, E, S, U, I, C, L, N>
	CLRL	(R1)+
	.ENDR

	; look at each CPU data base

	MOVL	G^SMP$GL_ACTIVE_CPUS, R3	; get active cpu mask
10$:	FFS	#0, #32, R3, R4			; find next active cpu
	BEQL	20$				;  if no more, leave...
	BBSC	R4, R3, 15$			; clear the found bit
15$:
	MOVL	G^SMP$GL_CPU_DATA[R4], R5	; get cpu data addr
 
	; assume that the null cpu value is right after the seven other
	; longwords in the cpu-specific data structure

	ASSUME	CPU$L_NULLCPU EQ <CPU$L_KERNEL + 28>
 
	MOVAL	CPU$L_KERNEL(R5), R0
	MOVL	R2, R1

	.IRP	MODE, <K, E, S, U, I, C, L, N>
	ADDL2	(R0)+, (R1)+
	.ENDR

	BRB	10$				; do next cpu
 
20$:    
	; remove null time from interrupt time

	SUBL2	NTICKS(R2), ITICKS(R2)

	MOVL	#SS$_NORMAL, R0
	RET

	.END

(end)

