File cf-profile.pl of Package cf-profile

#!/usr/bin/perl -w

##############################################################################
#
#   cf-profile.pl
#
#   Copyright (C) cfengineers.net
#
#   Written and maintained by Jon Henrik Bjornstad <jonhenrik@cfengineers.net>
#
#   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; version 3.
#
#   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.
#
##############################################################################

use strict;
use POSIX;
use Time::HiRes;
use Data::Dumper;
use Getopt::Std;

my %opts = ();
my %data = ();
my $debug = 0;
my $line = "";
my $cur_bundle = "";
my $cur_bundle_key = "";
my $promise_type = "";
my $iter = "";
my $parent_bundle = "";
my @parent = ();
my @parent_keys = ();
my $is_edit_bundle = 0;
my @b_log = ();
my $tabber = " " x 4;
my $branch = "-" x 4;
$line = <STDIN>;

getopts("T:dhstva", \%opts);

if(defined($opts{h})){
	usage();
}

if(defined($opts{d})){
	$debug = 1;
}
if(defined($opts{T})){
	$tabber = " " x $opts{T};
	$branch = "-" x $opts{T};
}

if(!defined($opts{a}) and !(defined($opts{t}) or defined($opts{c}) or defined($opts{s}))) {
	print "ERROR: you need to specify at least one of -a, -t, -s or -c\n";
	usage();
}

$data{start} = Time::HiRes::gettimeofday();

if($line =~ /^.*> /) {
	debug("Found output version < 3.5.0");
	prelude_v1();
	bundles_v1();
}else{
	die("This program is currently working with legacy output of cfengine < 3.5.0. If you are on
cfengine >= 3.5.0, try using the -l or --legacy-output switches for cf-agent.");
}

if(defined($opts{t}) or defined($opts{a})){
	print "===============================================================================\n";
	print "Execution tree\n";
	print "===============================================================================\n";
	print "Start: $data{start} s\n";
	print "|\n";

	foreach my $b(@b_log){
		my $elapsed = sprintf("%.5f", $data{bundles}{$b}{stop} - $data{bundles}{$b}{start});
		my $rel_start = sprintf("%.5f", $data{bundles}{$b}{start} - $data{start});
		my $rel_stop = sprintf("%.5f", $data{bundles}{$b}{stop} - $data{start});
		my $tab = "$tabber"x$data{bundles}{$b}{level};
	#	my $tab = "      "x$data{bundles}{$b}{level};
		my $header = "$branch"x$data{bundles}{$b}{level};
	#	my $header = "-----"x$data{bundles}{$b}{level};
		print "|$header> Bundle $b\n";
		print "|$tab"."$tab"."Start: $data{bundles}{$b}{start} s\n" if defined($opts{v});
		print "|$tab"."$tab"."Stop: $data{bundles}{$b}{stop} s\n" if defined($opts{v});
		print "|$tab"."$tab"."Elapsed: $elapsed s\n";
		print "|$tab"."$tab"."Relative start: $rel_start s\n" if defined($opts{v});
		print "|$tab"."$tab"."Relative stop: $rel_stop s\n" if defined($opts{v});
		
		if(defined($opts{v})){
			foreach my $p(@{$data{bundles}{$b}{prtype}}) {
				my $t = ($data{bundles}{$b}{promise_types}{$p}{start})? $data{bundles}{$b}{promise_types}{$p}{start} : "NAN";
				my ($pt,$pass) = split(/:/,$p);
				print "|$tab"."$tab"."$tab"."Promise type $pt: pass $pass\n";
				print "|$tab"."$tab"."$tab"."$tab"."Start: $t s\n";
				if(defined($data{bundles}{$b}{promise_types}{$p}{classes})) {
					print "|$tab"."$tab"."$tab"."$tab"."$tab".join("\n|$tab"."$tab"."$tab"."$tab"."$tab", @{$data{bundles}{$b}{promise_types}{$p}{classes}});
					print "\n";
				}
			}
		}
		print "|\n";
	}

	$data{stop} = Time::HiRes::gettimeofday();
	print "|\n";
	print "Stop: $data{stop} s\n";
	print "===============================================================================\n";
	print "\n";
}

if(defined($opts{s}) or defined($opts{a})){
	print "===============================================================================\n";
	print "Summary\n";
	print "===============================================================================\n";
	print "Top 10 worst, bundles:\n";
	print "Top 10 worst, promise types:\n";
}

exit(0);

sub usage {
	print<<EOF;

Usage: $0 [-T N] [-s|-t|-c|-a|-d|-v|-h]

   -s         : Print only summary info
   -t         : Print only eecution tree
   -c         : Print only classes info
   -a         : Print all (synonym to -s -t -c)
   -T N       : Set the tabulator to N chars in execution tree
   -d         : Set debug mode
   -v         : Set verbose output
   -h         : Print this help text

EOF
	exit(1);
}

sub debug {
	my $msg = shift;
	print "DEBUG: $msg\n" if $debug;
}

sub prelude_v1{
	$line = <STDIN>;
	do {
		if($line =~ /(Defined|Hard)\s+classes\s+=\s+\{\s+(.*)\s*\}/){
			$data{all_classes} = $2;
			debug("Found classes: \"$2\"");
			return 0;
		}
	} while($line = <STDIN>)
}

sub bundles_v1 {
	do {
		if($line =~ /Handling\s+file\s+edits\s+in\s+edit_line\s+bundle/){
			$is_edit_bundle = 1;  
		}
		if($line =~ /\s+BUNDLE\s+(\w+)(\(?\s*\{?[^\}]+\}?\s?\)?)?/){
			if(!$is_edit_bundle) {
				my $bundle = $1;
				my $args = (defined($2))? $2 : "";
				chomp $args;
				if($args) {
					while($line !~ /\'\}\s+\)$/){
						$line = <STDIN>;
						$args .= $line;
					}
				}
				chomp($args);
				debug("Found bundle $bundle $args");
				$cur_bundle = $bundle;
				$cur_bundle_key = $bundle.":".$args;
				$data{bundles}{$cur_bundle_key}{start} = Time::HiRes::gettimeofday();
				$b_log[$#b_log + 1] = $cur_bundle_key;
			}
			$is_edit_bundle = 0;
		} elsif ($line =~ /(\S+)\s+in\s+bundle\s+$cur_bundle\s+\((\d+)\)/){
			$promise_type = $1;
			$iter = $2;
			$data{bundles}{$cur_bundle_key}{prtype}[$#{$data{bundles}{$cur_bundle_key}{prtype}} + 1] = $promise_type.":".$iter;
			$data{bundles}{$cur_bundle_key}{promise_types}{$promise_type.":".$iter}{start} = Time::HiRes::gettimeofday();
			if($promise_type =~ /^methods$/ && ! grep(/$cur_bundle/,@parent)){
				debug("Registering parent $cur_bundle");
				push(@parent,$cur_bundle);
				push(@parent_keys,$cur_bundle_key);
			}
			debug("Found $promise_type in bundle $cur_bundle iter $iter");
		}elsif($line =~ /(Bundle\s+Accounting\s+Summary\s+for|Zero\s+promises\s+executed\s+for\s+bundle)\s+\"*\'*(\w+)\"*\'*/) {
			my $b = $2;
			debug("End $b");
			if($#parent >= 0 && $parent[$#parent] =~ /$b/) {
				pop(@parent);
				my $p = pop(@parent_keys);
				$data{bundles}{$p}{level} = $#parent + 2;
				$data{bundles}{$p}{stop} = Time::HiRes::gettimeofday();
			}else{
				$data{bundles}{$cur_bundle_key}{stop} = Time::HiRes::gettimeofday();
				$data{bundles}{$cur_bundle_key}{level} = $#parent + 2;
			}
#		}elsif ($line =~ /\s+(\+|\-)\s+(\S+)$/){
#			$data{bundles}{$cur_bundle_key}{promise_types}{$promise_type.":".$iter}{classes}[$#{$data{bundles}{$cur_bundle_key}{promise_types}{$promise_type.":".$iter}{classes}} + 1] = "$1$2";
		}elsif($line =~ /(defining\s+explicit\s+local\s+bundle\s+class\s+|defining\s+promise\s+result\s+class\s+)(\S+)/){
			$data{bundles}{$cur_bundle_key}{promise_types}{$promise_type.":".$iter}{classes}[$#{$data{bundles}{$cur_bundle_key}{promise_types}{$promise_type.":".$iter}{classes}} + 1] = "+$2";
		}
	} while($line = <STDIN>)
}
openSUSE Build Service is sponsored by