i91@nikhefh.hep.nl (Fons Rademakers) (01/28/89)
Here follows a little program to display in a histogram the cpu load on your node. Try it, have fun and let me know if you made some inprovements. ========= cut here =========== #!/bin/sh # to extract, remove the header and type "sh filename" if `test ! -s ./Comp` then echo "writting ./Comp" cat > ./Comp << '\Rogue\Monster\' #! /bin/sh # don't compile with -save option, routine display_load may be called recursively ftn load_stat -indexl -zero -type bind -b load_stat.exe load_stat.bin \Rogue\Monster\ else echo "will not over write ./Comp" fi if `test ! -s ./README` then echo "writting ./README" cat > ./README << '\Rogue\Monster\' This directory contains a little program that monitors the cpu load of your node. It creates a little window at the bottom-right corner of your screen in which a cpu load histogram will be displayed. The histogram is updated every 5 sec. until the first bin reaches the max screen width. When that happens the histogram will be compacted to half its size and the time interval will increase by a factor 2. This continues add infinitum. Every hour is marked by a vertical line. The colors used by load_stat may be redefined. To do this place load_stat.config in you ~/user_data directory and change the color indices. Also included are 2 key-definition files (for 1024 and 1280 screens) that arrange your windows in a pseudo-tiled way (by the courtesy of Kee Hinckley). With the np2s and np3s keys (numeric-pad-shift 2 and 3) you can change the load_stat window. Put load_stat in your ~/com or ~/bin directory to start load_stat.exe in the background. Load_stat was a quick hack made some Sunday afternoon, but it contains a lot of interesting Apollo programming techniques (especially for the novice Apollo programmer), a.o.: animation using an off-screen bitmap, gpr refresh routines, usage of the ctm manager, undocumented proc1 routine. Have fun, Fons Rademakers (i91@nikhefh.hep.nl) \Rogue\Monster\ else echo "will not over write ./README" fi if `test ! -s ./keydefs1024` then echo "writting ./keydefs1024" cat > ./keydefs1024 << '\Rogue\Monster\' (961,000)dr;(961,063)idf (000,000)dr;(480,384) wdf 1 (483,000)dr;(959,384) wdf 2 (000,386)dr;(480,770) wdf 3 (483,386)dr;(959,770) wdf 4 (000,000)dr;(480,384) wdf 5 (483,000)dr;(959,384) wdf 6 (000,386)dr;(480,770) wdf 7 (483,386)dr;(959,770) wdf 8 kd np7 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(480,384)wg;tl ke kd np4 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(480,770)wg;tl ke kd np1 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(480,384)wg;twb -l;twb -b;dr;(000,770)wm;tl ke kd np8 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(959,384)wg;tl ke kd np5 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(959,770)wg;tl ke kd np2 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(959,384)wg;twb -l;twb -b;dr;(000,770)wm;tl ke kd np9 twb -r;twb -t;dr;(959,000)wm;twb -l;twb -b;dr;(483,384)wg;tl ke kd np6 twb -r;twb -t;dr;(959,000)wm;twb -l;twb -b;dr;(483,770)wg;tl ke kd np3 twb -r;twb -t;dr;(959,000)wm;twb -l;twb -b;dr;(483,384)wg;twb -r;twb -b;dr;(959,770)wm;tl ke # load_stat keydefs: shift-keypad-2: stretch load_stat window over full # screen width # shift-keypad-3: put load_stat window back in corner kd np3s (1000,750)dr; gm; twb -r; twb -b; dr; (1023,770)wm; twb -l; twb -t; dr; (961,707)wg; tl ke kd np2s (1000,750)dr; gm; twb -l; twb -t; dr; ( 000,707)wg; tl ke cms;ti;tl \Rogue\Monster\ else echo "will not over write ./keydefs1024" fi if `test ! -s ./keydefs1280` then echo "writting ./keydefs1280" cat > ./keydefs1280 << '\Rogue\Monster\' (1217,000)dr;(1217,063)idf (000,000)dr;(609,496) wdf 1 (612,000)dr;(1215,496) wdf 2 (000,498)dr;(609,994) wdf 3 (612,498)dr;(1215,994) wdf 4 (000,000)dr;(609,496) wdf 5 (612,000)dr;(1215,496) wdf 6 (000,498)dr;(609,994) wdf 7 (612,498)dr;(1215,994) wdf 8 kd np7 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(609,496)wg;tl ke kd np4 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(609,994)wg;tl ke kd np1 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(609,496)wg;twb -l;twb -b;dr;(000,994)wm;tl ke kd np8 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(1215,496)wg;tl ke kd np5 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(1215,994)wg;tl ke kd np2 twb -l;dr;(000,000)wg;twb -r;twb -b;dr;(1215,496)wg;twb -l;twb -b;dr;(000,994)wm;tl ke kd np9 twb -r;twb -t;dr;(1215,000)wm;twb -l;twb -b;dr;(612,496)wg;tl ke kd np6 twb -r;twb -t;dr;(1215,000)wm;twb -l;twb -b;dr;(612,994)wg;tl ke kd np3 twb -r;twb -t;dr;(1215,000)wm;twb -l;twb -b;dr;(612,496)wg;twb -r;twb -b;dr;(1215,994)wm;tl ke # load_stat keydefs kd np3s (1250,950)dr; gm; twb -r; twb -b; dr; (1279,995)wm; twb -l; twb -t; dr; (1217,932)wg; tl ke kd np2s (1250,950)dr; gm; twb -l; twb -t; dr; ( 000,932)wg; tl ke cms;ti;tl \Rogue\Monster\ else echo "will not over write ./keydefs1280" fi if `test ! -s ./load_stat` then echo "writting ./load_stat" cat > ./load_stat << '\Rogue\Monster\' #! /bin/sh # # Install the load_stat program in the background xdmc "cms" xdmc "(0,0)dr; (100,150)cp /user/rdm/src/load_stat/load_stat.exe -n load_stat; wi load_stat" \Rogue\Monster\ else echo "will not over write ./load_stat" fi if `test ! -s ./load_stat.cmn` then echo "writting ./load_stat.cmn" cat > ./load_stat.cmn << '\Rogue\Monster\' integer*4 init_bitmap_desc, off_bitmap_desc, off_attr_desc, + maxbin, r_time_int, time_mark, bg_color, hist_color, + mark_color, color_id, ticks, text_color integer*2 stream_id, pad_window, bitmap_size, slots_total, + vis_list, off_bitmap_size, hi_plane, font_id, + src_window real*8 cpu_start character*5 time_str * common /load_common/ init_bitmap_desc, stream_id, pad_window(4), + bitmap_size(2), slots_total, vis_list(4,15), + cpu_start, off_bitmap_size(2), hi_plane, + off_bitmap_desc, off_attr_desc, maxbin, + r_time_int, time_mark, ticks, text_color, + bg_color, hist_color, mark_color, + color_id(8), font_id, src_window(4) * common /load_text/ time_str \Rogue\Monster\ else echo "will not over write ./load_stat.cmn" fi if `test ! -s ./load_stat.config` then echo "writting ./load_stat.config" cat > ./load_stat.config << '\Rogue\Monster\' # first entry =back grnd color, 2=histogram color, 3=hour mark color, 4=time color # colors are: 1=red, 2=green, 3=blue, 4=cyan, 5=magenta, 6=yellow, 7=black, 8=white # ******** don't remove these three lines ******** 3 6 1 8 \Rogue\Monster\ else echo "will not over write ./load_stat.config" fi if `test ! -s ./load_stat.ftn` then echo "writting ./load_stat.ftn" cat > ./load_stat.ftn << '\Rogue\Monster\' program load_stat ************************************************************************ * * * LOAD_STAT (vsn 1.00) * * * * This program shows in a little window the total CPU load statistics. * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 27-Nov-1988 * * modified by: * ************************************************************************ * %nolist %include '/sys/ins/base.ins.ftn' %include '/sys/ins/pad.ins.ftn' %include '/sys/ins/gpr.ins.ftn' %include '/sys/ins/cal.ins.ftn' %include '/sys/ins/time.ins.ftn' %list * %include 'load_stat.cmn' * external load_window_proc external load_disp_mem_proc * integer*4 status, cpu_load, pad_check integer*2 disp_char(28), disp_len, r_clock(3) logical unobscured character*26 dmcmd * data bitmap_size /1280, 1280/ * *-- start real time interval (r_time_int) is 5 seconds, mark every hour * r_time_int = 5 time_mark = 3600/r_time_int * *-- check every pad_check seconds if the window needs to be refreshed * ticks = 0 pad_check = 1 call cal_$sec_to_clock(pad_check, r_clock) * call gpr_$inq_disp_characteristics(gpr_$direct, stream_$stdout, + int2(56), disp_char, disp_len, status) * hi_plane = disp_char(15) - 1 maxbin = disp_char(7) * *-- make window with width and height of 63 pixels (icon size), border *-- of a pad is 5 pixels and the legend (including border) is 24 pixels * if (disp_char(7) .gt. 1200) then pad_window(1) = 994 - 5 - 34 { from the bottom starting at 994 } pad_window(2) = 1280 - 53 - 5 pad_window(3) = 63 - 5 - 5 pad_window(4) = 63 - 5 - 24 else pad_window(1) = 770 - 5 - 34 { from the bottom starting at 770 } pad_window(2) = 1024 - 53 - 5 pad_window(3) = 63 - 5 - 5 pad_window(4) = 63 - 5 - 24 endif * call pad_$create_window(' ', int2(0), pad_$transcript, int2(1), + pad_window, stream_id, status) * call pad_$set_border(stream_id, int2(1), .false., status) * call pad_$set_auto_close(stream_id, int2(1), .true., status) * *-- set off the cursor in the new window, a 'tn' will not move on it * write(dmcmd,1000) pad_window(2)+10, pad_window(1)+10 1000 format('dr;(',i4.4,',',i4.4,')curs -off;gm') * call pad_$dm_cmd(stream_id, dmcmd, int2(26), status) * call gpr_$init(gpr_$direct, stream_id, bitmap_size, hi_plane, + init_bitmap_desc, status) * call gpr_$set_refresh_entry(iaddr(load_window_proc), + iaddr(load_disp_mem_proc), status) * call gpr_$set_obscured_opt(gpr_$ok_if_obs, status) * call gpr_$enable_input(gpr_$locator_update, 0, status) call gpr_$set_cursor_active(.true., status) * call gpr_$load_font_file('/sys/dm/fonts/f5x7', int2(18), font_id, + status) * *-- default colors, bg = white, histo = red, mark = black, text = black * if (hi_plane .gt. 0) then call get_color_ids bg_color = color_id(8) hist_color = color_id(1) mark_color = color_id(7) text_color = color_id(7) call read_load_config else bg_color = 0 hist_color = 1 mark_color = 1 text_color = 1 endif * call get_start_time(time_str) * cpu_start = 0.0 call get_load(cpu_load, .true.) * call display_load(cpu_load, .true., .true.) * 10 call time_$wait(time_$relative, r_clock, status) * ticks = ticks + 1 if (mod(ticks, r_time_int) .eq. 0) then * ticks = 0 call get_load(cpu_load, .false.) *$$$ print *, 'CPU load = ', cpu_load, ' %' * call display_load(cpu_load, .false., .false.) * else * *-- check if display changed size or position *-- if an update is needed then the refresh routine will be triggered *-- by the gpr_$acquire_display call * unobscured = gpr_$acquire_display(status) call gpr_$release_display(status) endif * goto 10 * end subroutine get_load(cpu_load, init) ************************************************************************ * * * GET_LOAD (vsn 2.00) * * * * Get load every R_TIME_INT seconds. * * The algorithm is very simple: calculate how many CPU time has been * * used by all processes in the real time interval R_TIME_INT. If the * * elapsed CPU time is equal to the R_TIME_INT we have a load of 100%. * * * * Algorithm modified by Achille to get instead of the time used by * * all processes the NULL (i.e. idle time) per time interval. The * * arithmetic is further trivial. * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 27-Nov-1988 * * modified by: Achille Petrilli (achille@cernapo.cern.ch), 29-Nov-1988 * ************************************************************************ * %include '/sys/ins/base.ins.ftn' %include 'load_stat.cmn' * *-- pid is the pid of the NULL process *-- (init is # 1 under sr10, I guess DM is #1 under sr9) * integer*2 pid parameter (pid = 2) * integer*2 res(12) integer*4 status, cpu_load, i real*8 cpu_sec, t_load logical init * do i = 1, 12 res(i) = 0 enddo * call proc1_$get_info(pid, res, status) if (status .ne. status_$ok) call error_$print(status) call cal_$float_clock(res(9), cpu_sec) * if (init) then cpu_load = 0 else t_load = + dabs(dble(r_time_int)-(cpu_sec-cpu_start))/ + dble(r_time_int)*100.D0 cpu_load = dnint(t_load) if (cpu_load .gt. 100) cpu_load = 100 endif * cpu_start = cpu_sec * end subroutine display_load(cpu_load, init, pos_change) ************************************************************************ * * * DISPLAY_LOAD (vsn 1.00) * * * * Displays the system load graphically in a histogram. * * The historgram is drawn in an off-screen bitmap and when complete * * copied to the screen. * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 27-Nov-1988 * * modified by: * ************************************************************************ * %nolist %include '/sys/ins/base.ins.ftn' %include '/sys/ins/gpr.ins.ftn' %list * %include 'load_stat.cmn' * integer*2 x(2), y(2), pos(2), top, xt, yt integer*4 status, cpu_load, t_desc, bins(1280), ibin, i, j, k real yscale logical init, pos_change, unobscured * data yscale / 100. / data ibin / 0 / data bins / 1280*0 / data top / 2 / data pos / 0, 0 / data off_bitmap_size / 1280, 1280 / * *-- create off screen bitmap and attribute block * if (init) then call gpr_$allocate_attribute_block(off_attr_desc, status) call gpr_$allocate_bitmap(off_bitmap_size, hi_plane, + off_attr_desc, off_bitmap_desc, + status) endif * *-- in case of position change of the pad (and at init time) get the *-- window size and set the bitmaps accordingly, also set the y-scale * if (pos_change) then call pad_$inq_full_window(stream_id, int2(1), pad_window, + status) * call gpr_$set_bitmap_dimensions(init_bitmap_desc, + pad_window(3), hi_plane, + status) * call gpr_$set_bitmap_dimensions(off_bitmap_desc, + pad_window(3), hi_plane, + status) * *-- full scale (100%) is just a little ('top' pixels) less than *-- the full window * yscale = float(pad_window(4)-top)/100.0 * src_window(1) = 0 src_window(2) = 0 src_window(3) = pad_window(3) src_window(4) = pad_window(4) * endif * *-- get current bitmap desc * call gpr_$inq_bitmap(t_desc, status) * *-- switch to offscreen bitmap and clear it * call gpr_$set_bitmap(off_bitmap_desc, status) call gpr_$clear(bg_color, status) * call gpr_$set_text_font(font_id, status) call gpr_$set_text_value(text_color, status) call gpr_$set_text_background_value(bg_color, status) * if (.not. pos_change) then if (mod(ibin,time_mark) .ge. 0 .and. + mod(ibin,time_mark) .le. 1) then cpu_load = cpu_load + 1000 endif if (ibin .eq. maxbin) call divide_time_int(bins, ibin) ibin = ibin + 1 bins(ibin) = cpu_load endif * j = ibin + 1 do 10 i = pad_window(3), 1, -1 j = j - 1 if (j .eq. 0) goto 20 x(1) = i - 1 x(2) = i - 1 y(1) = pad_window(4) - 1 if (bins(j) .gt. 200) then k = 100 call gpr_$set_draw_value(mark_color, status) else k = bins(j) call gpr_$set_draw_value(hist_color, status) endif y(2) = y(1) - int(float(k)*yscale) if (y(2) .lt. top) y(2) = top if (y(2) .eq. y(1)) goto 10 call gpr_$multiline(x, y, int2(2), status) 10 continue * 20 xt = i - 40 yt = 9 call gpr_$move(xt, yt, status) call gpr_$text(time_str, int2(5), status) * *-- return to original bitmap * call gpr_$set_bitmap(t_desc, status) * unobscured = gpr_$acquire_display(status) * call gpr_$set_cursor_active(.false., status) * if (unobscured) then * call gpr_$set_clipping_active(.false., status) call gpr_$pixel_blt(off_bitmap_desc, src_window, pos, status) * else * call gpr_$set_clipping_active(.true., status) call gpr_$inq_vis_list(int2(15), slots_total, vis_list, status) * do i = 1, slots_total call gpr_$set_clip_window(vis_list(1,i), status) call gpr_$pixel_blt(off_bitmap_desc, src_window, pos, + status) enddo * endif * call gpr_$set_cursor_active(.true., status) * call gpr_$release_display(status) * end subroutine load_window_proc(unobscured, position_change) ************************************************************************ * * * LOAD_WINDOW_PROC (vsn 1.00) * * * * Load window refresh procedure * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 27-Nov-1988 * * modified by: * ************************************************************************ * logical unobscured, position_change, change * integer*4 status integer*2 acquire_count * call gpr_$force_release(acquire_count, status) * change = unobscured .or. position_change call display_load(0, .false., change) * end subroutine load_disp_mem_proc(unobscured, position_change) ************************************************************************ * * * LOAD_DISP_MEM_PROC (vsn 1.00) * * * * Procedure that could refresh any hidden display memory. * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 27-Nov-1988 * * modified by: * ************************************************************************ * logical unobscured, position_change * end subroutine divide_time_int(bins, nbin) ************************************************************************ * * * DIVIDE_TIME_INT (vsn 1.00) * * * * Compact array BINS of length NBIN. Return compacted array * * of length NBIN/2 * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 28-Nov-1988 * * modified by: * ************************************************************************ * %include 'load_stat.cmn' * integer bins(*), nbin, i, j * j = 0 do i = 1, nbin, 2 j = j + 1 if (bins(i) .gt. 200) bins(i) = bins(i) - 1000 if (bins(i+1) .gt. 200) bins(i+1) = bins(i+1) - 1000 bins(j) = nint(float(bins(i) + bins(i+1))/2.0) enddo * do i = j+1, nbin bins(i) = 0 enddo * nbin = nbin / 2 * *-- double time interval and set new time marks every hour * r_time_int = 2*r_time_int time_mark = 3600/r_time_int * do i = 0, nbin-1 if (mod(i,time_mark) .ge. 0 .and. + mod(i,time_mark) .le. 1) then bins(i+1) = bins(i+1) + 1000 endif enddo * end subroutine read_load_config ************************************************************************ * * * READ_LOAD_CONFIG (vsn 1.00) * * * * Reads the file ~/user_data/load.config for the desired colors. * * Very primitive and a rigid format!!! * * * * Entry 1 is the background color. * * Entry 2 is the histogram color. * * Entry 3 is the hour mark color. * * Entry 4 is the start time color. * * * * The color ids load_map uses are: * * 1 red * * 2 green * * 3 blue * * 4 cyan * * 5 magenta * * 6 yellow * * 7 black * * 8 white * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 28-Nov-1988 * * modified by: * ************************************************************************ * %include 'load_stat.cmn' * character*80 comment integer i, icol logical fexist * inquire(file='~/user_data/load_stat.config', exist=fexist) * *-- is file does not exist, use defaults * if (.not. fexist) return * open(1, file='~/user_data/load_stat.config', status='readonly') * *-- skip the three required comment lines * do i = 1, 3 read(1, '(a)') comment enddo * read(1, '(i1)', err=999,end=999) icol bg_color = color_id(icol) read(1, '(i1)', err=999,end=999) icol hist_color = color_id(icol) read(1, '(i1)', err=999,end=999) icol mark_color = color_id(icol) read(1, '(i1)', err=999,end=999) icol text_color = color_id(icol) * 999 close(1) return * end subroutine get_color_ids ************************************************************************ * * * GET_COLOR_IDS (vsn 1.00) * * * * Get the color table indices of the 8 basic colors, without * * disturbing any exiting colormap configuration. * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 28-Nov-1988 * * modified by: * ************************************************************************ * %include 'load_stat.cmn' * integer*2 max_dist integer*4 color_val(8), status, i * *-- red green blue cyan *-- magenta yellow black white * data color_val /16#FF0000, 16#00FF00, 16#0000FF, 16#00FFFF, + 16#FF00FF, 16#FFFF00, 16#000000, 16#FFFFFF/ data max_dist /1/ * *-- find colors in colormap * do i = 1, 8 CALL ctm_$find_color(color_val(i), max_dist, color_id(i), + status) enddo * end subroutine get_start_time(time_str) ************************************************************************ * * * GET_START_TIME (vsn 1.00) * * * * Get load_stat's start time. * * * * written by: Fons Rademakers (i91@nikhefh.hep.nl), 28-Nov-1988 * * modified by: * ************************************************************************ * %INCLUDE '/sys/ins/cal.ins.ftn' * integer*2 loctim(6) character*5 time_str character*2 hh, mm, t * call cal_$decode_local_time(loctim) * if (loctim(4) .lt. 10) then write(t, '(i1)') loctim(4) hh = '0'//t else write(hh, '(i2)') loctim(4) endif If (loctim(5) .lt. 10) then write(t, '(i1)') loctim(5) mm = '0'//t else write(mm, '(i2)') loctim(5) endif * time_str = hh//':'//mm * end \Rogue\Monster\ else echo "will not over write ./load_stat.ftn" fi echo "Finished archive 1 of 1" exit -- Org: NIKHEF-H, National Institute for Nuclear and High-Energy Physics. Mail: Kruislaan 409, P.O. Box 41882, 1009 DB Amsterdam, the Netherlands Phone: (20)5925018 or 5925003 Telex: 10262 (hef nl) UUCP: i91@nikhefh.hep.nl BITNET: nikhefh!i91@mcvax.bitnet
vince@bcsaic.UUCP (Vince Skahan) (02/03/89)
I tried to run your cpu load program and it compiles just fine on my DN3000 (1280x1024 B+W, 8MB memory) but all I get is a white screen (no load histogram appears)...does this have something to do with the fact that I'm running SR10.1 on thus node ( - has an undocumented call you used gone away at SR10.x) Drop me a note at the address below or post a follow-up. This is a nice program to have around if I can get it to run (you might want to get a hold of "meters" from ADus (I think) for another way to have on-line display of system usage). Anyway, I'm very interested in getting your program up and running here and would appreciate any help you can give... Thanks. -- Vince Skahan Boeing Computer Services - Phila. (215) 591-4116 ARPA: skahan@boeing.com UUCP: bcsaic!skahan Note: the opinions expressed above are mine and have no connection to Boeing...