v0.98b
[apc.git] / apc.ml
blob11257da2a14cf5ee5774ba23d78379971e35b549
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.98b"
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),
733 let sum = kload.user +. kload.nice +. kload.sys
734 +. kload.intr +. kload.softirq
736 (1.0 -. kload.iowait) -. sum
738 else
739 aux `k [ (1.0, 0.0, 0.0), 1.0 -. kload.idle ]
741 let () = aux `i [ (1.0, 1.0, 0.0), 1.0 -. iload.all ] in
742 GlMat.pop ();
745 let update delta' kload' iload' =
746 let delta = 1.0 /. delta' in
747 kload := scale_stat kload' delta;
748 iload := scale_stat iload' delta;
752 module Graph (V: View) = struct
753 let ox = if !Args.scalebar then 0 else !Args.barw
754 let sw = float V.w /. float (!Args.w - ox)
755 let sh = float V.h /. float !Args.h
756 let sx = float (V.x - ox) /. float V.w
757 let sy = float V.y /. float V.h
758 let vw = ref 0
759 let vh = ref 0
760 let vx = ref 0
761 let vy = ref 0
762 let scale = V.freq /. V.interval
763 let gscale = 1.0 /. float V.sgrid
764 let nsamples = ref 0
766 let fw, fh =
767 if !Args.labels
768 then 3 * Glut.bitmapWidth font (Char.code '%'), 20
769 else 0, 10
771 let gridlist =
772 let base = GlList.gen_lists ~len:1 in
773 GlList.nth base ~pos:0
775 let viewport typ =
776 let ox = if !Args.scalebar then 0 else !Args.barw in
777 let x, y, w, h =
778 match typ with
779 | `labels -> (!vx + ox, !vy + 5, fw, !vh - fh)
780 | `graph -> (!vx + fw + 5 + ox, !vy + 5, !vw - fw - 10, !vh - fh)
782 GlDraw.viewport x y w h;
785 let sgrid () =
786 for i = 0 to V.sgrid
788 let x = if i = 0 then 0.0009 else float i *. gscale in
789 GlDraw.vertex ~x ~y:0.0 ();
790 GlDraw.vertex ~x ~y:1.0 ();
791 done;
794 let grid () =
795 viewport `graph;
796 GlDraw.line_width 1.0;
797 GlDraw.color (0.0, 1.0, 0.0);
798 GlDraw.begins `lines;
799 if !Args.mgrid
800 then
801 begin
802 GlDraw.vertex2 (0.0009, 0.0);
803 GlDraw.vertex2 (0.0009, 1.0);
804 GlDraw.vertex2 (1.0000, 0.0);
805 GlDraw.vertex2 (1.0000, 1.0);
807 else
808 sgrid ()
810 let () =
811 let lim = 100 / V.pgrid in
812 for i = 0 to lim
814 let y = (i * V.pgrid |> float) /. 100.0 in
815 let y = if i = lim then y -. 0.0009 else y in
816 GlDraw.vertex ~x:0.0 ~y ();
817 GlDraw.vertex ~x:1.0 ~y ();
818 done;
820 let () = GlDraw.ends () in
821 if !Args.labels
822 then
823 begin
824 viewport `labels;
825 GlDraw.color (1.0, 1.0, 1.0);
826 let ohp = 100.0 in
827 for i = 0 to 100 / V.pgrid
829 let p = i * V.pgrid in
830 let y = float p /. ohp in
831 let s = Printf.sprintf "%3d%%" p in
832 draw_string 1.0 y s
833 done
837 let reshape w h =
838 let wxsw = float (w - ox) *. sw
839 and hxsh = float h *. sh in
840 vw := wxsw |> truncate;
841 vh := hxsh |> truncate;
842 vx := wxsw *. sx |> truncate;
843 vy := hxsh *. sy |> truncate;
844 GlList.begins gridlist `compile;
845 grid ();
846 GlList.ends ();
849 let swap =
850 Glut.swapBuffers |> oohz !Args.delay;
853 let inc () = incr nsamples
855 let mgrid () =
856 GlDraw.line_width 1.0;
857 GlDraw.color (0.0, 1.0, 0.0);
858 GlDraw.begins `lines;
859 let offset =
860 ((pred !nsamples |> float) *. scale /. gscale |> modf |> fst) *. gscale
862 for i = 0 to pred V.sgrid
864 let x = offset +. float i *. gscale in
865 GlDraw.vertex ~x ~y:0.0 ();
866 GlDraw.vertex ~x ~y:1.0 ();
867 done;
868 GlDraw.ends ();
871 let display () =
872 GlList.call gridlist;
873 viewport `graph;
874 if !Args.mgrid then mgrid ();
875 GlDraw.line_width 1.5;
877 let sample sampler =
878 GlDraw.color sampler.color;
879 let () =
880 if not !Args.poly
881 then GlDraw.begins `line_strip
882 else
883 begin
884 GlDraw.begins `polygon;
885 GlDraw.vertex2 (0.0, 0.0);
888 let yield = sampler.getyielder () in
889 let rec loop last i =
890 match yield () with
891 | Some y as opty ->
892 let x = float i *. scale in
893 GlDraw.vertex ~x ~y ();
894 loop opty (succ i)
895 | None ->
896 if !Args.poly
897 then
898 match last with
899 | None -> ()
900 | Some y ->
901 let x = float (pred i) *. scale in
902 GlDraw.vertex ~x ~y:0.0 ()
904 loop None 0;
905 GlDraw.ends ();
907 List.iter sample V.samplers;
910 let funcs = display, reshape, inc
913 let getplacements w h n barw =
914 let sr = float n |> sqrt |> ceil |> truncate in
915 let d = n / sr in
916 let r = if n mod sr = 0 then 0 else 1 in
917 let x, y =
918 if w - barw > h
919 then
920 sr + r, d
921 else
922 d, sr + r
924 let w' = w - barw in
925 let h' = h in
926 let vw = w' / x in
927 let vh = h' / y in
928 let rec loop accu i =
929 if i = n
930 then accu
931 else
932 let yc = i / x in
933 let xc = i mod x in
934 let xc = xc * vw + barw in
935 let yc = yc * vh in
936 (i, xc, yc) :: accu |> loop |< succ i
938 loop [] 0, vw, vh
941 let create fd w h =
942 let module S =
943 struct
944 let freq = !Args.freq
945 let nsamples = !Args.interval /. freq |> ceil |> truncate
948 let placements, vw, vh = getplacements w h NP.nprocs !Args.barw in
950 let iget () = NP.idletimeofday fd NP.nprocs in
951 let is = iget () in
953 let kget () =
954 let gks = NP.parse_stat () in
955 gks () |> Array.of_list
957 let ks = kget () in
959 let crgraph (kaccu, iaccu, gaccu) (i, x, y) =
960 let module Si = Sampler (S) in
961 let isampler =
962 { getyielder = Si.getyielder
963 ; color = (1.0, 1.0, 0.0)
964 ; update = Si.update
967 let (kcalc, ksampler) =
968 let module Sc = Sampler (S) in
969 let sampler =
970 { getyielder = Sc.getyielder
971 ; color = (1.0, 0.0, 0.0)
972 ; update = Sc.update
975 let calc =
976 if !Args.gzh
977 then
978 let d = ref 0.0 in
979 let f d' = d := d' in
980 let () = Gzh.gen f in
981 fun _ _ _ ->
982 { zero_stat with all = !d }
983 else
984 if !Args.uptime
985 then
986 let (u1, i1) = NP.parse_uptime () in
987 let u1 = ref u1
988 and i1 = ref i1 in
989 fun _ _ _ ->
990 let (u2, i2) = NP.parse_uptime () in
991 let du = u2 -. !u1
992 and di = i2 -. !i1 in
993 u1 := u2;
994 i1 := i2;
995 { zero_stat with all = di /. du }
996 else
997 let i' = if i = NP.nprocs then 0 else succ i in
998 let g ks n = Array.get ks i' |> snd |> Array.get |< n in
999 let gall ks =
1000 let user = g ks NP.user
1001 and nice = g ks NP.nice
1002 and sys = g ks NP.sys
1003 and idle = g ks NP.idle
1004 and iowait = g ks NP.idle
1005 and intr = g ks NP.intr
1006 and softirq = g ks NP.softirq in
1007 let () =
1009 !Args.debug
1010 then
1011 Format.eprintf
1012 "user=%f nice=%f sys=%f iowait=%f intr=%f softirq=%f@."
1013 user
1014 nice
1016 iowait
1017 intr
1018 softirq
1021 { all = idle
1022 ; user = user
1023 ; nice = nice
1024 ; sys = sys
1025 ; idle = idle
1026 ; iowait = iowait
1027 ; intr = intr
1028 ; softirq = softirq
1031 let i1 = ref (gall ks) in
1032 fun ks t1 t2 ->
1033 let i2 = gall ks in
1034 let diff = add_stat i2 (neg_stat !i1) in
1035 i1 := i2;
1036 diff
1038 calc, sampler
1040 let module V =
1041 struct
1042 let x = x
1043 let y = y
1044 let w = vw
1045 let h = vh
1046 let freq = S.freq
1047 let interval = !Args.interval
1048 let pgrid = !Args.pgrid
1049 let sgrid = !Args.sgrid
1050 let samplers =
1051 if !Args.ksampler
1052 then [isampler; ksampler]
1053 else [isampler]
1056 let module Graph = Graph (V) in
1057 let icalc =
1058 let i1 = Array.get is i |> ref in
1059 fun is t1 t2 ->
1060 let i2 = Array.get is i in
1061 if classify_float i2 = FP_infinite
1062 then
1063 { zero_stat with all = t2 -. t1 }
1064 else
1065 let i1' = !i1 in
1066 i1 := i2;
1067 { zero_stat with all = i2 -. i1' }
1069 let kaccu =
1070 if !Args.ksampler
1071 then (i, kcalc, ksampler) :: kaccu
1072 else kaccu
1074 kaccu, (i, icalc, isampler) :: iaccu, Graph.funcs :: gaccu
1076 let kl, il, gl = List.fold_left crgraph ([], [], []) placements in
1077 ((if kl == [] then (fun () -> [||]) else kget), kl), (iget, il), gl
1080 let opendev path =
1081 if NP.winnt
1082 then
1083 Unix.stdout
1084 else
1086 Unix.openfile path [Unix.O_RDONLY] 0
1087 with
1088 | Unix.Unix_error (Unix.ENODEV, s1, s2) ->
1089 eprintf "Could not open ITC device %S:\n%s(%s): %s)\n"
1090 path s1 s2 |< Unix.error_message Unix.ENODEV;
1091 eprintf "(perhaps the module is not loaded?)@.";
1092 exit 100
1094 | Unix.Unix_error (Unix.ENOENT, s1, s2) ->
1095 eprintf "Could not open ITC device %S:\n%s(%s): %s\n"
1096 path s1 s2 |< Unix.error_message Unix.ENOENT;
1097 exit 100
1099 | Unix.Unix_error (Unix.EALREADY, s1, s2) ->
1100 eprintf "Could not open ITC device %S:\n%s(%s): %s\n"
1101 path s1 s2 |< Unix.error_message Unix.EALREADY;
1102 eprintf "(perhaps modules is already in use?)@.";
1103 exit 100
1105 | Unix.Unix_error (error, s1, s2) ->
1106 eprintf "Could not open ITC device %S:\n%s(%s): %s\n"
1107 path s1 s2 |< Unix.error_message error;
1108 exit 100
1110 | exn ->
1111 eprintf "Could not open ITC device %S:\n%s\n"
1112 path |< Printexc.to_string exn;
1113 exit 100
1116 let seticon () =
1117 let module X = struct external seticon : string -> unit = "ml_seticon" end in
1118 let len = 32*4 in
1119 let data = String.create |< 32*len + 2*4 in
1120 let line r g b a =
1121 let r = Char.chr r
1122 and g = Char.chr g
1123 and b = Char.chr b
1124 and a = Char.chr a in
1125 let s = String.create len in
1126 let rec fill x =
1127 if x = len
1128 then s
1129 else
1130 begin
1131 x + 0 |> String.set s |< b;
1132 x + 1 |> String.set s |< g;
1133 x + 2 |> String.set s |< r;
1134 x + 3 |> String.set s |< a;
1135 x + 4 |> fill
1138 fill 0
1140 let el = line 0x00 0x00 0x00 0xff
1141 and kl = line 0xff 0x00 0x00 0xff
1142 and il = line 0xff 0xff 0x00 0xff in
1143 let fill l sy ey =
1144 let src = l and dst = data and src_pos = 0 in
1145 let rec loop n dst_pos =
1146 if n > 0
1147 then
1148 begin
1149 StringLabels.blit ~src ~src_pos ~dst ~dst_pos ~len;
1150 pred n |> loop |< dst_pos + len
1153 (ey - sy) |> loop |< (32 - ey) * len + 4*2
1155 fun ~iload ~kload ->
1156 let iy = iload *. 32.0 |> ceil |> truncate |> max 0 |> min 32
1157 and ky = kload *. 32.0 |> ceil |> truncate |> max 0 |> min 32 in
1158 let ey =
1159 if ky < iy
1160 then (fill kl 0 ky; fill il ky iy; iy)
1161 else (fill kl 0 ky; ky)
1163 fill el ey 32;
1164 X.seticon data;
1167 let main () =
1168 let _ = Glut.init [|""|] in
1169 let () = Args.init () in
1170 let () =
1171 if !Args.verbose
1172 then
1173 "detected " ^ string_of_int NP.nprocs ^ " CPUs" |> print_endline
1175 let () = if !Args.gzh then Gzh.init !Args.verbose in
1176 let () = Delay.init !Args.timer !Args.gzh in
1177 let () = if !Args.niceval != 0 then NP.setnice !Args.niceval in
1178 let w = !Args.w
1179 and h = !Args.h in
1180 let fd = opendev !Args.devpath in
1181 let module FullV = View (struct let w = w let h = h end) in
1182 let _winid = FullV.init () in
1183 let (kget, kfuncs), (iget, ifuncs), gl = create fd w h in
1184 let bar_update =
1185 List.iter FullV.add gl;
1186 if !Args.barw > 0
1187 then
1188 let module Bar =
1189 Bar (struct let barw = !Args.barw let bars = !Args.bars end)
1191 FullV.add (Bar.display, Bar.reshape, fun _ -> ());
1192 Bar.update
1193 else
1194 fun _ _ _ -> ()
1196 let seticon = if !Args.icon then seticon () else fun ~iload ~kload -> () in
1197 let rec loop t1 () =
1198 let t2 = Unix.gettimeofday () in
1199 let dt = t2 -. t1 in
1200 if dt >= !Args.freq
1201 then
1202 let is = iget () in
1203 let ks = kget () in
1204 let rec loop2 load sample = function
1205 | [] -> load
1206 | (nr, calc, sampler) :: rest ->
1207 let cpuload = calc sample t1 t2 in
1208 let thisload = 1.0 -. (cpuload.all /. dt) in
1209 let thisload = max 0.0 thisload in
1210 let () =
1211 if !Args.verbose
1212 then
1213 ("cpu load(" ^ string_of_int nr ^ "): "
1214 ^ (thisload *. 100.0 |> string_of_float)
1215 |> print_endline)
1217 let load = add_stat load cpuload in
1218 sampler.update t1 t2 0.0 cpuload.all;
1219 loop2 load sample rest
1221 let iload = loop2 zero_stat is ifuncs in
1222 let kload = loop2 zero_stat ks kfuncs in
1223 if !Args.debug
1224 then
1225 begin
1226 iload.all |> string_of_float |> prerr_endline;
1227 kload.all |> string_of_float |> prerr_endline;
1230 seticon ~iload:iload.all ~kload:kload.all;
1231 bar_update dt kload iload;
1232 FullV.inc ();
1233 FullV.update ();
1234 FullV.func (Some (loop t2))
1235 else
1236 Delay.delay ()
1238 FullV.func (Some (Unix.gettimeofday () |> loop));
1239 FullV.run ()
1242 let _ =
1243 try main ()
1244 with
1245 | Unix.Unix_error (e, s1, s2) ->
1246 eprintf "%s(%s): %s@." s1 s2 |< Unix.error_message e
1248 | exn ->
1249 Printexc.to_string exn |> eprintf "Exception: %s@."