From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  1-DEC-1989 15:24
To:	MRGATE::"ARISIA::EVERHART"
Subj:	MONMODE Christmas is coming 1/2

Message-Id:  <8912012008.AA12273@crdgw1.ge.com>
Received: From NSFNET-RELAY.AC.UK by CRVAX.SRI.COM with TCP; Fri,  1 DEC 89 10:24:06 PDT
Received: from sun.nsfnet-relay.ac.uk by vax.NSFnet-Relay.AC.UK 
           via Janet with NIFTP  id aa13528; 1 Dec 89 17:51 GMT
Date:           Fri, 1 Dec 89  17:56 BST
From: Nick de Smith <"PSI%JANET.000000000040::NICK%ncdlab.ulcc.ac.uk"@NSFnet-Relay.AC.UK>
To: INFO-VAX <@NSFnet-Relay.AC.UK:INFO-VAX@crvax.sri.com>
Subject:        MONMODE Christmas is coming 1/2

Hi,

Here's a bit of light relief from all this serious talk about newsgroups etc.

Enclosed (below) is part 1 of a 2 part submission called MONMODE. It is not
supposed to be taken seriously - its just a strange thing to do with DCL. Part 2
follows later.

Description:

This is a weird, sick, and nasty DCL command file that does a MONITOR MODES /SMP
for up to a 7 CPU SMP system (4 CPUs on an 80 column screen). It works just fine
on a uniprocessor. It is also just great for burning up supervisor mode. No
images except DCL.EXE are used. Oh, and its VMS V5.x only!

I suppose that if there is any value in this sort of rubbish, it is to
demonstrate the usage of bizarre or little known features of DCL.
NO UNDOCUMENTED FEATURE is used herein.
The corollary of this, of course, is that no documented feature is unused! (not
quite true).

Happy Xmas,

nick	NICK@ncdlab.ulcc.ac.uk
	(lets back back to *real* issues on INFO-VAX)

MONMODE.1
$! ------------------ CUT HERE -----------------------
$ v='f$verify(f$trnlnm("SHARE_VERIFY"))'
$!
$! This archive created by VMS_SHARE Version 7.1-004  3-AUG-1989
$!   On  1-DEC-1989 17:41:42.03   By user NICK 
$!
$! This VMS_SHARE Written by:
$!    Andy Harper, Kings College London UK
$!
$! Acknowledgements to:
$!    James Gray       - Original VMS_SHARE
$!    Michael Bednarek - Original Concept and implementation
$!
$!+ THIS PACKAGE DISTRIBUTED IN 2 PARTS, TO KEEP EACH PART
$!  BELOW 30 BLOCKS
$!
$! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER
$! AND EXECUTE AS A COMMAND PROCEDURE  (  @name  )
$!
$! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING:
$!       1. MONMODE.COM;2
$!
$set="set"
$set symbol/scope=(nolocal,noglobal)
$f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID"))
$e="write sys$error  ""%UNPACK"", "
$w="write sys$output ""%UNPACK"", "
$ if f$trnlnm("SHARE_LOG") then $ w = "!"
$ if f$getsyi("version") .ges. "V4.4" then $ goto START
$ e "-E-OLDVER, Must run at least VMS 4.4"
$ v=f$verify(v)
$ exit 44
$UNPACK: SUBROUTINE ! P1=filename, P2=checksum
$ if f$search(P1) .eqs. "" then $ goto file_absent
$ e "-W-EXISTS, File ''P1' exists. Skipped."
$ delete/nolog 'f'*
$ exit
$file_absent:
$ if f$parse(P1) .nes. "" then $ goto dirok
$ dn=f$parse(P1,,,"DIRECTORY")
$ w "-I-CREDIR, Creating directory ''dn'."
$ create/dir 'dn'
$ if $status then $ goto dirok
$ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped."
$ delete/nolog 'f'*
$ exit
$dirok:
$ w "-I-PROCESS, Processing file ''P1'."
$ define/user sys$output nl:
$ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1'
PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET(
SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");
buff:=CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(buff))
;LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION(
BEGINNING_OF(buff));g:=0;LOOP EXITIF MARK(NONE)=END_OF(buff);x:=
ERASE_CHARACTER(1);IF g = 0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x=
"V" THEN APPEND_LINE;MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;
IF x="+" THEN g:=1;ERASE_LINE;ENDIF;ELSE IF x="-" THEN g:=0;ENDIF;ERASE_LINE;
ENDIF;ENDLOOP;p:="`";POSITION(BEGINNING_OF(buff));LOOP r:=SEARCH(p,FORWARD);
EXITIF r=0;POSITION(r);ERASE(r);COPY_TEXT(ASCII(INT(ERASE_CHARACTER(3))));
ENDLOOP;o:=GET_INFO(COMMAND_LINE,"output_file");WRITE_FILE(buff,o);
ENDPROCEDURE;Unpacker;EXIT;
$ delete/nolog 'f'*
$ CHECKSUM 'P1'
$ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT
$ e "-E-CHKSMFAIL, Checksum of ''P1' failed."
$ ENDSUBROUTINE
$START:
$ create/nolog 'f'
X$`009Setv = 'F$Verify( "No" )
X$!+
X$!`009MONMODE.COM`009A DCL form of MONITOR MODES /SMP
X$!
X$!`009Author`009`009: Nick de Smith`009`009NICK@NCDLAB.ULCC.AC.UK
X$!`009Date`009`009: 01-Dec-89
X$!
X$!`009`009Happy Christmas, weirdos!
X$!
X$!`009Edit`009Edit date`009By`009Why
X$!`009 01`00901-Dec-89`009NMdS`009New. Christmas special!
X$!
X$`009Copyright = "`169 1989 by Nick de Smith"
X$!
X$!`009This software is provided for interest only. It may not be lent,
X$!`009copied or used in any way for the purpose of profit. The author
X$!`009accepts no responsibility for any action that may result from the
X$!`009use of this software.
X$!`009This software may be copied (keeping this copyright notice) and used
X$!`009freely providing the above conditions are observed.
X$!
X$! Description:
X$!`009This is a weird, sick, and nasty DCL command file that does a MONITOR
V MODES /SMP for
X$!`009up to a 7 CPU SMP system (4 CPUs on an 80 column screen). It works jus
Vt fine on a uniprocessor.
X$!`009It is also just great for burning up supervisor mode.
X$!`009No images except DCL.EXE are used. Oh, and its VMS V5.x only!
X$!
X$!`009I suppose that if there is any value in this sort of rubbish, it is to
V demonstrate
X$!`009the usage of bizarre or little known features of DCL. NO UNDOCUMENTED
V FEATURE is used herein.
X$!`009The corollary of this, of course, is that no documented feature is unu
Vsed! (not quite true).
X$!
X$!`009P1`009Interval to wait between scans, either in seconds, or as a delta
V time string.
X$!`009`009The default is 30 seconds.
X$!`009P2`009Terminal width to use. The default is 80 columns. Only 80 or 132
V may be specified.
X$!-
X$`009Set Symbol /Scope=(NoLocal,NoGlobal)`009`009`009`009`009! Insulate ours
Velves
X$!
X$`009Name`009= F$Parse( F$Environment( "PROCEDURE" ),,, "NAME" )
X$`009Info`009= "%" + Name + "-I, "`009`009`009`009`009`009! Information mess
Vage
X$`009Warn`009= "%" + Name + "-W, "`009`009`009`009`009`009! Warning message
X$`009Fatal`009= "%" + Name + "-F, "`009`009`009`009`009`009! Fatal error mes
Vsage
X$`009Ask`009= "Read SYS$COMMAND /End=End /Prompt="`009`009`009`009! User pro
Vmpt command
X$`009Say`009= "Write SYS$OUTPUT"`009`009`009`009`009`009! Print to terminal
X$`009TRUE`009= (1.eq.1)`009`009`009`009`009`009`009! Logical TRUE
X$`009FALSE`009= (1.eq.0)`009`009`009`009`009`009`009! Logical FALSE
X$!
X$`009If .not. F$GetDVI( "SYS$COMMAND", "TT_ANSICRT" )`009`009`009! Must be a
Vn ANSI terminal
X$`009Then`009Say Fatal, Name, " can only run on an ANSI terminal"
X$`009`009Goto END_1
X$`009EndIf
X$!
X$`009Esc`0910,8`093`009= %x1b`009`009`009`009`009`009`009! ASCII escape
X$`009CSI`009`009= Esc + "`091"
X$`009Home`009`009= CSI + "H"`009`009`009`009`009`009! Home cursor
X$`009At`009`009= CSI + "!UL;!ULH"`009`009`009`009`009! Move to x,y
X$`009Clear`009`009= Home + CSI + "J"`009`009`009`009`009! Clear Screen
X$`009Bold`009`009= CSI + "1m"`009`009`009`009`009`009! Print in BOLD
X$`009Normal`009`009= CSI + "0m"`009`009`009`009`009`009! Print in normal
X$!
X$! We use !AD to peek at memory. !AD takes two arguments; the length and add
Vress of the string.
X$! It is therefore possible to get !AD to return the contents of any user re
Vadable block of memory.
X$! The SMP per-CPU database is such a block, and we can therefore use this t
Vechnique to access it.
X$! The following "macros" are used in the form:
X$!
X$!`009`009value = 'xPeek address 'Ep
X$!
X$! where "x" is one of: "L" for a longword (32 bits), "W" for a word (16 bit
Vs) or "B" for a byte (8 bits)
X$!
X$`009LPeek`009= "F$CvUI( 0, 32, F$Fao( ""!AD"", 4, "`009`009`009`009! Peek a
Vt a longword
X$`009WPeek`009= "F$CvUI( 0, 16, F$Fao( ""!AD"", 2, "`009`009`009`009!  ''  '
V' '' word
X$`009BPeek`009= "F$CvUI( 0,  8, F$Fao( ""!AD"", 1, "`009`009`009`009!  ''  '
V' '' byte
X$`009Ep`009= ") )"`009`009`009`009`009`009`009`009! "End of Peek" command
X$!
X$`009On CONTROL_Y Then Goto END`009`009`009`009`009`009! Trap trouble
X$`009On WARNING   Then Goto END`009`009`009`009`009`009! Trap trouble
X$!
X$! Try to set the terminal width to Width. Note that you must have DEC_CRT f
Vor SET TERMINAL /WIDTH=n to work.
X$!
X$`009If F$Type ( P2 ) .eqs. "INTEGER"`009`009`009`009`009! Terminal width to
V use
X$`009Then`009Width`009= P2`009`009`009`009`009`009`009! ...use passed width
X$`009`009If (Width .ne. 80) .and (Width .ne. 132)`009`009`009! ...check for
V valid width
X$`009`009Then`009Say Fatal, "Invalid width specified"
X$`009`009`009Say Info, "Specify only 80 or 132 columns"
X$`009`009`009Goto END_1
X$`009`009EndIf
X$`009Else`009Width`009= 80`009`009`009`009`009`009`009! ...use default
X$`009EndIf
X$`009Saved_Width = F$GetDVI( "SYS$COMMAND", "DEVBUFSIZ" )`009`009`009! Save
V the terminal width
X$`009If Saved_Width .ne. Width Then Set Terminal /Width=&Width`009`009! Try
V to run in 80 column mode
X$!
X$`009Interval`009:= 'P1`009`009`009`009`009`009`009! Interval between scans
V in seconds or HH:MM:SS
X$`009If Interval .eqs. "" Then Interval = "00:00:30"`009`009`009`009! Defaul
Vt to 30 seconds
X$`009If F$Type( Interval ) .eqs. "INTEGER"`009`009`009`009`009! If its a tim
Ve in seconds...
X$`009Then`009If (Interval .ge. 3600) .or. (Interval .le. 0)`009`009`009! ...
Vmust be less than 1 hour
X$`009`009Then`009Say Fatal, "Interval in seconds must be less than 1 hour"
X$`009`009`009Say Info, "Use HH:MM:SS form of interval for longer periods"
X$`009`009`009Goto END
X$`009`009EndIf
X$`009`009Interval`009= F$Fao( "!2ZL:!2ZL:!2ZL", 0, Interval / 60, Interval -
V (Interval/60*60) )
X$`009EndIf
X$!
X$! From SYS$SYSTEM:SYS.MAP. As these are in the base image for VMS, they sho
Vuld be the same for all VMS V5.x systems.
X$!
X$`009EXE$GL_ABSTIM_TICS`009= %x800046F8`009`009`009`009`009! Number of TICs
V since system boot
X$`009EXE$GQ_SYSTIME`009`009= %x80004450`009`009`009`009`009! System time
X$`009SMP$GL_FLAGS`009`009= %x800045CC`009`009`009`009`009! SMP flag word
X$`009`009SMP$M_ENABLED`009`009= %x00000001`009`009`009`009! SMP processing i
Vs enabled
X$`009SMP$GL_ACTIVE_CPUS`009= %x800045A8`009`009`009`009`009! Mask of CPUs be
Ving used by SMP
X$`009SMP$GL_CPU_DATA`009`009= %x800045DC`009`009`009`009`009! Table of point
Vers to per-CPU databases
X$!
X$! From $CPUDEF. We assume that CPU$L_NULLCPU = CPU$L_KERNEL + CPU_L_IDLE =
V CPU$L_KERNEL + CPU$S_KERNEL + 4
X$!
X$`009CPU$B_STATE`009`009= %xd`009`009`009`009`009`009! State of this process
Vor
X$`009CPU$S_KERNEL`009`009= %x1c`009`009`009`009`009`009! Size of time in mod
Ves structure
X$`009CPU$L_KERNEL`009`009= %x278`009`009`009`009`009`009! Time in    KERNEL
V mode
X$`009`009CPU_L_KERNEL`009= %x00`009`009`009`009`009`009! Offset to   ''    '
V'
X$`009`009CPU_L_EXEC`009= %x04`009`009`009`009`009`009!   ''   ''  EXEC    ''
X$`009`009CPU_L_SUPER`009= %x08`009`009`009`009`009`009!   ''   ''  SUPERVISO
VR ''
X$`009`009CPU_L_USER`009= %x0c`009`009`009`009`009`009!   ''   ''  USER    ''
X$`009`009CPU_L_INTERRUPT`009= %x10`009`009`009`009`009`009!   ''   ''  INTER
VRUPT ''
X$`009`009CPU_L_COMPAT`009= %x14`009`009`009`009`009`009!   ''   ''  Compatab
Vility ''
X$`009`009CPU_L_MPSYNCH`009= %x18`009`009`009`009`009`009!   ''   ''  MPSYNCH
V ''
X$`009`009CPU_L_IDLE`009= %x1c`009`009`009`009`009`009!   ''   ''  EXEC    ''
X$`009Header_'CPU_L_KERNEL`009= "Kernel mode"`009`009`009`009`009! Set up the
V row headers
X$`009Header_'CPU_L_EXEC`009= "Executive mode"
X$`009Header_'CPU_L_SUPER`009= "Supervisor mode"
X$`009Header_'CPU_L_USER`009= "User mode"
X$`009Header_'CPU_L_INTERRUPT`009= "Interrupt mode"
X$`009Header_'CPU_L_COMPAT`009= "Compatability mode"
X$`009Header_'CPU_L_MPSYNCH`009= "MP Synchronisation"
X$`009Header_'CPU_L_IDLE`009= "Idle time"
X$!
X$! Even though the hack below sets the string Zero_Data to spaces, not zeroe
Vs, what is important is
X$! the difference between Mode_Time_x and Last_Mode_Time_x, which will now b
Ve zero if both are set to this string.
X$!
X$`009Zero_Data`091 0, CPU$S_KERNEL + 4 `093 :=`009`009`009`009`009! String o
Vf spaces
X$!
X$! In CPU$B_STATE (correspond to CPU$C_xxxx values)
X$!
X$`009CPU_State`009= "RESERVED,Being Initialised,Running,Stopping,Stopped,Boo
Vt timed out,Boot rejected,Waiting to GO"
X$!
X$! Start of main code.
X$!
X$`009Say F$Fao( Clear + "Node: !AS", F$TrnLNM( "SYS$NODE" ) )`009`009! Print
V the header
X$`009Temp = "SMP Monitor Modes"
X$`009Say F$Fao( At + Bold + Temp + Normal, 1, (Width - F$Length( Temp )) / 2
V ) ! ...and tell the user
X$`009Temp = "Time:         "
X$`009Say F$Fao( At + Temp, 1, Width - F$Length( Temp ), 0 )`009`009`009! ...
Vand tell the user
X$`009If ('LPeek SMP$GL_FLAGS 'Ep .and. SMP$M_ENABLED) .eq. 0`009`009`009! If
V no SMP code is loaded...
X$`009Then`009Max_CPU`009= 1`009`009`009`009`009`009`009! ...then there can o
Vnly be one CPU
X$`009`009Temp = "(SMP not enabled)"
X$`009`009Say F$Fao( At + Bold + Temp + Normal, 2, (Width - F$Length( Temp ))
V / 2 ) ! ...and tell the user
X$`009Else`009If Width .eq. 80`009`009`009`009`009`009! There can be up to 32
V CPUs under SMP, but...
X$`009`009Then`009Max_CPU`009= 4`009`009`009`009`009`009! ...on an 80 column
V screen we only look at 4
X$`009`009Else`009Max_CPU = 7`009`009`009`009`009`009! ...but with 132 column
Vs, we look at up to 7
X$`009`009EndIf
X$`009EndIf
X$`009Say F$Fao( At + Copyright, 2, 1 )`009`009`009`009`009! Display the copy
Vright notice
X$!
X$`009Offset = 0
X$ 10$:`009If Offset .le. CPU_L_IDLE`009`009`009`009`009`009! Print the line
V headers
X$`009Then`009Say F$Fao( At + Header_'Offset, 7 + Offset / 2, 1 )
X$`009`009Offset = Offset + 4
X$`009`009Goto 10$
X$`009EndIf
X$`009Say F$Fao( At + "Total:", 7 + Offset / 2, 15 )
X$!
X$! Wait for each timing interval, and display the results.
X$!
X$`009First_Time`009= TRUE`009`009`009`009`009`009`009! TRUE if first time th
Vrough data collection
X$`009Gosub GET_CPU_DATA`009`009`009`009`009`009`009! Initialise data collect
Vion
X$`009Say F$Fao( At + "                        ", 2, 1 )`009`009`009! Remove
V the copyright notice
X$ 20$:`009Wait 'Interval`009`009`009`009`009`009`009`009! Wait until next sc
Van time
X$ `009Gosub GET_CPU_DATA`009`009`009`009`009`009`009! Collect the data
X$`009Say F$Fao( At + "!8%T", 1, Width - 8, EXE$GQ_SYSTIME )`009`009`009! Sho
Vw the system time (no centiseconds)
X$`009CPU = 0`009`009`009`009`009`009`009`009`009! For each active CPU...
X$ 30$:`009If CPU .le. Max_CPU_Number
X$`009Then`009Say F$Fao( At + "CPU !UL", 4, 25 + CPU * 15, CPU )`009`009! Say
V which CPU we are looking at
X$`009`009Say F$Fao( At + "!AS"    , 5, 27 - F$Length( State_'CPU ) / 2 + CPU
V * 15, State_'CPU ) ! ...and the state
X$`009`009Offset = 0
X$`009`009Total = 0
X$`009`009Tick_Mult = System_TICs - Last_System_TICs`009`009`009! Ticks in la
Vst scan interval
X$ 40$:`009`009If Offset .le. CPU_L_IDLE`009`009`009`009`009! While some data
V to display...
X$`009`009Then`009Value = F$CvUI( Offset * 8, 32, Mode_Time_'CPU ) - F$CvUI(
V Offset * 8, 32, Last_Mode_Time_'CPU )
X$`009`009`009Value = ( Value * 10000 ) / Tick_Mult`009`009`009! Make into a
V % * 100
X$`009`009`009If Value .lt. 0 Then Value = -Value`009`009`009! Make into unsi
Vgned value!
X$`009`009`009Say F$Fao( At + "!3UL.!2ZL %", 7 + Offset / 2, 23 + CPU * 15, V
Value / 100, Value - (Value/100)*100 )
X$`009`009`009Total = Total + Value`009`009`009`009`009! Add up total %tage
X$`009`009`009Offset = Offset + 4`009`009`009`009`009! Move to next counter i
Vn CPU data
X$`009`009`009Goto 40$
X$`009`009EndIf
X$`009`009Say F$Fao( At + "!3UL.!2ZL %", 7 + Offset / 2, 23 + CPU * 15, Total
V / 100, Total - (Total/100)*100 )
X$`009`009CPU = CPU + 1`009`009`009`009`009`009`009! Move to next CPU
X$`009`009Goto 30$
X$`009EndIf
X$!
X$`009Goto 20$`009`009`009`009`009`009`009`009! Go back to wait for next scan
X$`009Goto END`009`009`009`009`009`009`009`009! Never get here (play safe)
X$!
X$! Read the executive per-CPU database for each active CPU.
+-+-+-+-+-+-+-+-  END  OF PART 1 +-+-+-+-+-+-+-+-

