Imported Upstream version 3.3.3
[debian/amanda] / amplot / amplot.awk
1 #
2 # Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 # Copyright (c) 1992-1998, 2000 University of Maryland at College Park
4 # Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
5 # All Rights Reserved.
6 #
7 # Permission to use, copy, modify, distribute, and sell this software and its
8 # documentation for any purpose is hereby granted without fee, provided that
9 # the above copyright notice appear in all copies and that both that
10 # copyright notice and this permission notice appear in supporting
11 # documentation, and that the name of U.M. not be used in advertising or
12 # publicity pertaining to distribution of the software without specific,
13 # written prior permission.  U.M. makes no representations about the
14 # suitability of this software for any purpose.  It is provided "as is"
15 # without express or implied warranty.
16 #
17 # U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #
24 # Author: Olafur Gudumundsson, ogud@tis.com
25 # formerly at:     Systems Design and Analysis Group
26 #                  Computer Science Department
27 #                  University of Maryland at College Park
28 #
29 # An awk program to parse the amdump file and output the information
30 # in a form at the gnuplot program amplot.g wants
31 #
32 #       Creation Date: April 1992
33 #       modified: Aug 1993
34 #       Modified for Amanda-2.2: Dec 1993
35 #       Modified for Amanda-2.2: Mar 1994 and May 1994 and June 1994
36 #       Enhanced: April 1995
37 #       Input: One amdump file 
38 #       Output: Number of files that get fed into gnuplot
39 #
40 BEGIN{
41 # The folowing parameters may have to be set to suit each site, both 
42 # parameters are expressed in HOUR's. 
43 # If your average amanda dump is more than 3 hours you should increase the
44 # value of maxtime, similary if your dumps are finishing in less than 2 hours
45 # you should decrease the value of maxtime.
46 # This is now setable from amplot's command line.
47 #       maxtime  = 4;                   # how long to plot graph for in hours
48
49 # Min host controls the reporting of hosts that take long in dumping
50 # This varible can be set explicity or as a fraction of maxtime
51 # If you are seeing too many hosts reported increase the value of this 
52 # constant
53 #
54         min_host = maxtime * 0.75;      # good rule of thumb
55 #       min_host = 2.5;                 # expicit cutoff value in hours
56
57 #
58 # DO NOT CHANGE ANYTHING BELOW THIS LINE
59 #
60         time_scale = 60;        # display in minutes DO NOT CHANGE
61         maxtime  *= time_scale; # convert to minutes
62         min_host *= time_scale *time_scale; # convert to seconds
63                                                 # dumping than this 
64         disk_raise = 120;       # scaling factors for Holding disk graph
65         tape_raise = 90;
66         dump_shift = 7.5;       # scaling factors for Dumpers idle graph
67         dump_raise = 0;
68         que_raise  = 300;       # scaling factors for the queue's
69         count_scale= 1.0/3.0;   # new scale 
70                                 # scaling factors for the x axis 
71         bandw_raise = 250;
72         bandw_scale = 30/300;   # default calculated below 
73
74         holding_disk = -1;      # uninitialized
75                 
76         cnt        = 0;         # default values for counters
77         din        = 0;         # number of dumps to holding disk
78         dout       = 0;         # number of dumps to tape 
79         tapeq      = 0;         # how many dumps in tape queue
80         tape_err   = 0;         # how many tape errors
81         tout       = 0;         # data written out to tape 
82         quit       = 0;         # normal end of run
83         plot_fmt   = "%7.2f %6.2f\n%7.2f %6.2f\n";  # format of files for gnuplot
84         plot_fmt1  = "%7.2f %6.2f\n";  # format of files for gnuplot
85 }
86         
87 {               # state machine for processing input lines lines
88         if( $1 == "driver:") {
89                 if($2=="result")            do_result();
90                 else if( $2=="state")       do_state();
91                 else if( $2=="interface-state") ;
92                 else if( $2=="hdisk-state") do_hdisk++;
93                 else if( $2=="flush" && $3=="size" ) {
94                         flush_size = $4;
95                 }
96                 else if( $2=="start" && $3=="time")       do_start();
97                 else if( $2=="send-cmd") { 
98                         if( $7=="FILE-DUMP"){
99                           file_dump++;
100                           dmpr_strt[$6]=$4;
101                           host[$6]=$10;
102                           disk[$6]=$12;
103                           level[$6]=$14;
104                         }
105                         else if( $7 == "FILE-WRITE") file_write++;
106                         else if( $7 == "START-TAPER") fil = $9;
107                 }
108                 else if( $2=="finished-cmd") cmd_fin++;
109                 else if( $2=="started")      forked++;
110                 else if( $2=="QUITTING")     do_quit();
111                 else if( $2=="find_diskspace:") ; #eat this line
112                 else if( $2=="assign_holdingdisk:") ; #eat this line
113                 else if( $2=="adjust_diskspace:") ; #eat this line
114                 else if( $2=="tape" && $3=="size") ; #eat this line
115                 else if( $2=="dump" && $3=="failed") ; #eat this line
116                 else if( $2=="taper" && $3=="failed") ; #eat this line
117                 else if( $2=="dumping" || $2 == "adding" || $2 == "holding-disks:") 
118                   dumping++; # eat this line
119                 else if( $2!="FINISHED" && $2 != "pid" && $2 != "taper-tryagain"&& $2!="startaflush:")
120                   print fil,"Unknown statement#",$0;
121         }
122         else if ( $1 == "planner:") {
123                 if( $2 == "SKIPPED" || $2 == "FAILED") {
124                         failed++;
125                         print fil, "INFO#", $0;
126                 }
127         }
128         else if( $1 == "GENERATING")        sched_start=NR;
129         else if( $1 == "ENDFLUSH")          sched_start=NR;
130         else if( $1 == "DELAYING")          do_moves();    # find estimated size
131         else if( $1 == "dumper:") {
132                 if($4 != "starting" && $2 != "pid" && $2 != "stream_client:" && $2 != "dgram_bind:") 
133                     print fil, "INFO#", $0;
134         }
135         else if( $1 == "taper:") {
136                 if($3 != "label" && $3 != "end" && $2 != "DONE" && $2 != "pid" && $2 != "slot" && $2 != "reader-side:" && $2 != "page" && $2 != "buffer" && $3 != "at" && $3 != "switching" && $2 != "slot:" && $2 != "status")
137                     print fil, "INFO#", $0;
138         }
139         else if( $1 == "FLUSH") {
140                 no_flush++;
141         }
142         else if( NF==1 && sched_start > 0 && NR-sched_start > 1) { # new style end of schedule
143                 no_disks = NR-sched_start-2; # lets hope there are no extra lines
144                 sched_start = 0;
145         }
146 }
147
148 function do_state(){            # state line is printed out after driver
149                                 # finishes pondering new actions
150                                 # it reports the state as seen be driver
151 # fields in the state line 
152 # $2 = "state"          # $3 = "time"           # $4 = time_val
153 # $5 = "free"           # $6 = "kps:"           # $7 =  free_kps
154 # $8 = "space:"         # $9 = space            # $10 = "taper:"
155 # $11 = "writing"/"idle"# $12 = "idle-dumpers:"
156 # $13 = #idle           # $14 = "qlen"          # $15 = "tapeq:"
157 # $16 = #waiting        # $17 = "runq:"         # $18 = #not started 
158 # $19 = "roomq"         # $20 = #roomq          # $21 = "wakeup:"
159 # $22 = #wakeup         # $23 = "driver-idle:"  # $23 = status
160
161         cnt++;                                  # number of event
162         time = $4/time_scale;
163         #Check overflow in driver ouput (big value instead of negative)
164         if($7>0 && $7 < 0x7fffffff)
165                 unused = (bandw - $7)*bandw_scale+bandw_raise;
166         else
167                 unused = bandw_raise;
168         if( unused != unused_old) 
169                 printf plot_fmt, time, unused_old, time,unused >>"bandw_free";
170         unused_old = unused;
171
172         if(holding_disk_old != $9) {
173                 disk_alloc_time[disk_a] = time;
174                 disk_alloc_space[disk_a] = holding_disk_old;
175                 disk_a++;
176                 disk_alloc_time[disk_a] = time;
177                 disk_alloc_space[disk_a] = $9;
178                 disk_a++;
179                 holding_disk_old = $9;
180         }
181
182         twait = tsize;
183         if(twait_old != twait) {
184                 twait_time[twait_a] = time;
185                 twait_wait[twait_a] = twait_old;
186                 twait_a++;
187                 twait_time[twait_a] = time;
188                 twait_wait[twait_a] = twait;
189                 twait_a++;
190                 twait_old = twait;
191         }
192
193         active = (dumpers-$13)*dump_shift+dump_raise;
194         if( active != active_old )
195                 printf plot_fmt, time, active_old, time, active >> "dump_idle";
196         active_old = active;
197
198 # tape on or off
199         if($11=="writing")state = tape_raise+10;
200         else              state = tape_raise;
201         if( state != state_old )
202                 printf plot_fmt, time, state_old, time, state >> "tape_idle";
203         state_old = state;
204
205         run = $18*count_scale+que_raise;
206         if( run != run_old )
207                 printf plot_fmt, time, run_old, time, run >> "run_queue";
208         run_old = run;
209
210         finish = written * count_scale+que_raise;
211         if( finish != finish_old )
212                 printf plot_fmt, time, finish_old, time, finish >> "finished";
213         finish_old = finish;
214
215         tapeQ = $16 * count_scale+que_raise;
216         if( tapeQ != tapeQ_old )
217                 printf plot_fmt, time, tapeQ_old, time, tapeQ >> "tape_queue";
218         tapeQ_old = tapeQ;
219
220 }
221
222 function do_start() {           # get configuration parameters
223         dumpers    = $6;        # how many 
224         day        = $14;
225         dump_shift = 75/dumpers; 
226         bandw      = $8;                
227         bandw_scale = (30/bandw);
228         unused_old = bandw_raise;
229         print 0, unused_old > "bandw_free";
230         if( sched_start >0 ) {
231                 no_disks = NR-sched_start-1; # backward compatability
232                 sched_start =0;
233                 print "do_start: no_disks", no_disks, $0;
234         }
235         no_disks += no_flush;
236         size        = $10/1024;        # size of holding disk in MB
237         holding_disk= $10 + flush_size;
238         init_holding_disk= $10 + flush_size;
239         holding_disk_old = $10;
240         disk_a = 0;
241         disk_alloc_time[disk_a] = 0;
242         disk_alloc_space[disk_a] = holding_disk_old;
243         disk_a++;
244         tsize = flush_size;
245         twait_old = tsize;
246         twait_a = 0;
247         twait_time[twait_a] = 0;
248         twait_wait[twait_a] = twait_old;
249         twait_a++;
250         if( NF==14) {           # original file was missing this
251                 policy="FIFO";
252                 alg   ="InOrder";
253         }
254         else if(NF>=18) {               # newer files have this format
255                 policy = $18;
256                 alg = $16;
257                 if( alg=="drain-ends") big = $20; 
258         }
259         
260         start = $4;     # this is the start time of the first dump 
261                         # taper idle to this point should not be included
262         run_old = no_disks*cont_scale+que_raise;
263         print 0, run_old                >"run_queue";
264         finish_old = tapeQ_old = que_raise;
265         print 0, finish_old             >"finished";    
266         print 0, tapeQ_old              >"tape_queue" ; 
267         state_old = tape_raise;
268         print 0, state_old              > "tape_idle";
269         active_old = dump_raise;
270         print 0,active_old              >"dump_idle";
271
272 }
273
274 function do_quit(){             # this is issued by driver at the end
275                                 # when it has nothing more to do
276         cnt++;
277         quit = 1;
278         tim  = $4 / time_scale;
279
280         disk_alloc_time[disk_a] = tim;
281         disk_alloc_space[disk_a] = holding_disk_old;
282         disk_a++;
283         max_space=disk_alloc_space[0];
284         for(a=0; a<disk_a; a++) {
285                 if(disk_alloc_space[a] > max_space) {
286                         max_space = disk_alloc_space[a];
287                 }
288         }
289
290         space_change = 0;
291         if(max_space > holding_disk) {
292                 space_change = max_space - holding_disk;
293                 holding_disk = max_space;
294         }
295
296         twait_time[twait_a] = tim;
297         twait_wait[twait_a] = twait_old;
298         twait_a++;
299         min_wait=twait_wait[0];
300         for(a=0; a<twait_a; a++) {
301                 if(twait_wait[a] < min_wait) {
302                         min_wait = twait_wait[a];
303                 }
304         }
305         if(min_wait < 0) {
306                 if(flush_size == 0) {
307                         holding_disk -= min_wait;
308                         holding_disk -= space_change;
309                 }
310                 for(a=0; a<twait_a; a++) {
311                         twait_wait[a] -= min_wait;
312                 }
313         }
314         if (holding_disk != 0) {
315                 const = 100/holding_disk;
316         }
317         else {
318                 const = 100;
319         }
320         for(a=0; a<disk_a; ++a) {
321                 space = (holding_disk - disk_alloc_space[a])*const+disk_raise
322                 printf plot_fmt1, disk_alloc_time[a], space >> "disk_alloc";
323         }
324         for(a=0; a<twait_a; ++a) {
325                 space = (twait_wait[a])*const+disk_raise
326                 printf plot_fmt1, twait_time[a], space >> "tape_wait";
327         }
328
329         printf plot_fmt, tim, active_old, tim, dump_raise >>"dump_idle";
330         printf plot_fmt, tim, state_old, tim, tape_raise >>"tape_idle"; 
331         printf plot_fmt, tim, unused_old, tim, bandw_raise >>"bandw_free";
332         printf plot_fmt, tim, finish_old, tim, written*count_scale+que_raise >>"finished";
333         printf plot_fmt, tim, run_old, tim, run_old >>"run_queue";
334 }
335
336 function do_result(){           # process lines driver: result
337         if($7=="DONE" ) {
338                 if( $6=="taper:"){              # taper done
339                         tsize -= $14;   
340                         tout  += $14;
341                         tcnt--; written++;
342                 }
343                 else {                          # dumperx done 
344                   tsize += (int($15/32)+1)*32;  # in tape blocks 
345                   tcnt++;       done++;
346                   xx = host[$6];
347                   d = disk[$6];
348                   l = level[$6];
349                   host_time[xx]+= ( tt = $4 - dmpr_strt[$6]);
350                   if(xx in disk_list) disk_list[xx] = disk_list[xx] "\n";
351                   disk_list[xx] = disk_list[xx] \
352                                   xx ":" d "/" l "\t" \
353                                   pr_time(dmpr_strt[$6]) \
354                                   " - " pr_time($4) \
355                                   " = "  pr_time(tt);
356 #                 print host[$6], disk[host[$6]];
357 #                       print host[$6], $4, dmpr_strt[$6], host_time[host[$6]]
358                 }
359         }
360         else if ($6=="taper:") {                # something else than DONE
361                 if($7=="TAPE-ERROR" || $7=="TRY-AGAIN") {
362                         tape_err= 1;
363                         err_time=$4/time_scale;
364                 }
365                 else if ($7=="TAPER-OK") tape_err=0;
366                 else if ($7=="PORT")    tape_err=0;
367                 else if ($7=="REQUEST-NEW-TAPE")    tape_err=0;
368                 else if ($7=="NEW-TAPE")    tape_err=0;
369                 else if ($7=="PARTDONE")    tape_err=0;
370                 else if ($7=="DUMPER-STATUS")    tape_err=0;
371                 else print fil, "UNKNOWN STATUS# "$0 ;
372         }
373         else {                                  # something bad from dumper 
374                 if ($7=="FAILED") { failed++;}
375                 else if ($7=="TRY-AGAIN"){ try++;}
376                 else if ($7=="PORT") ;  # ignore from chunker
377                 else if ($7=="RQ-MORE-DISK") ;  # FIXME: ignore for now
378                 else if ($7=="NO-ROOM")  
379                   print fil, pr_time($4),"#"  ++no_room, $0;
380                 else if( $7=="ABORT-FINISHED") print fil, "#" ++no_abort, $0;
381                 else print fil, "UNKNOWN STATUS# " $0;
382         }
383 }
384
385 function do_moves() { # function that extracts the estimated size of dumps
386                       # by processing DELAYING and promoting lines
387         est_size=$6;
388         getline ;                       # eat get next line print out planner msg
389         while (NF > 0 && (($1 == "delay:") || ($1 == "planner:")) ) {
390           if( $1 == "delay:") est_size = $NF;   # processing delay lines
391           else print fil, "DELAY#", $0;
392           getline;
393         }
394         getline ;                       # eating blank line
395         if( $1== "PROMOTING") {         # everything is dandy 
396                 getline;                # get first promote line
397                 while ( NF>0 && ($1 == "promote:" || $1 == "planner:" || $1 == "no" || $1 == "try") ) {
398                         if( $2 == "moving") {
399                                 est_size=$8;
400                                 print fil, "PROMOTING#", $1, $3;
401                         }
402                         else if($2 != "checking" && $2 != "can't" && $3 != "too" &&  $1 != "no" && $1 != "try" && $2 != "time")
403                              print fil,"PROMOTING#", $0;
404                         getline ;       # get next promote line
405                 }
406         }
407         else print fil, "DID NOT FIND PROMOTING LINE IN THE RIGHT PLACE",NR,$0;
408 }
409
410
411 END {
412         if( holding_disk == -1) {               # bad input file 
413                 print fil,": MISSING SPACE DECLARATION" ;
414                 exit;
415         }
416 # print headers of each graph  this is for the gnulot version 
417         if( tim >maxtime && extend==0)# if graph will extend beond borders
418           printf "Graph extends beond borders %s taking %7.3f > (max = %7.3f)\n",
419                         fil, tim, maxtime ;
420         print_t();                      # print titles
421         if( no_room + no_abort > 0) 
422              printf "NO-ROOM=%5d ABORT-FINISHED=%5d\n",  no_room, no_abort;
423         max_out = 20;
424         old_t = min_host * min_host;  # Some thing big
425         print "Longest dumping hosts   Times", min_host;
426         print "Host:disk/lev  \t start  -   end   =   run\t=> total";
427         while ( max_out-- > 0 && old_t > min_host) {
428           t = 0;
429           for (j in host_time) {
430             if( t < host_time[j] && host_time[j] <old_t){
431               t = host_time[d=j];
432             }
433           }
434           printf "%s\t=> %s\n\n", disk_list[d], pr_time(host_time[d]);
435 #         printf "%-20.20s Total Dump time %s\n", d, pr_time(host_time[d]);
436           old_t = t;
437         }
438 }
439
440 function print_t(){             # printing out the labels for the graph 
441         label=0;                # calculating where labels go and 
442                                 # range for x and y axes
443         maxy = int(no_disks/60+1)*20+que_raise;
444         printf "set yrange[0:%d]\n",maxy >"title";
445         if( maxtime < tim && extend !=0) {
446                 printf "set xrange[0:%d]\n", tim+30 >>"title";
447                 first_col = 10;
448                 second_col = (tim+30) * 0.45;
449                 key_col = (tim+30) * 1.042;
450                 third_col = (tim+30) * 1.0125;
451         }
452         else {
453                 printf "set xrange[0:%d]\n", maxtime >>"title";
454                 first_col = maxtime * 0.042
455                 second_col = maxtime * 0.45
456                 key_col = maxtime;
457                 third_col = maxtime*1.0125;
458         }
459         label_shift = (7 + int(no_disks/100));
460         lab = label_start = maxy+(6*label_shift) ;  # showing 6 labels
461         printf "set key at %d, %d\n", key_col, lab+4 >>"title";
462         printf "set label %d \"Amanda Dump %s\" at %d,%d\n", ++label,fil, 
463                 first_col,lab >"title";
464         lab -= label_shift;
465         printf "set label %d \"Bandwidth = %d\" at %d,%d\n",++label,bandw,
466                 first_col,lab >>"title";
467
468         lab -= label_shift;
469         printf "set label %d \"Holding disk = %d\" at %d,%d\n",++label,size,
470                 first_col,lab >>"title";
471
472         lab -= label_shift;
473         printf "set label %d \"Tape Policy = %s\" at %d,%d\n",++label,policy,
474                 first_col,lab >>"title";
475
476         lab -= label_shift;
477         printf "set label %d \"Dumpers= %d\" at %d,%d\n",++label,dumpers,
478                 first_col,lab >>"title";
479
480         lab -= label_shift;
481         if( alg =="drain-ends") 
482                 printf "set label %d \"Driver alg = %s At big end %d\" at %d,%d\n",
483                         ++label,alg, big,first_col,lab >>"title";
484         else #if( alg =="InOrder")  # other special cases
485                 printf "set label %d \"Driver alg = %s\" at %d,%d\n",
486                         ++label,alg,first_col, lab >>"title";
487
488         lab = label_start;
489         printf "set label %d \"Elapsed Time = %s\" at %d,%d\n",
490                 ++label,pr_time(tim*60),second_col,lab >>"title";
491
492         lab -= label_shift;
493         if( tape_err==1)        stm = "TAPE ERROR";
494         else if( quit ==1)      stm = "SUCCESS";
495         else  {                 stm = "UNKNOWN";
496                 print "Unknown terminating status",fil;
497         }
498         printf "set label %d \"Final status = %s\" at %d,%d\n",
499                 ++label,stm, second_col,lab >> "title";
500
501         lab -= label_shift;
502         printf "set label %d \"Dumped/Failed = %3d/%d\" at %d,%d\n",
503                 ++label,done,(failed+(try/2)), second_col,lab >>"title";
504
505         lab -= label_shift; 
506         printf "set label %d \"Output data size = %d\" at %d, %d\n",
507                 ++label,int(tout/1024+0.49999),second_col,lab >>"title";
508         if( est_size >0) {
509                 lab -= label_shift; 
510                 printf "set label %d \"Estimated data size = %d\" at %d, %d\n",
511                         ++label,int(est_size/1024+0.49999),second_col,lab >>"title";
512         }
513
514         if (gnuplot==0) {
515                 printf "set output \"%s.ps\"\n",fil >>"title";
516                 if(bw==1) {
517                         if(paper==1) printf "set term postscript landscape \"Times-Roman\" 10\n" >>"title";
518                         else printf "set term postscript portrait \"Times-Roman\" 10\n" >>"title";
519                 }
520                 else {
521                         if(paper==1) printf "set term postscript landscape color \"Times-Roman\" 10\n" >>"title";
522                         else printf "set term postscript portrait color \"Times-Roman\" 10\n" >>"title";
523                 }
524         } else {
525                 printf "set term x11\n" >> "title";
526         }
527         printf "set ylabel """";" >>"title";    # make sure there is no ylabel
528         fmt= "set label %d \"%s\" at "third_col", %d\n";
529         printf fmt, ++label,"%DUMPERS", 40 >>"title";
530         printf fmt, ++label,"TAPE",  95 >>"title";
531         printf fmt, ++label,"HOLDING",180 >>"title";
532         printf fmt, ++label,"DISK", 160 >>"title";
533         printf fmt, ++label,"%BANDWIDTH", 260 >>"title";
534         printf fmt, ++label,"QUEUES",(que_raise+maxy)/2 >>"title";
535         if((paper+gnuplot) > 0) print "set size 0.9, 0.9;"  >>"title";
536         else                    print "set size 0.7,1.3;"   >>"title";
537 }
538
539 function pr_time(pr_a){ #function to pretty print time
540   pr_h = int(pr_a/3600);
541   pr_m = int(pr_a/60)%60;
542   pr_s = int(pr_a+0.5) %60;
543   if( pr_m < 10 && pr_s < 10 ) return  pr_h":0"pr_m":0"pr_s;
544   else if( pr_s < 10)          return  pr_h":" pr_m":0"pr_s;
545   else if( pr_m < 10)          return  pr_h":0"pr_m":" pr_s;
546   else                         return  pr_h":" pr_m":" pr_s;
547 }