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.
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.
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.
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
29 # An awk program to parse the amdump file and output the information
30 # in a form at the gnuplot program amplot.g wants
32 # Creation Date: April 1992
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
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
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
54 min_host = maxtime * 0.75; # good rule of thumb
55 # min_host = 2.5; # expicit cutoff value in hours
58 # DO NOT CHANGE ANYTHING BELOW THIS LINE
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
64 disk_raise = 120; # scaling factors for Holding disk graph
66 dump_shift = 7.5; # scaling factors for Dumpers idle graph
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
72 bandw_scale = 30/300; # default calculated below
74 holding_disk = -1; # uninitialized
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
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" ) {
96 else if( $2=="start" && $3=="time") do_start();
97 else if( $2=="send-cmd") {
105 else if( $7 == "FILE-WRITE") file_write++;
106 else if( $7 == "START-TAPER") fil = $9;
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;
122 else if ( $1 == "planner:") {
123 if( $2 == "SKIPPED" || $2 == "FAILED") {
125 print fil, "INFO#", $0;
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;
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;
139 else if( $1 == "FLUSH") {
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
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
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;
167 unused = bandw_raise;
168 if( unused != unused_old)
169 printf plot_fmt, time, unused_old, time,unused >>"bandw_free";
172 if(holding_disk_old != $9) {
173 disk_alloc_time[disk_a] = time;
174 disk_alloc_space[disk_a] = holding_disk_old;
176 disk_alloc_time[disk_a] = time;
177 disk_alloc_space[disk_a] = $9;
179 holding_disk_old = $9;
183 if(twait_old != twait) {
184 twait_time[twait_a] = time;
185 twait_wait[twait_a] = twait_old;
187 twait_time[twait_a] = time;
188 twait_wait[twait_a] = twait;
193 active = (dumpers-$13)*dump_shift+dump_raise;
194 if( active != active_old )
195 printf plot_fmt, time, active_old, time, active >> "dump_idle";
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";
205 run = $18*count_scale+que_raise;
207 printf plot_fmt, time, run_old, time, run >> "run_queue";
210 finish = written * count_scale+que_raise;
211 if( finish != finish_old )
212 printf plot_fmt, time, finish_old, time, finish >> "finished";
215 tapeQ = $16 * count_scale+que_raise;
216 if( tapeQ != tapeQ_old )
217 printf plot_fmt, time, tapeQ_old, time, tapeQ >> "tape_queue";
222 function do_start() { # get configuration parameters
223 dumpers = $6; # how many
225 dump_shift = 75/dumpers;
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
233 print "do_start: no_disks", no_disks, $0;
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;
241 disk_alloc_time[disk_a] = 0;
242 disk_alloc_space[disk_a] = holding_disk_old;
247 twait_time[twait_a] = 0;
248 twait_wait[twait_a] = twait_old;
250 if( NF==14) { # original file was missing this
254 else if(NF>=18) { # newer files have this format
257 if( alg=="drain-ends") big = $20;
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";
274 function do_quit(){ # this is issued by driver at the end
275 # when it has nothing more to do
278 tim = $4 / time_scale;
280 disk_alloc_time[disk_a] = tim;
281 disk_alloc_space[disk_a] = holding_disk_old;
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];
291 if(max_space > holding_disk) {
292 space_change = max_space - holding_disk;
293 holding_disk = max_space;
296 twait_time[twait_a] = tim;
297 twait_wait[twait_a] = twait_old;
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];
306 if(flush_size == 0) {
307 holding_disk -= min_wait;
308 holding_disk -= space_change;
310 for(a=0; a<twait_a; a++) {
311 twait_wait[a] -= min_wait;
314 if (holding_disk != 0) {
315 const = 100/holding_disk;
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";
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";
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";
336 function do_result(){ # process lines driver: result
338 if( $6=="taper:"){ # taper done
343 else { # dumperx done
344 tsize += (int($15/32)+1)*32; # in tape blocks
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]) \
356 # print host[$6], disk[host[$6]];
357 # print host[$6], $4, dmpr_strt[$6], host_time[host[$6]]
360 else if ($6=="taper:") { # something else than DONE
361 if($7=="TAPE-ERROR" || $7=="TRY-AGAIN") {
363 err_time=$4/time_scale;
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 ;
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;
385 function do_moves() { # function that extracts the estimated size of dumps
386 # by processing DELAYING and promoting lines
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;
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") {
400 print fil, "PROMOTING#", $1, $3;
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
407 else print fil, "DID NOT FIND PROMOTING LINE IN THE RIGHT PLACE",NR,$0;
412 if( holding_disk == -1) { # bad input file
413 print fil,": MISSING SPACE DECLARATION" ;
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",
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;
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) {
429 for (j in host_time) {
430 if( t < host_time[j] && host_time[j] <old_t){
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]);
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";
448 second_col = (tim+30) * 0.45;
449 key_col = (tim+30) * 1.042;
450 third_col = (tim+30) * 1.0125;
453 printf "set xrange[0:%d]\n", maxtime >>"title";
454 first_col = maxtime * 0.042
455 second_col = maxtime * 0.45
457 third_col = maxtime*1.0125;
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";
465 printf "set label %d \"Bandwidth = %d\" at %d,%d\n",++label,bandw,
466 first_col,lab >>"title";
469 printf "set label %d \"Holding disk = %d\" at %d,%d\n",++label,size,
470 first_col,lab >>"title";
473 printf "set label %d \"Tape Policy = %s\" at %d,%d\n",++label,policy,
474 first_col,lab >>"title";
477 printf "set label %d \"Dumpers= %d\" at %d,%d\n",++label,dumpers,
478 first_col,lab >>"title";
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";
489 printf "set label %d \"Elapsed Time = %s\" at %d,%d\n",
490 ++label,pr_time(tim*60),second_col,lab >>"title";
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;
498 printf "set label %d \"Final status = %s\" at %d,%d\n",
499 ++label,stm, second_col,lab >> "title";
502 printf "set label %d \"Dumped/Failed = %3d/%d\" at %d,%d\n",
503 ++label,done,(failed+(try/2)), second_col,lab >>"title";
506 printf "set label %d \"Output data size = %d\" at %d, %d\n",
507 ++label,int(tout/1024+0.49999),second_col,lab >>"title";
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";
515 printf "set output \"%s.ps\"\n",fil >>"title";
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";
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";
525 printf "set term x11\n" >> "title";
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";
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;