#!/usr/bin/perl -w # cad_eval.pl Script for summarizing cadence logs # # # By Jeff Winston http://www.kwcpa.com/tools # Rev. 1.0, 6/24/04 Copyright (C) 2004 # # --------------------------------------------------------------------- # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # #of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # #along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, # USA. or check out http://www.gnu.org/copyleft/gpl.html # --------------------------------------------------------------------- # A complete description of how to use the script can be found by # calling the script with no arguments $| = 1; # enable autoflush use Time::Local; # header and help if ($#ARGV < 2) { print "\nUsage: cad_eval.pl {N * } \n\n"; print "cad_eval.pl uses the information in the cadence.log input files to provide\n"; print "a usage report, starting from the start_date given in the command line. Multiple\n"; print ".log files can be provided. The report consists of two parts. The first part is\n"; print "a listing, by input file, of the amount of time N licenses were in use for all N\n"; print" between 1 and the maximum number of licenses used. The second part is a combined\n"; print" histogram that shows peak number of licenses used for each week.\n\n"; print "Note: Some processing warnings around daylight savings time changes are not\n"; print "unusual, as perl and Cadence reckon these changes slightly differently.\n\n"; exit; } # get arguments while ($#ARGV > 1) { $tmp = shift @ARGV; push @infiles, $tmp; } $start_date = shift @ARGV; $outfile = shift @ARGV; # constants $sec_hour = 60 * 60; $sec_day = $sec_hour * 24; $sec_week = 7 * $sec_day; #inits $date=0; $start_epoch = seconds($start_date,"00:00:00"); $max_week=0; # open output file open(OUTFIL , "> $outfile") or die "Error opening $outfile\n"; print OUTFIL "CAD Tool Usage Report. Start Date: $start_date. Log files:\n"; foreach $filename (@infiles) { print OUTFIL " $filename\n"; } print OUTFIL "\nProcessing Warnings:\n"; # loop through all input files foreach $infile (@infiles) { # per-input-file inits $last_epoch = $start_epoch; $next_day=0; $line_count=0; $line_no=0; $recording=0; $week=0; $next_wk_start = $start_epoch + $sec_week; $weekname{$week} = $start_date; # open files open(INFIL ,"< $infile") or die "Error opening $infile\n"; print "\nOpening $infile\n"; #main loop while (defined ($line = )) { # line counting $line_no++; $line_count++; if ($line_count == 250000) { print "Processed $line_no lines\n"; $line_count=0; } # parse line @words = split " ",$line; # process line only if it's line 1 of a license manager entry if (($#words > 2) && (($words[1] =~ "cdslmd") || ($words[1] =~ "lmgrd"))) { # if it's a time stamp if ($words[2] eq "TIMESTAMP") { $next_day=0; # reset extra day flag # get the date, and set recording flag if it's the start date $date = $words[3]; $cur_day_epoch = seconds($date,"00:00:00"); if (($recording == 0) && ($cur_day_epoch > $start_epoch)) { $recording = 1; print "$date: Recording...\n"; } } # if recording if ($recording == 1) { # capture time, but only if we're going to be interested in using it if (($words[2] eq "OUT:" ) || ($words[2] eq "IN:" ) || ($line =~ " Starting ")) { $cur_epoch = seconds($date,$words[0]); # need to add a day if the time field "turned over" to next day if ($cur_epoch < $last_epoch) { # you get this error occasionally - related to daylight savings time # either clock is set back, or is set ahead but during the wrong (w.r.t. localtime) hour $a=localtime($last_epoch); if ($next_day == 1) { print "$line_no: $date $words[0]: Warning: Time set back twice (was $a)\n"; print OUTFIL "$infile: $line_no: $date $words[0]: Warning: Time set back twice (was $a)\n"; } $next_day=1; } $last_epoch = $cur_epoch; # use time with the extra day if appropriate $now_epoch = $cur_epoch + ($next_day * $sec_day); # if current time is later than current week - increment week # until we're current, creating week label and slot for # each intervening week while ($now_epoch > $next_wk_start) { # accumulate peak usage for week just past foreach $tool (@{$tools{$infile}}) { $tool_week_str = $tool . "%" . $week; if (!(defined($cum_ttl_per_week{$tool_week_str}))) { $cum_ttl_per_week{$tool_week_str} =0; } # accumulate the peak usage per file $cum_ttl_per_week{$tool_week_str} = $cum_ttl_per_week{$tool_week_str} + $peak_this_week{$tool}; # and reset the peak to the current usage to start the new week $peak_this_week{$tool} = $curlic_out{$tool}; } # advance week $week++; # get formatted time for start of this week, format it and store it @timarray = localtime($next_wk_start); $timarray[4]++; $timarray[5] = $timarray[5]+1900; $weekname{$week} = sprintf("%02d",$timarray[4]) . "/" . sprintf("%02d",$timarray[3]) . "/" . $timarray[5]; # boost pointer to beginning of next week $next_wk_start = $next_wk_start + $sec_week; } # keep track of most recent week to appear in any file if ($max_week < $week) { $max_week = $week; } } # process check out if ($words[2] eq "OUT:") { # get tool name, and add to list if new $tool = $words[3]; $tool =~ s/\"//g; $found=0; foreach $tl (@{$tools{$infile}}) { if ($tool eq $tl) { $found=1; last; } } if ($found == 0) { push @{$tools{$infile}}, $tool; # when adding to list, init hash entries # these are re-inited for each new file $curlic_out{$tool} = 0; $peak_this_week{$tool} = 0; $file_peak{$tool} = 0; # max_peak is file independent if (!(defined($max_peak{$tool}))) { $max_peak{$tool}= 0; } } # increase number of licenses out for this tool for this file $curlic_out{$tool}++; # generate hash indice $toolstr = $tool . "%" . $curlic_out{$tool} . "%" . $infile; # bump all the max values... # bump running peak for this tool for this week if ($curlic_out{$tool} > $peak_this_week{$tool}) { $peak_this_week{$tool} = $curlic_out{$tool}; } # bump running peak for this tool for this input file if ($curlic_out{$tool} > $file_peak{$tool}) { $file_peak{$tool} = $curlic_out{$tool}; $day_of_first_peak{$toolstr} = localtime($now_epoch); } # bump running peak for this tool if ($curlic_out{$tool} > $max_peak{$tool}) { $max_peak{$tool} = $curlic_out{$tool}; } # store time tool was checked out $time_out{$toolstr} = $now_epoch; } #process check in elsif ($words[2] eq "IN:") { # if unknown tool - flag error $tool = $words[3]; $tool =~ s/\"//g; $found=0; foreach $tl (@{$tools{$infile}}) { if ($tool eq $tl) { $found=1; last; } } if ($found == 0) { print "$line_no: $date $words[0]: Warning: Unknown tool $tool checked IN without prior check OUT\n"; print OUTFIL "$infile, $line_no: $date $words[0]: Warning: Unknown tool $tool checked IN without prior check OUT\n"; } # otherwise, if there are some of this tool checked out... elsif ($curlic_out{$tool}>0) { # generate hash indices $toolstr = $tool . "%" . $curlic_out{$tool} . "%" . $infile; # init usage if needed if (!(defined($usage{$toolstr}))) { $usage{$toolstr} =0; } # add to usage if ($now_epoch > $time_out{$toolstr}) { $usage{$toolstr} = $usage{$toolstr} + ($now_epoch - $time_out{$toolstr}); # or flag error if incremental usage negative } elsif ($now_epoch < $time_out{$toolstr}) { $a=localtime($time_out{$toolstr}); print "$line_no: $date $words[0]: Warning: Negative time Interval: $tool (From $a)\n"; print OUTFIL "$infile, $line_no: $date $words[0]: Warning: Negative time Interval: $tool (From $a)\n"; } # reduce number of licenses out $curlic_out{$tool}--; } } # license re-start. all tools check in elsif ($line =~ " Starting ") { # go through all tools foreach $tool (@{$tools{$infile}}) { # and all licenses out for ($x=1; $x <= $curlic_out{$tool}; $x++) { $toolstr = $tool . "%" . $x . "%" . $infile; # init usage if needed if (!(defined($usage{$toolstr}))) { $usage{$toolstr} =0; } # add to usage time up to latest time in file if ($now_epoch > $time_out{$toolstr}) { $usage{$toolstr} = $usage{$toolstr} + ($now_epoch - $time_out{$toolstr}); # or flag error if incremental usage negative } elsif ($now_epoch < $time_out{$toolstr}) { $a=localtime($time_out{$toolstr}); print "$lineno: $date $words[0]: Warning: Negative time Interval: $tool (From $a)\n"; print OUTFIL "$infile, $lineno: $date $words[0]: Warning: Negative time Interval: $tool (From $a)\n"; } } # zero out outstanding licenses $curlic_out{$tool}=0; } } } } } # cleanup - terminate all open licenses as of now (same code as license re-start) # go through all tools foreach $tool (@{$tools{$infile}}) { # update cumulative weekly peak $tool_week_str = $tool . "%" . $week; if (!(defined($cum_ttl_per_week{$tool_week_str}))) { $cum_ttl_per_week{$tool_week_str} =0; } $cum_ttl_per_week{$tool_week_str} = $cum_ttl_per_week{$tool_week_str} + $peak_this_week{$tool}; # go through all licenses out for ($x=1; $x <= $curlic_out{$tool}; $x++) { $toolstr = $tool . "%" . $x . "%" . $infile; # init usage if needed if (!(defined($usage{$toolstr}))) { $usage{$toolstr} =0; } # add to usage time up to last time in file if ($now_epoch > $time_out{$toolstr}) { $usage{$toolstr} = $usage{$toolstr} + ($now_epoch - $time_out{$toolstr}); # or flag error if incremental usage negative } elsif ($now_epoch < $time_out{$toolstr}) { $a=localtime($time_out{$toolstr}); print "$lineno: $date $words[0]: Warning: Negative time Interval: $tool (From $a)\n"; print OUTFIL "$infile, $lineno: $date $words[0]: Warning: Negative time Interval: $tool (From $a)\n"; } } # zero out tools in use $curlic_out{$tool}=0; } print "Processed $line_no lines\n"; close (INFIL); } # merge tool lists into one master list, and sort it foreach $infile (@infiles) { foreach $tool (@{$tools{$infile}}) { $found=0; foreach $tl (@alltools) { if ($tl eq $tool) { $found=1; last; } } if ($found == 0) { push @alltools, $tool; } } } @sorted_tools = sort { $a cmp $b } @alltools; # print results # go by tool foreach $tool (@sorted_tools) { # first, summaries of time usage foreach $infile (@infiles) { # go by number of licenses out for ($x=1; $x <= $max_peak{$tool}; $x++) { $toolstr = $tool . "%" . $x . "%" . $infile; # only do it for usages that exist if (defined($usage{$toolstr})) { # print header first time if ($x==1) { print OUTFIL "\nTool: $tool, File: $infile\n"; } # calculate and print usage $day_use = int($usage{$toolstr}/$sec_day); $hr_use = sprintf("%5.2f",($usage{$toolstr} - ($day_use * $sec_day))/$sec_hour); printf OUTFIL "Licenses %2d Time: %4d Days %5.2f Hours 1st Peak: %s\n",$x,$day_use,$hr_use,$day_of_first_peak{$toolstr}; } } } # now the histogram print OUTFIL "\n\fCombined Histogram for Tool: $tool\n"; # go by week for ($w=0; $w<=$max_week; $w++) { $tool_week_str = $tool . "%" . $w; # print header printf OUTFIL ("Week of %10s: ",$weekname{$w}); # if usage is recorded, print bar graph if (defined($cum_ttl_per_week{$tool_week_str})) { for ($z=0; $z < $cum_ttl_per_week{$tool_week_str}; $z++) { if ($z==0) { printf OUTFIL "%3d |",$cum_ttl_per_week{$tool_week_str}; } print OUTFIL "*"; } } print OUTFIL "\n"; } } # all done print "$outfile written\n"; exit; #convert date and time to epoch time sub seconds { my $date = shift @_; my $time = shift @_; @num = split ":",$time; @dat = split "/",$date; my $seconds = $num[2]; my $minutes = $num[1]; my $hours = $num[0]; my $month = $dat[0]-1; my $day = $dat[1]; my $year = $dat[2] -1900; $epoch = timelocal($seconds,$minutes,$hours,$day,$month,$year); return($epoch); }