From:	CSBVAX::CSBVAX::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 23-FEB-1989 08:09
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Re: NULL CPU time under VMS 5.0


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Wed, 22 FEB 89 19:02:19 PDT
Received: from hac2arpa.hac.com by KL.SRI.COM with TCP; Wed, 22 Feb 89 18:55:12 PST
Received: from [128.152.50.2] by hac2arpa.hac.com (5.59/SMI-DDN)
	id AA16837; Wed, 22 Feb 89 18:56:45 PST
Resent-From: @ENGVAX.SCG.hac.com:SBAILEY@DOMINOES.UUCP
Resent-Message-Id: <8902230256.AA16837@hac2arpa.hac.com>
Message-Id: <8902230256.AA16837@hac2arpa.hac.com>
Received: from DOMINOES.UUCP by ENGVAX.SCG.HAC.COM; Wed, 22 Feb 89 18:31 PST
Date: Wed, 22 Feb 89 15:11 PST
From: Scott Bailey <@ENGVAX.SCG.hac.com:SBAILEY@DOMINOES.UUCP>
Subject: Re: NULL CPU time under VMS 5.0
To: info-vax-submit@ENGVAX.SCG.hac.com
X-Vms-To: INFO-VAX-SUBMIT,SBAILEY
Resent-Date: Wed, 22 Feb 89 18:43 PST
Resent-To: info-vax%kl.sri.com@hac2arpa.hac.com

Path: x23!sbailey
From: sbailey@dominoes.uucp (Scott Bailey)
Newsgroups: comp.os.vms
Subject: Re: NULL CPU time under VMS 5.0
Message-ID: <6@dominoes.uucp>
Date: 22 Feb 89 15:11:15 GMT
References: <14814@cup.portal.com>
Organization: Xerox Corporation, El Segundo CA
Lines: 173

In article <14814@cup.portal.com>, uunet.uu.net!portal!cup.portal.com!David_Anthony_Guevara@oberon.usc.EDU writes:
> The NULL time question has been covered before on the net.  Unfortunately
> I did not bother to save any of the articles.  I guess the general request
> is for a simple routine to get the NULL time of the CPU.  The code should
> be fairly robust and hopefully not break under future releases of VMS 5.x.

What the heck...  Below is a short Macro routine which returns the number of
idle ticks and the number of CPUs those ticks were accumulated on.  I'm 
posting this to the group for a couple reasons -- the topic seems to be of 
general interest, and I wouldn't mind comments from VMS gurus on improving the 
code (which we use at our site).

This routine has been tested through VMS V5.0-2, but only on uniprocessors...  
Also, I have no idea what impact starting and stopping processors will have on 
the collected idle time.

Good luck... we may need it... :-)

  Scott Bailey                    Arpa:   SBailey.ESGSDWCO@Xerox.COM
  VAX Systems Manager             BITNET: SCOTT@HMCVAX
  Xerox Corp. RE/GSD/WCO          Phone:  213 / 333-5441

$! ................... Cut between dotted lines and save. ...................
$!...........................................................................
$! VAX/VMS archive file created by VMS_SHARE V06.10 7-FEB-1989.
$!
$! VMS_SHARE was written by James Gray (Gray:OSBUSouth@Xerox.COM) from
$! VMS_SHAR by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au).
$!
$! To unpack, simply save, concatinate all parts into one file and
$! execute (@) that file.
$!
$! This archive was created by user SBAILEY
$! on 22-FEB-1989 15:03:25.08.
$!
$! It contains the following 1 file:
$!        CPUIDLE.MAR
$!
$!============================================================================
$ SET SYMBOL/SCOPE=( NOLOCAL, NOGLOBAL )
$ VERSION = F$GETSYI( "VERSION" )
$ IF VERSION .GES "V4.4" THEN GOTO VERSION_OK
$ WRITE SYS$OUTPUT "You are running VMS ''VERSION'; ", -
    "VMS_SHARE V06.10 7-FEB-1989 requires VMS V4.4 or higher."
$ EXIT 44 ! SS$_ABORT
$VERSION_OK:
$ GOTO START
$!
$UNPACK_FILE:
$ WRITE SYS$OUTPUT "Creating ''FILE_IS'"
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ EDIT/TPU/COMMAND=SYS$INPUT/NODISPLAY/OUTPUT='FILE_IS'/NOSECTION -
    VMS_SHARE_DUMMY.DUMMY
b_part := CREATE_BUFFER( "{Part}", GET_INFO( COMMAND_LINE, "file_name" ) )
; s_file_spec := GET_INFO( COMMAND_LINE, "output_file" ); SET( OUTPUT_FILE
, b_part, s_file_spec ); b_errors := CREATE_BUFFER( "{Errors}" ); i_errors 
:= 0; pat_beg_1 := ANCHOR & "-+-+-+ Beginning"; pat_beg_2 := LINE_BEGIN 
& "+-+-+-+ Beginning"; pat_end := ANCHOR & "+-+-+-+-+ End"; POSITION
( BEGINNING_OF( b_part ) ); LOOP EXITIF SEARCH( SPAN( ' ' )@r_trail 
& LINE_END, FORWARD) = 0; POSITION( r_trail ); ERASE( r_trail ); ENDLOOP
; POSITION( BEGINNING_OF( b_part ) ); i_append_line := 0; LOOP EXITIF MARK
( NONE ) = END_OF( b_part ); s_x := ERASE_CHARACTER( 1 )
; IF s_x = '+' THEN r_skip := SEARCH( pat_beg_1, FORWARD, EXACT ); IF r_skip 
<> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ERASE_LINE; ENDIF
; ENDIF; IF s_x = '-' THEN r_skip := SEARCH( pat_end, FORWARD, EXACT )
; IF r_skip <> 0 THEN s_x := ''; MOVE_HORIZONTAL( -CURRENT_OFFSET ); m_skip 
:= MARK( NONE ); r_skip := SEARCH( pat_beg_2, FORWARD, EXACT ); IF r_skip 
<> 0 THEN POSITION( END_OF( r_skip ) ); MOVE_HORIZONTAL( -CURRENT_OFFSET )
; MOVE_VERTICAL( 1 ); MOVE_HORIZONTAL( -1 ); ELSE POSITION( END_OF( b_part 
) ); ENDIF; ERASE( CREATE_RANGE( m_skip, MARK( NONE ), NONE ) ); ENDIF; ENDIF
; IF s_x = 'V' THEN s_x := ''; IF i_append_line <> 0 THEN APPEND_LINE
; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF; i_append_line := 1
; MOVE_VERTICAL( 1 ); ENDIF; IF s_x = 'X' THEN s_x := ''; IF i_append_line 
<> 0 THEN APPEND_LINE; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF
; i_append_line := 0; MOVE_VERTICAL( 1 ); ENDIF; IF s_x <> '' THEN i_errors 
:= i_errors + 1; s_text := CURRENT_LINE; POSITION( b_errors ); COPY_TEXT
( "The following line could not be unpacked properly:" ); SPLIT_LINE
; COPY_TEXT( s_x ); COPY_TEXT( s_text ); POSITION( b_part ); MOVE_VERTICAL
( 1 ); ENDIF; ENDLOOP; POSITION( BEGINNING_OF( b_part ) ); LOOP r_x := SEARCH
( "`", FORWARD, EXACT ); EXITIF r_x = 0; POSITION( r_x ); ERASE_CHARACTER
( 1 ); COPY_TEXT( ASCII( INT( ERASE_CHARACTER( 3 ) ) ) ); ENDLOOP
; IF i_errors = 0 THEN SET( NO_WRITE, b_errors, ON ); ELSE POSITION
( BEGINNING_OF( b_errors ) ); COPY_TEXT( FAO
( "The following !UL errors were detected while unpacking !AS", i_errors
, s_file_spec ) ); SPLIT_LINE; SET( OUTPUT_FILE, b_errors, "SYS$COMMAND" )
; ENDIF; EXIT; 
$ DELETE VMS_SHARE_DUMMY.DUMMY;*
$ CHECKSUM 'FILE_IS
$ WRITE SYS$OUTPUT " CHECKSUM ", -
  F$ELEMENT( CHECKSUM_IS .EQ. CHECKSUM$CHECKSUM, ",", "failed!!,passed." )
$ RETURN
$!
$START: 
$ FILE_IS = "CPUIDLE.MAR"
$ CHECKSUM_IS = 2117241941
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
V;  +-------------------------------------------------------------------------
X--+
X;  `124`009`009`009`009`009`009`009`009`009       `124
V;  `124  UTIL$ROOT:[PERFMON]CPUIDLE.MAR`009`009      Calculate CPU Idle Time
X  `124
V;  `124  Scott Bailey, Xerox Corp. RE/GSD/WCO`009    Created November 14, 198
X8  `124
X;  `124`009`009`009`009`009`009`009`009`009       `124
X;  `124  Modification History`009`009`009`009`009`009       `124
X;  `124  V1.0-002`00911/14/88 RSB`009Original version`009`009`009       `124
X;  `124`009`009`009`009`009`009`009`009`009       `124
V;  +-------------------------------------------------------------------------
X--+
X;
V; This procedure returns the number of 10-ms ticks of idle time accumulated b
Xy
X; the active CPUs found on the system.  It also returns the number of CPUs
V; found, so the caller can determine how useful the returned idle time is. Th
Xe
X; basic algorithm is stolen from the routine GET_SPC in module SYSGETSPI in
X; facility MONITOR from the VMS V5.0 fiche.
X;
X`009.TITLE`009CPUIDLE - Calculate CPU Idle Time
X`009.IDENT`009'V1.0-002'
X`009.LIBRARY 'SYS$LIBRARY:LIB'
X`009.LINK`009'SYS$SYSTEM:SYS.STB' /SELECTIVE_SEARCH
X;
X`009$CPUDEF
X`009$SSDEF
X;
X; status.wl.v = CPUIDLE(idle.wl.r,cpus.wl.r)
X;
X; IDLE (longword output parameter, passed by reference) contains the total
X; aggregate idle time measured on the system, in 10-ms ticks.
X; CPUS (longword output parameter, passed by reference) contains the number
X; of active CPUs whose idle times were analyzed.
X; STATUS (longword function value) contains the return status from this call.
X; It will be SS$_BADPARAM if the argument count was incorrect, otherwise it
X; will be SS$_NORMAL.  Flakey arguments may cause access violations.
X;
XIDLE = 4`009`009`009`009; Argument list offset definitions
XCPUS = 8
X;
V; This procedure has been tested only on uniprocessor systems.  The effects o
Xf
V; starting and stopping cpus on a multiprocessor system are unknown but proba
Xbly
X; result in idle times which are not monotonically increasing with time; e.g.
V; if a cpu is stopped, its idle time is probably removed from the total, whic
Xh
X; causes the returned value to decrease.
X;
X`009.PSECT`009$CODE`009`009PIC,USR,CON,REL,LCL,SHR,EXE,RD,NOWRT,NOVEC
X`009.ENTRY`009CPUIDLE,`094M<R2,R3,R4>
X`009CMPL`009#2,(AP)`009`009`009`009; Did user supply 2 arguments?
X`009BEQL`00910$`009`009`009`009; Yes, continue
X`009MOVL`009#SS$_BADPARAM,R0`009`009; Set error status
X`009RET`009`009`009`009`009; and get out
X10$:`009`009`009`009`009`009; Initialize counters
X`009CLRL`009R0`009`009`009`009; Idle tick counter
X`009CLRL`009R4`009`009`009`009; Active CPU counter
X`009MOVL`009G`094SMP$GL_ACTIVE_CPUS,R1`009`009; Get bitmask of active CPUs
X20$:`009`009`009`009`009`009; Start of scan loop
X`009FFS`009#0,#32,R1,R2`009`009`009; R2 will have next CPU index
X`009BEQL`00930$`009`009`009`009; Quit if no more active CPUs
X`009MOVL`009G`094SMP$GL_CPU_DATA[R2],R3`009; R3 points to CPU's counters
X`009ADDL2`009CPU$L_NULLCPU(R3),R0`009`009; Add in idle time
X`009INCL`009R4`009`009`009`009; Count this CPU
X`009BBSC`009R2,R1,20$`009`009`009; Mark CPU 'counted' & loop
X30$:`009`009`009`009`009`009; Pass back information
X`009MOVL`009R0,@IDLE(AP)`009`009`009; Store total idle time
X`009MOVL`009R4,@CPUS(AP)`009`009`009; Store active CPU count
X`009MOVL`009#SS$_NORMAL,R0`009`009`009; We finished okay
X`009RET
X`009.END
$ GOSUB UNPACK_FILE
$ EXIT

