/* This REXX command file does the working set computation on a specified
   process or the entire system.  It is kicked off by workset.cmd so that the
   exit list processing can clean up the working set primatives. */

parse upper arg All
All = All' terminator'
parse var All Pre '/PLOT' After
if After \= '' then
  PlotSpecified = TRUE
else
  PlotSpecified = FALSE
/*say 'Pre = "'Pre'", After = "'After'", PlotSpecified = 'PlotSpecified*/
parse upper arg Pre '/PLOT' After
All = Pre' 'After

parse var All Pre 'FOR ' After
ForSpecified = FALSE
UntilSpecified = FALSE
if After \= '' then
    ForSpecified = TRUE
else
  do
    parse var All Pre 'UNTIL ' After
    if After \= '' then
      UntilSpecified = TRUE
  end
/*say 'Pre = "'Pre'", After = "'After'", ForSpecified = 'ForSpecified', UntilSpecified = 'UntilSpecified*/

parse var Pre ProcessName Interval WSIntervals junk
if datatype( ProcessName) = 'NUM' then
  do
    WSIntervals = Interval
    Interval = ProcessName
    ProcessName = 'SYSTEM'
  end
if ProcessName = '' then
  ProcessName = 'SYSTEM'
if datatype( Interval) \= 'NUM' then
  do
    Interval = 5
    WSIntervals = 12
  end
if datatype( WSIntervals) \= 'NUM' then
  WSIntervals = 12

if ((ForSpecified = TRUE) & (UntilSpecified = TRUE)) then
  do
    say 'FOR and UNTIL cannot both be specified.'
    ProcessName = '?'
  end

if (ForSpecified = TRUE) then
  do
    parse var After Duration ' HOURS'
    if datatype( Duration) \= 'NUM' then
      do
        say '"Duration" is not a number.'
        ProcessName = '?'
      end
    say 'Working set computation will run for 'Duration' hours.'
  end
if (UntilSpecified = TRUE) then
  do
    parse var After ATime AmPm junk
    if datatype( ATime) \= 'NUM' then
      do
        say '"ATime" is not a number.'
        ProcessName = '?'
      end
    if AmPm = 'PM' then
      ATime = ATime + 12
    say 'Working set computation will run until 'ATime':00:00.'
  end
/*say 'ProcessName = "'ProcessName'", Interval = 'Interval', WSIntervals = 'WSIntervals*/

if ProcessName = '?' then
  do
    say 'This REXX command file does working set calculation on either the entire system'
    say '  or a specified process.  It uses THESEUS0.DLL.'
    say 'Syntax:'
    say '  "WORKSET [Process] [Interval [WSIntervals]] [FOR n [HOURS] | UNTIL n AM|PM]'
    say '           /PLOT"'
    say 'Where:'
    say '  Process is the name of the process to compute the working set.  If the'
    say '    process is not active, the command file will wait for it to start.  The'
    say '    command file terminates when the program terminates.  If there are multiple'
    say '    processes with the same name, the last one started is used.  If the name'
    say '    "system" is used (or if the name is omitted), the entire system is done.'
    say '  Interval is the sample time in seconds.  Default is 5 seconds.'
    say '  WSIntervals is the number of intervals which constitue the "working set".'
    say '    Default is 12.'
    say '  "FOR n [HOURS]" means to do the run for "n" hours.'
    say '  "UNTIL n AM|PM" means to do the run until "n am" or "n pm".'
    say '  "/PLOT" means to output the data ready for plotting.'
    say 'The inputs are not case sensitive.'
    say 'The command file can be terminated with either Ctrl-C or Ctrl-Break.'
    say 'Example: workset for 5 hours'
    say '  Do working set on the whole system every 5 seconds for 5 hours.'
    say 'Example: workset myprog 10 6 until 10 pm'
    say '  Do working set on the process "myprog" every 10 seconds, with 6 intervals'
    say '   making up the working set, until 10 PM.'
    exit
  end

call RxFuncAdd 'SysSleep', 'RexxUtil', 'SysSleep'
call RxFuncAdd 'RT2LoadFuncs', 'THESEUS0', 'RT2LoadFuncs'
rc = RT2LoadFuncs()
if rc \= 0 then
  do
    say 'There was an error.'
    exit
  end

ProcessPid = 0
LookCount = 0
if ProcessName = 'SYSTEM' then
  do
    say 'Computing the working set of the entire system.'
    rc = RT2WSStart('ws_handle')
    if rc \= 0 then
    do
      say 'Working set start did not occur.  rc = 'rc
      if rc = 2 then
         SAY 'The SYSTEM workset is already running.'
      exit rc
    end
  end
else
  do
    say 'Computing the working set of the process "'ProcessName'".'
    do until ProcessPid \= 0
      call RT2FindProcesses 'pTable'
      do i = 1 to pTable.0
        parse value pTable.i with pid parent threads name
        if name = ProcessName then
          ProcessPid = pid
      end
      if ProcessPid = 0 then
        do
          if LookCount = 0 then
            say 'Waiting until the process is active.  (Will look each second.)'
          LookCount = LookCount + 1
          call SysSleep 1
        end
    end
    say 'The process was found with PID = 'D2X(ProcessPid,4)'.'
    rc = RT2WSStart('ws_handle', ProcessPid);
  end

say 'Working set run started at 'time()' on 'date(Language)'.'
say 'Interval is 'Interval' seconds, with 'WSIntervals' intervals in the working set.'
if PlotSpecified = TRUE then
  if ProcessName = 'SYSTEM' then
    say ' time(no colons) RIGHT(now,6,0) RIGHT(ws,6,0) RIGHT(free,6,0)(in Mbytes)'
  else
    say ' time(no colons) RIGHT(now,6,0) RIGHT(ws,6,0) (in Mbytes)'
else
  if ProcessName = 'SYSTEM' then do
    say ' '
    say '        <       Output in pages          >    Number of Processes'
    say '  time     now    ws   accessed free   idle  contributing    Total '
    end
  else
    say '  time     now    ws   accessed  totalRam (in pages)'

if (ForSpecified = TRUE) then
  do
    CurrentTime = time('R')
    Duration = Duration * 3600   /* Convert from hours to seconds. */
  end

do until always = never
  call SysSleep Interval
  if ProcessName = 'SYSTEM' then
    do
      return = RT2WSSystemTick('ws_handle', WSIntervals)
      parse var return rc now ws accessed free idle pu pt resident total
      if PlotSpecified = TRUE then
        do
          parse value time() with Hours ':' Minutes ':' Seconds
          say Hours''Minutes''Seconds RIGHT(now/256,6,0) RIGHT(ws/256,6,0) RIGHT(free/256,6,0)
        end
      else
        say time() RIGHT(now,6,0) RIGHT(ws,6,0)'  'RIGHT(accessed,6,0) RIGHT(free,6,0) RIGHT(idle,6,0)'    'RIGHT(pu,6,0)'      'RIGHT(pt,6,0)
      DROP now accessed ws free idle pu pt
    end
  else
    do
      return = RT2WSProcessTick('ws_handle', WSIntervals)
      parse var return rc now ws accessed total
      if rc = 5 then
        do
          say 'The process has terminated.  The time is 'time()', the date is 'date(Language)'.'
          call terminate
        end
      else
        if PlotSpecified = TRUE then
          do
            parse value time() with Hours ':' Minutes ':' Seconds
            say Hours''Minutes''Seconds RIGHT(now/256,6,0) RIGHT(ws/256,6,0)
          end
        else
          say time() RIGHT(now,6,0) RIGHT(ws,6,0) RIGHT(accessed,6,0)'     'RIGHT(total,6,0)
    end

  if (ForSpecified = TRUE) then
    do
      if (time('E') >= Duration) then
        do
          say 'The run duration has expired.  The time is 'time()', the date is 'date(Language)'.'
          call terminate
        end
    end
  if (UntilSpecified = TRUE) then
    do
      parse value time() with Hours ':' Minutes ':' Seconds
      if (Hours >= ATime) then
        do
          say 'The end run time has occured.  The time is 'time()', the date is 'date(Language)'.'
          call terminate
        end
    end
end

terminate:
  return = RT2WSStop('ws_handle')
  parse var return rc count minimum recommended accessed
  say 'There were 'count' samples taken.'
  say 'Absolute minimum number of pages is 'minimum'.'
  say 'Recommended number of pages is      'recommended'.'
  say 'Total number of accessed pages is   'accessed'.'
  exit
return
