v0.98
[apc.git] / apc.ml
blob71aa9ccc72b9be5bd2109cf87a23a84e7fb30f60
1 open Format
3 let (|>) x f = f x
4 let (|<) f x = f x
6 let font = Glut.BITMAP_HELVETICA_12
7 let draw_string ?(font=font) x y s =
8 GlPix.raster_pos ~x ~y ();
9 String.iter (fun c -> Glut.bitmapCharacter ~font ~c:(Char.code c)) s
12 type stats =
13 { all : float
14 ; user : float
15 ; nice : float
16 ; sys : float
17 ; idle : float
18 ; iowait : float
19 ; intr : float
20 ; softirq : float
24 let zero_stat =
25 { all = 0.0
26 ; user = 0.0
27 ; nice = 0.0
28 ; sys = 0.0
29 ; idle = 0.0
30 ; iowait = 0.0
31 ; intr = 0.0
32 ; softirq = 0.0
36 let neg_stat a =
37 { all = -.a.all
38 ; user = -.a.user
39 ; nice = -.a.nice
40 ; sys = -.a.sys
41 ; idle = -.a.idle
42 ; iowait = -.a.iowait
43 ; intr = -.a.intr
44 ; softirq = -.a.softirq
48 let scale_stat a s =
49 { all = a.all *. s
50 ; user = a.user *. s
51 ; nice = a.nice *. s
52 ; sys = a.sys *. s
53 ; idle = a.idle *. s
54 ; iowait = a.iowait *. s
55 ; intr = a.intr *. s
56 ; softirq = a.softirq *. s
60 let add_stat a b =
61 { all = a.all +. b.all
62 ; user = a.user +. b.user
63 ; nice = a.nice +. b.nice
64 ; sys = a.sys +. b.sys
65 ; idle = a.idle +. b.idle
66 ; iowait = a.iowait +. b.iowait
67 ; intr = a.intr +. b.intr
68 ; softirq = a.softirq +. b.softirq
72 module NP = struct
73 type sysinfo =
74 { uptime: int64
75 ; loads: int64 * int64 * int64
76 ; totalram: int64
77 ; freeram: int64
78 ; sharedram: int64
79 ; bufferram: int64
80 ; totalswap: int64
81 ; freeswap: int64
82 ; procs: int64
86 external get_nprocs : unit -> int = "ml_get_nprocs"
87 external idletimeofday : Unix.file_descr -> int -> float array
88 = "ml_idletimeofday"
89 external sysinfo : unit -> sysinfo = "ml_sysinfo"
90 external waitalrm : unit -> unit = "ml_waitalrm"
91 external get_hz : unit -> int = "ml_get_hz"
92 external setnice : int -> unit = "ml_nice"
93 external delay : float -> unit = "ml_delay"
94 external is_winnt : unit -> bool = "ml_is_winnt"
96 let winnt = is_winnt ()
98 let user = 0
99 let nice = 1
100 let sys = 2
101 let idle = 3
102 let iowait = 4
103 let intr = 5
104 let softirq = 6
106 let hz = get_hz () |> float
108 let jiffies_to_sec j =
109 float j /. hz
112 let parse_uptime () =
113 let ic = open_in "/proc/uptime" in
114 let vals = Scanf.fscanf ic "%f %f" (fun u i -> (u, i)) in
115 close_in ic;
116 vals
119 let nprocs = get_nprocs ()
121 let rec parse_int_cont s pos =
122 let slen = String.length s in
123 let pos =
124 let rec skipws pos =
125 if pos = slen
126 then pos
127 else
128 if String.get s pos = ' '
129 then succ pos |> skipws
130 else pos
131 in skipws pos
133 let endpos =
134 try String.index_from s pos ' '
135 with Not_found -> slen
137 let i = endpos - pos |> String.sub s pos
138 |> int_of_string
139 |> jiffies_to_sec in
140 if endpos = slen
141 then
142 `last i
143 else
144 `more (i, fun () -> succ endpos |> parse_int_cont s)
147 let parse_cpul s =
148 let rec tolist accu = function
149 | `last i -> i :: accu
150 | `more (i, f) -> f () |> tolist (i :: accu)
152 let index = String.index s ' ' in
153 let cpuname = String.sub s 0 index in
154 let vals = parse_int_cont s (succ index) |> tolist [] in
155 let vals = List.rev |<
156 if List.length vals < 7
157 then
158 0.0 :: 0.0 :: 0.0 :: 0.0 :: vals
159 else
160 vals
162 cpuname, Array.of_list vals
165 let parse_stat () =
166 if winnt
167 then
168 fun () ->
169 let ia = idletimeofday Unix.stdin nprocs in
170 let rec convert accu total n =
171 if n = nprocs
172 then
173 let t = total in
174 let a = "cpu", Array.make 7 t in
175 a :: List.rev accu
176 else
177 let i = Array.get ia n in
178 let total = total +. i in
179 let v = "cpu" ^ string_of_int n, Array.make 7 i in
180 convert |< v :: accu |< total |< succ n
182 convert [] 0.0 0
183 else
184 fun () ->
185 let ic = open_in "/proc/stat" in
186 let rec loop i accu =
187 if i = -1
188 then List.rev accu
189 else (input_line ic |> parse_cpul) :: accu |> loop (pred i)
191 let ret = loop nprocs [] in
192 close_in ic;
196 let getselfdir () =
198 Filename.dirname |< Unix.readlink "/proc/self/exe"
199 with exn ->
200 "./"
204 module Args = struct
205 let banner =
206 [ "Amazing Piece of Code by insanely gifted programmer, Version 0.98"
207 ; "Motivation by: gzh and afs"
208 ; "usage: "
209 ] |> String.concat "\n"
211 let freq = ref 1.0
212 let interval = ref 15.0
213 let devpath = NP.getselfdir () |> Filename.concat |< "itc" |> ref
214 let pgrid = ref 10
215 let sgrid = ref 10
216 let w = ref 400
217 let h = ref 200
218 let verbose = ref false
219 let delay = ref 0.04
220 let ksampler = ref true
221 let barw = ref 100
222 let bars = ref 50
223 let sigway = ref true
224 let niceval = ref 0
225 let gzh = ref false
226 let scalebar = ref false
227 let timer = ref 100
228 let debug = ref false
229 let poly = ref false
230 let uptime = ref false
231 let icon = ref false
232 let labels = ref true
233 let mgrid = ref false
234 let sepstat = ref false
236 let pad n s =
237 let l = String.length s in
238 if l >= n
239 then
241 else
242 let d = String.make n ' ' in
243 StringLabels.blit ~src:s ~dst:d
244 ~src_pos:0 ~len:l
245 ~dst_pos:0;
249 let sooo b = if b then "on" else "off"
250 let dA tos s {contents=v} = s ^ " (" ^ tos v ^ ")"
251 let dF = dA |< sprintf "%4.2f"
252 let dB = dA sooo
253 let dcB = dA sooo
254 let dI = dA string_of_int
255 let dS = dA (fun s -> "`" ^ String.escaped s ^ "'")
257 let sF opt r doc =
258 "-" ^ opt, Arg.Set_float r, pad 9 "<float> " ^ doc |> dF |< r
260 let sI opt r doc =
261 "-" ^ opt, Arg.Set_int r, pad 9 "<int> " ^ doc |> dI |< r
263 let sB opt r doc =
264 "-" ^ opt, Arg.Set r, pad 9 "" ^ doc |> dB |< r
266 let sS opt r doc =
267 "-" ^ opt, Arg.Set_string r, pad 9 "<string> " ^ doc |> dS |< r
269 let fB opt r doc =
270 if r.contents
271 then
272 "-" ^ opt, Arg.Clear r, pad 9 "" ^ doc |> dB |< r
273 else
274 "-" ^ opt, Arg.Set r, pad 9 "" ^ doc |> dcB |< r
276 let init () =
277 let opts =
278 [ sF "f" freq "sampling frequency in seconds"
279 ; sF "D" delay "refresh delay in seconds"
280 ; sF "i" interval "history interval in seconds"
281 ; sI "p" pgrid "percent grid items"
282 ; sI "s" sgrid "history grid items"
283 ; sI "w" w "width"
284 ; sI "h" h "height"
285 ; sI "b" barw "bar width"
286 ; sI "B" bars "number of CPU bars"
287 ; sI "n" niceval "value to renice self on init"
288 ; sI "t" timer "timer frequency in herz"
289 ; sS "d" devpath "path to itc device"
290 ; fB "k" ksampler |< "kernel sampler"
291 ^ (if NP.winnt then "" else " (`/proc/[stat|uptime]')")
292 ; fB "g" gzh "gzh way (does not quite work yet)"
293 ; fB "u" uptime
294 "`uptime' instead of `stat' as kernel sampler (UP only)"
295 ; sB "v" verbose "verbose"
296 ; fB "S" sigway "sigwait delay method"
297 ; fB "C" sepstat "separate sys/nice/intr/iowait values (kernel sampler)"
298 ; fB "c" scalebar "constant bar width"
299 ; fB "P" poly "filled area instead of lines"
300 ; fB "I" icon "icon (hack)"
301 ; fB "l" labels "labels"
302 ; fB "m" mgrid "moving grid"
305 let opts =
306 if NP.winnt
307 then
308 begin
309 let nixopts = ["-n"; "-u"; "-d"; "-I"; "-S"; "-g"] in
310 prerr_endline "Only kernel sampler is available on Windows";
311 List.filter (fun (s, _, _) -> List.mem s nixopts |> not) opts
313 else
314 opts
316 Arg.parse opts
317 (fun s ->
318 "don't know what to do with " ^ s |> prerr_endline;
319 exit 100
321 banner;
325 module Gzh = struct
326 let lim = ref 0
327 let stop = ref false
328 let refdt = ref 0.0
330 let rec furious_cycle i =
331 if not !stop && i > 0
332 then pred i |> furious_cycle
333 else (i, Unix.gettimeofday ())
336 let init verbose =
337 let t = 0.5 in
338 let it = { Unix.it_interval = t; it_value = t } in
339 let tries = 1 in
340 let handler =
341 let n = ref tries in
342 fun _ ->
343 decr n;
344 stop := !n = 0;
346 let sign = Sys.sigalrm in
347 let oldh = Sys.signal sign |< Sys.Signal_handle handler in
348 let oldi = Unix.setitimer Unix.ITIMER_REAL it in
349 let oldbp = Unix.sigprocmask Unix.SIG_BLOCK [sign] in
350 let () = NP.waitalrm () in
351 let () = stop := false in
352 let oldup = Unix.sigprocmask Unix.SIG_UNBLOCK [sign] in
353 let t1 = Unix.gettimeofday () in
354 let n, t2 = furious_cycle max_int in
355 let () = refdt := t2 -. t1 in
356 let () = lim := tries * (max_int - n) in
357 let () = if verbose then
358 begin
359 printf "Completed %d iterations in %f seconds@." !lim !refdt
360 end in
361 let _ = Unix.sigprocmask Unix.SIG_UNBLOCK oldup in
362 let _ = Unix.setitimer Unix.ITIMER_REAL oldi in
363 let _ = Unix.sigprocmask Unix.SIG_BLOCK oldbp in
364 let _ = Sys.signal sign oldh in
368 let gen f =
369 let thf () =
370 NP.setnice 20;
371 stop := false;
372 let l = ref 0 in
373 let rec loop t1 =
374 let _, t2 = furious_cycle !lim in
375 let dt = t2 -. t1 in
376 incr l;
377 if !Args.debug && !l > 10
378 then
379 begin
380 printf "Completed %d iterations in %f seconds load %f@."
381 !lim dt |< !refdt /. dt;
382 l := 0;
385 !refdt /. dt |> f;
386 loop t2
388 Unix.gettimeofday () |> loop
390 let _ = Thread.create thf () in
395 let oohz oohz fn =
396 let prev = ref 0.0 in
397 fun () ->
398 let a = !prev in
399 let b = Unix.gettimeofday () in
400 if b -. a > oohz
401 then
402 begin
403 prev := b;
404 fn ()
408 module Delay = struct
409 let sighandler signr = ()
411 let winfreq = ref 0.0
413 let init freq gzh =
414 if NP.winnt
415 then
416 winfreq := 1.0 /. float freq
417 else
418 let () =
419 Sys.Signal_handle sighandler |> Sys.set_signal Sys.sigalrm;
420 if !Args.sigway
421 then
422 let l = if gzh then [Sys.sigprof; Sys.sigvtalrm] else [] in
423 Unix.sigprocmask Unix.SIG_BLOCK |< Sys.sigalrm :: l |> ignore;
426 let v = 1.0 /. float freq in
427 let t = { Unix.it_interval = v; it_value = v } in
428 let _ = Unix.setitimer Unix.ITIMER_REAL t in
432 let delay () =
433 if NP.winnt
434 then
435 NP.delay !winfreq
436 else
437 begin
438 if !Args.sigway
439 then
440 NP.waitalrm ()
441 else
442 begin
443 try let _ = Unix.select [] [] [] ~-.1.0 in ()
444 with Unix.Unix_error (Unix.EINTR, _, _) -> ()
450 type sampler =
451 { color : Gl.rgb;
452 getyielder : unit -> unit -> float option;
453 update : float -> float -> float -> float -> unit;
456 module Sampler(T : sig val nsamples : int val freq : float end) =
457 struct
458 let nsamples = T.nsamples + 1
459 let samples = Array.create nsamples 0.0
460 let head = ref 0
461 let tail = ref 0
462 let active = ref 0
464 let update v n =
465 let n = min nsamples n in
466 let rec loop i j =
467 if j = 0
468 then ()
469 else
470 let i = if i = nsamples then 0 else i in
471 Array.set samples i v;
472 loop (succ i) (pred j)
474 let () = loop !head n in
475 let () = head := (!head + n) mod nsamples in
476 let () = active := min (!active + n) nsamples in
480 let getyielder () =
481 let tail =
482 let d = !head - !active in
483 if d < 0
484 then nsamples + d
485 else d
487 let ry = ref (fun () -> assert false) in
488 let rec yield i () =
489 if i = !active
490 then None
491 else
492 begin
493 ry := succ i |> yield;
494 Some ((i + tail) mod nsamples |> Array.get samples)
497 ry := yield 0;
498 (fun () -> !ry ());
501 let update t1 t2 i1 i2 =
502 let d = t2 -. t1 in
503 let i = i2 -. i1 in
504 let isamples = d /. T.freq |> truncate in
505 let l = 1.0 -. (i /. d) in
506 update l isamples;
510 module type ViewSampler =
512 val getyielder : unit -> unit -> float option
513 val update : float -> float -> float -> float -> unit
516 module type View =
518 val x : int
519 val y : int
520 val w : int
521 val h : int
522 val sgrid : int
523 val pgrid : int
524 val freq : float
525 val interval : float
526 val samplers : sampler list
529 module View(V: sig val w : int val h : int end) = struct
530 let ww = ref 0
531 let wh = ref 0
532 let funcs = ref []
534 let keyboard ~key ~x ~y =
535 if key = 27 || key = Char.code 'q'
536 then exit 0
539 let add dri =
540 funcs := dri :: !funcs
543 let display () =
544 GlClear.clear [`color];
545 List.iter (fun (display, _, _) -> display ()) !funcs;
546 Glut.swapBuffers ()
549 let reshape ~w ~h =
550 ww := w;
551 wh := h;
552 List.iter (fun (_, reshape, _) -> reshape w h) !funcs;
553 GlClear.clear [`color];
554 GlMat.mode `modelview;
555 GlMat.load_identity ();
556 GlMat.mode `projection;
557 GlMat.load_identity ();
558 GlMat.rotate ~y:1.0 ~angle:180.0 ();
559 GlMat.translate ~x:~-.1.0 ~y:~-.1.0 ();
560 GlMat.scale ~x:2.0 ~y:2.0 ();
561 Glut.postRedisplay ()
564 let init () =
565 let () =
566 Glut.initDisplayMode ~double_buffer:true ();
567 Glut.initWindowSize V.w V.h
569 let winid = Glut.createWindow "APC" in
570 Glut.displayFunc display;
571 Glut.reshapeFunc reshape;
572 Glut.keyboardFunc keyboard;
573 GlDraw.color (1.0, 1.0, 0.0);
574 winid;
577 let inc () = List.iter (fun (_, _, inc) -> inc ()) !funcs
578 let update = Glut.postRedisplay
579 let func = Glut.idleFunc
580 let run = Glut.mainLoop
583 module Bar(T: sig val barw : int val bars : int end) = struct
584 let nbars = T.bars
585 let kload = ref zero_stat
586 let iload = ref zero_stat
587 let vw = ref 0
588 let vh = ref 0
589 let sw = float T.barw /. float !Args.w
590 let bw = ref 0
591 let m = 1
592 let nrcpuscale = 1.0 /. float NP.nprocs
593 let fw = 3 * Glut.bitmapWidth font (Char.code 'W')
594 let ksepsl, isepsl =
595 let base = GlList.gen_lists ~len:2 in
596 GlList.nth base ~pos:0,
597 GlList.nth base ~pos:1
600 let getlr = function
601 | `i -> 0.01, 0.49
602 | `k -> 0.51, 0.99
605 let seps ki =
606 let xl, xr = getlr ki in
607 let y = 18 in
608 let h = !vh - 15 - y in
609 let () = GlDraw.viewport m y !bw h in
610 let () =
611 GlMat.push ();
612 GlMat.load_identity ();
613 GlMat.rotate ~y:1.0 ~angle:180.0 ();
614 GlMat.translate ~x:~-.1.0 ~y:~-.1.0 ();
615 GlMat.scale ~x:2.0 ~y:(2.0 /. float h) ()
617 let barm = 1 in
618 let mspace = barm * nbars in
619 let barh = (h + 66 - mspace / 2) / nbars |> float in
620 let barm = float barm in
621 let rec loop i yb =
622 if i = T.bars
623 then ()
624 else
625 let yt = yb +. barm in
626 let yn = yt +. barh in
627 GlDraw.vertex2 (xl, yb);
628 GlDraw.vertex2 (xl, yt);
629 GlDraw.vertex2 (xr, yt);
630 GlDraw.vertex2 (xr, yb);
631 succ i |> loop |< yn
633 GlDraw.color (0.0, 0.0, 0.0);
634 GlDraw.begins `quads;
635 loop 0 barh;
636 GlDraw.ends ();
637 GlMat.pop ();
640 let reshape w h =
641 vw := w;
642 vh := h;
643 bw :=
644 if !Args.scalebar
645 then
646 (float w *. sw |> truncate) - m
647 else
648 T.barw - m
651 GlList.begins ksepsl `compile;
652 seps `k;
653 GlList.ends ();
655 GlList.begins isepsl `compile;
656 seps `i;
657 GlList.ends ();
660 let drawseps = function
661 | `k -> GlList.call ksepsl
662 | `i -> GlList.call isepsl
665 let display () =
666 let kload = scale_stat !kload nrcpuscale in
667 let iload = scale_stat !iload nrcpuscale in
668 let kload_all = min (1.0 -. kload.all) 1.0 |> max 0.0 in
669 let iload_all = min (1.0 -. iload.all) 1.0 |> max 0.0 in
670 let () = GlDraw.viewport m 0 !bw 15 in
671 let () =
672 GlDraw.color (1.0, 1.0, 1.0);
673 let kload_all = 100.0 *. kload_all in
674 let iload_all = 100.0 *. iload_all in
675 let () =
676 GlMat.push ();
677 GlMat.load_identity ();
678 GlMat.scale ~x:(1.0/.float !bw) ~y:(1.0/.30.0) ()
680 let ix = !bw / 2 - fw |> float in
681 let kx = - (fw + !bw / 2) |> float in
682 let () = sprintf "%5.2f" iload_all |> draw_string ix 0.0 in
683 let () = sprintf "%5.2f" kload_all |> draw_string kx 0.0 in
684 let () = GlMat.pop () in ()
687 let y = 18 in
688 let h = !vh - 15 - y in
689 let () = GlDraw.viewport m y !bw h in
690 let () =
691 GlMat.push ();
692 GlMat.load_identity ();
693 GlMat.rotate ~y:1.0 ~angle:180.0 ();
694 GlMat.translate ~x:~-.1.0 ~y:~-.1.0 ();
695 GlMat.scale ~x:2.0 ~y:(2.0 /. float h) ()
697 let aux ki cl =
698 let xl, xr = getlr ki in
699 let drawquad yb yt =
700 GlDraw.begins `quads;
701 GlDraw.vertex2 (xl, yb);
702 GlDraw.vertex2 (xl, yt);
703 GlDraw.vertex2 (xr, yt);
704 GlDraw.vertex2 (xr, yb);
705 GlDraw.ends ()
707 let fold yb (color, load) =
708 if load > 0.0
709 then
710 let () = GlDraw.color color in
711 let yt = yb +. float h *. load in
712 let () = drawquad yb yt in
714 else
717 let yb = List.fold_left fold 0.0 cl in
718 let () = GlDraw.color (0.5, 0.5, 0.5) in
719 let yt = float h in
720 let () = drawquad yb yt in
721 let () = drawseps ki in
724 let () =
725 if !Args.sepstat
726 then
727 aux `k
728 [ (1.0, 1.0, 0.0), kload.user
729 ; (0.0, 0.0, 1.0), kload.nice
730 ; (1.0, 0.0, 0.0), kload.sys
731 ; (1.0, 1.0, 1.0), kload.intr
732 ; (0.75, 0.5, 0.5), (1.0 -. kload.iowait) -. kload.all
734 else
735 aux `k [ (1.0, 0.0, 0.0), 1.0 -. kload.idle ]
737 let () = aux `i [ (1.0, 1.0, 0.0), 1.0 -. iload.all ] in
738 GlMat.pop ();
741 let update delta' kload' iload' =
742 let delta = 1.0 /. delta' in
743 kload := scale_stat kload' delta;
744 iload := scale_stat iload' delta;
748 module Graph (V: View) = struct
749 let ox = if !Args.scalebar then 0 else !Args.barw
750 let sw = float V.w /. float (!Args.w - ox)
751 let sh = float V.h /. float !Args.h
752 let sx = float (V.x - ox) /. float V.w
753 let sy = float V.y /. float V.h
754 let vw = ref 0
755 let vh = ref 0
756 let vx = ref 0
757 let vy = ref 0
758 let scale = V.freq /. V.interval
759 let gscale = 1.0 /. float V.sgrid
760 let nsamples = ref 0
762 let fw, fh =
763 if !Args.labels
764 then 3 * Glut.bitmapWidth font (Char.code '%'), 20
765 else 0, 10
767 let gridlist =
768 let base = GlList.gen_lists ~len:1 in
769 GlList.nth base ~pos:0
771 let viewport typ =
772 let ox = if !Args.scalebar then 0 else !Args.barw in
773 let x, y, w, h =
774 match typ with
775 | `labels -> (!vx + ox, !vy + 5, fw, !vh - fh)
776 | `graph -> (!vx + fw + 5 + ox, !vy + 5, !vw - fw - 10, !vh - fh)
778 GlDraw.viewport x y w h;
781 let sgrid () =
782 for i = 0 to V.sgrid
784 let x = if i = 0 then 0.0009 else float i *. gscale in
785 GlDraw.vertex ~x ~y:0.0 ();
786 GlDraw.vertex ~x ~y:1.0 ();
787 done;
790 let grid () =
791 viewport `graph;
792 GlDraw.line_width 1.0;
793 GlDraw.color (0.0, 1.0, 0.0);
794 GlDraw.begins `lines;
795 if !Args.mgrid
796 then
797 begin
798 GlDraw.vertex2 (0.0009, 0.0);
799 GlDraw.vertex2 (0.0009, 1.0);
800 GlDraw.vertex2 (1.0000, 0.0);
801 GlDraw.vertex2 (1.0000, 1.0);
803 else
804 sgrid ()
806 let () =
807 let lim = 100 / V.pgrid in
808 for i = 0 to lim
810 let y = (i * V.pgrid |> float) /. 100.0 in
811 let y = if i = lim then y -. 0.0009 else y in
812 GlDraw.vertex ~x:0.0 ~y ();
813 GlDraw.vertex ~x:1.0 ~y ();
814 done;
816 let () = GlDraw.ends () in
817 if !Args.labels
818 then
819 begin
820 viewport `labels;
821 GlDraw.color (1.0, 1.0, 1.0);
822 let ohp = 100.0 in
823 for i = 0 to 100 / V.pgrid
825 let p = i * V.pgrid in
826 let y = float p /. ohp in
827 let s = Printf.sprintf "%3d%%" p in
828 draw_string 1.0 y s
829 done
833 let reshape w h =
834 let wxsw = float (w - ox) *. sw
835 and hxsh = float h *. sh in
836 vw := wxsw |> truncate;
837 vh := hxsh |> truncate;
838 vx := wxsw *. sx |> truncate;
839 vy := hxsh *. sy |> truncate;
840 GlList.begins gridlist `compile;
841 grid ();
842 GlList.ends ();
845 let swap =
846 Glut.swapBuffers |> oohz !Args.delay;
849 let inc () = incr nsamples
851 let mgrid () =
852 GlDraw.line_width 1.0;
853 GlDraw.color (0.0, 1.0, 0.0);
854 GlDraw.begins `lines;
855 let offset =
856 ((pred !nsamples |> float) *. scale /. gscale |> modf |> fst) *. gscale
858 for i = 0 to pred V.sgrid
860 let x = offset +. float i *. gscale in
861 GlDraw.vertex ~x ~y:0.0 ();
862 GlDraw.vertex ~x ~y:1.0 ();
863 done;
864 GlDraw.ends ();
867 let display () =
868 GlList.call gridlist;
869 viewport `graph;
870 if !Args.mgrid then mgrid ();
871 GlDraw.line_width 1.5;
873 let sample sampler =
874 GlDraw.color sampler.color;
875 let () =
876 if not !Args.poly
877 then GlDraw.begins `line_strip
878 else
879 begin
880 GlDraw.begins `polygon;
881 GlDraw.vertex2 (0.0, 0.0);
884 let yield = sampler.getyielder () in
885 let rec loop last i =
886 match yield () with
887 | Some y as opty ->
888 let x = float i *. scale in
889 GlDraw.vertex ~x ~y ();
890 loop opty (succ i)
891 | None ->
892 if !Args.poly
893 then
894 match last with
895 | None -> ()
896 | Some y ->
897 let x = float (pred i) *. scale in
898 GlDraw.vertex ~x ~y:0.0 ()
900 loop None 0;
901 GlDraw.ends ();
903 List.iter sample V.samplers;
906 let funcs = display, reshape, inc
909 let getplacements w h n barw =
910 let sr = float n |> sqrt |> ceil |> truncate in
911 let d = n / sr in
912 let r = if n mod sr = 0 then 0 else 1 in
913 let x, y =
914 if w - barw > h
915 then
916 sr + r, d
917 else
918 d, sr + r
920 let w' = w - barw in
921 let h' = h in
922 let vw = w' / x in
923 let vh = h' / y in
924 let rec loop accu i =
925 if i = n
926 then accu
927 else
928 let yc = i / x in
929 let xc = i mod x in
930 let xc = xc * vw + barw in
931 let yc = yc * vh in
932 (i, xc, yc) :: accu |> loop |< succ i
934 loop [] 0, vw, vh
937 let create fd w h =
938 let module S =
939 struct
940 let freq = !Args.freq
941 let nsamples = !Args.interval /. freq |> ceil |> truncate
944 let placements, vw, vh = getplacements w h NP.nprocs !Args.barw in
946 let iget () = NP.idletimeofday fd NP.nprocs in
947 let is = iget () in
949 let kget () =
950 let gks = NP.parse_stat () in
951 gks () |> Array.of_list
953 let ks = kget () in
955 let crgraph (kaccu, iaccu, gaccu) (i, x, y) =
956 let module Si = Sampler (S) in
957 let isampler =
958 { getyielder = Si.getyielder
959 ; color = (1.0, 1.0, 0.0)
960 ; update = Si.update
963 let (kcalc, ksampler) =
964 let module Sc = Sampler (S) in
965 let sampler =
966 { getyielder = Sc.getyielder
967 ; color = (1.0, 0.0, 0.0)
968 ; update = Sc.update
971 let calc =
972 if !Args.gzh
973 then
974 let d = ref 0.0 in
975 let f d' = d := d' in
976 let () = Gzh.gen f in
977 fun _ _ _ ->
978 { zero_stat with all = !d }
979 else
980 if !Args.uptime
981 then
982 let (u1, i1) = NP.parse_uptime () in
983 let u1 = ref u1
984 and i1 = ref i1 in
985 fun _ _ _ ->
986 let (u2, i2) = NP.parse_uptime () in
987 let du = u2 -. !u1
988 and di = i2 -. !i1 in
989 u1 := u2;
990 i1 := i2;
991 { zero_stat with all = di /. du }
992 else
993 let i' = if i = NP.nprocs then 0 else succ i in
994 let g ks n = Array.get ks i' |> snd |> Array.get |< n in
995 let gall ks =
996 let user = g ks NP.user
997 and nice = g ks NP.nice
998 and sys = g ks NP.sys
999 and idle = g ks NP.idle
1000 and iowait = g ks NP.idle
1001 and intr = g ks NP.intr
1002 and softirq = g ks NP.softirq in
1003 let () =
1005 !Args.debug
1006 then
1007 Format.eprintf
1008 "user=%f nice=%f sys=%f iowait=%f intr=%f softirq=%f@."
1009 user
1010 nice
1012 iowait
1013 intr
1014 softirq
1017 { all = idle
1018 ; user = user
1019 ; nice = nice
1020 ; sys = sys
1021 ; idle = idle
1022 ; iowait = iowait
1023 ; intr = intr
1024 ; softirq = softirq
1027 let i1 = ref (gall ks) in
1028 fun ks t1 t2 ->
1029 let i2 = gall ks in
1030 let diff = add_stat i2 (neg_stat !i1) in
1031 i1 := i2;
1032 diff
1034 calc, sampler
1036 let module V =
1037 struct
1038 let x = x
1039 let y = y
1040 let w = vw
1041 let h = vh
1042 let freq = S.freq
1043 let interval = !Args.interval
1044 let pgrid = !Args.pgrid
1045 let sgrid = !Args.sgrid
1046 let samplers =
1047 if !Args.ksampler
1048 then [isampler; ksampler]
1049 else [isampler]
1052 let module Graph = Graph (V) in
1053 let icalc =
1054 let i1 = Array.get is i |> ref in
1055 fun is t1 t2 ->
1056 let i2 = Array.get is i in
1057 if classify_float i2 = FP_infinite
1058 then
1059 { zero_stat with all = t2 -. t1 }
1060 else
1061 let i1' = !i1 in
1062 i1 := i2;
1063 { zero_stat with all = i2 -. i1' }
1065 let kaccu =
1066 if !Args.ksampler
1067 then (i, kcalc, ksampler) :: kaccu
1068 else kaccu
1070 kaccu, (i, icalc, isampler) :: iaccu, Graph.funcs :: gaccu
1072 let kl, il, gl = List.fold_left crgraph ([], [], []) placements in
1073 ((if kl == [] then (fun () -> [||]) else kget), kl), (iget, il), gl
1076 let opendev path =
1077 if NP.winnt
1078 then
1079 Unix.stdout
1080 else
1082 Unix.openfile path [Unix.O_RDONLY] 0
1083 with
1084 | Unix.Unix_error (Unix.ENODEV, s1, s2) ->
1085 eprintf "Could not open ITC device %S:\n%s(%s): %s)\n"
1086 path s1 s2 |< Unix.error_message Unix.ENODEV;
1087 eprintf "(perhaps the module is not loaded?)@.";
1088 exit 100
1090 | Unix.Unix_error (Unix.ENOENT, s1, s2) ->
1091 eprintf "Could not open ITC device %S:\n%s(%s): %s\n"
1092 path s1 s2 |< Unix.error_message Unix.ENOENT;
1093 exit 100
1095 | Unix.Unix_error (error, s1, s2) ->
1096 eprintf "Could not open ITC device %S:\n%s(%s): %s\n"
1097 path s1 s2 |< Unix.error_message error;
1098 eprintf "(perhaps modules is already in use?)@.";
1099 exit 100
1101 | exn ->
1102 eprintf "Could not open ITC device %S:\n%s\n"
1103 path |< Printexc.to_string exn;
1104 exit 100
1107 let seticon () =
1108 let module X = struct external seticon : string -> unit = "ml_seticon" end in
1109 let len = 32*4 in
1110 let data = String.create |< 32*len + 2*4 in
1111 let line r g b a =
1112 let r = Char.chr r
1113 and g = Char.chr g
1114 and b = Char.chr b
1115 and a = Char.chr a in
1116 let s = String.create len in
1117 let rec fill x =
1118 if x = len
1119 then s
1120 else
1121 begin
1122 x + 0 |> String.set s |< b;
1123 x + 1 |> String.set s |< g;
1124 x + 2 |> String.set s |< r;
1125 x + 3 |> String.set s |< a;
1126 x + 4 |> fill
1129 fill 0
1131 let el = line 0x00 0x00 0x00 0xff
1132 and kl = line 0xff 0x00 0x00 0xff
1133 and il = line 0xff 0xff 0x00 0xff in
1134 let fill l sy ey =
1135 let src = l and dst = data and src_pos = 0 in
1136 let rec loop n dst_pos =
1137 if n > 0
1138 then
1139 begin
1140 StringLabels.blit ~src ~src_pos ~dst ~dst_pos ~len;
1141 pred n |> loop |< dst_pos + len
1144 (ey - sy) |> loop |< (32 - ey) * len + 4*2
1146 fun ~iload ~kload ->
1147 let iy = iload *. 32.0 |> ceil |> truncate |> max 0 |> min 32
1148 and ky = kload *. 32.0 |> ceil |> truncate |> max 0 |> min 32 in
1149 let ey =
1150 if ky < iy
1151 then (fill kl 0 ky; fill il ky iy; iy)
1152 else (fill kl 0 ky; ky)
1154 fill el ey 32;
1155 X.seticon data;
1158 let main () =
1159 let _ = Glut.init [|""|] in
1160 (* let () = Gl.enable `line_smooth in *)
1161 let () = Args.init () in
1162 let () =
1163 if !Args.verbose
1164 then
1165 "detected " ^ string_of_int NP.nprocs ^ " CPUs" |> print_endline
1167 let () = if !Args.gzh then Gzh.init !Args.verbose in
1168 let () = Delay.init !Args.timer !Args.gzh in
1169 let () = if !Args.niceval != 0 then NP.setnice !Args.niceval in
1170 let w = !Args.w
1171 and h = !Args.h in
1172 let fd = opendev !Args.devpath in
1173 let module FullV = View (struct let w = w let h = h end) in
1174 let _winid = FullV.init () in
1175 let (kget, kfuncs), (iget, ifuncs), gl = create fd w h in
1176 let bar_update =
1177 List.iter FullV.add gl;
1178 if !Args.barw > 0
1179 then
1180 let module Bar =
1181 Bar (struct let barw = !Args.barw let bars = !Args.bars end)
1183 FullV.add (Bar.display, Bar.reshape, fun _ -> ());
1184 Bar.update
1185 else
1186 fun _ _ _ -> ()
1188 let seticon = if !Args.icon then seticon () else fun ~iload ~kload -> () in
1189 let rec loop t1 () =
1190 let t2 = Unix.gettimeofday () in
1191 let dt = t2 -. t1 in
1192 if dt >= !Args.freq
1193 then
1194 let is = iget () in
1195 let ks = kget () in
1196 let rec loop2 load sample = function
1197 | [] -> load
1198 | (nr, calc, sampler) :: rest ->
1199 let cpuload = calc sample t1 t2 in
1200 let thisload = 1.0 -. (cpuload.all /. dt) in
1201 let thisload = max 0.0 thisload in
1202 let () =
1203 if !Args.verbose
1204 then
1205 ("cpu load(" ^ string_of_int nr ^ "): "
1206 ^ (thisload *. 100.0 |> string_of_float)
1207 |> print_endline)
1209 let load = add_stat load cpuload in
1210 sampler.update t1 t2 0.0 load.all;
1211 loop2 load sample rest
1213 let iload = loop2 zero_stat is ifuncs in
1214 let kload = loop2 zero_stat ks kfuncs in
1215 if !Args.debug
1216 then
1217 begin
1218 iload.all |> string_of_float |> prerr_endline;
1219 kload.all |> string_of_float |> prerr_endline;
1222 seticon ~iload:iload.all ~kload:kload.all;
1223 bar_update dt kload iload;
1224 FullV.inc ();
1225 FullV.update ();
1226 FullV.func (Some (loop t2))
1227 else
1228 Delay.delay ()
1230 FullV.func (Some (Unix.gettimeofday () |> loop));
1231 FullV.run ()
1234 let _ =
1235 try main ()
1236 with
1237 | Unix.Unix_error (e, s1, s2) ->
1238 eprintf "%s(%s): %s@." s1 s2 |< Unix.error_message e
1240 | exn ->
1241 Printexc.to_string exn |> eprintf "Exception: %s@."