stategraph.in 4.69 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
#!/usr/bin/perl -w

#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#

use lib '@prefix@/lib';
use libdb;
require "ctime.pl";

my $datetag = `date +%Y%m%d%H%M%S`;
chomp($datetag);
my $date = &ctime(time);
$date =~ s/[ \t]+/ /;
$date =~ s/\n//;
my $defprefix = "stategraph-$datetag";
my $prefix = $defprefix;
my $v = 0; # Verbose
my $help=0;
my $allmodes=1;
my %modes=();

while ($_ = shift) {
    print "arg: '$_'\n" if ($v);
    /^-h/ && do { $help=1; next; };
    /^-[dv]/ && do { $v++; next; };
    /^-o/ && do { $prefix=shift || $defprefix; next; };
    # if it is all lowercase, caps it, otherwise leave it alone
    if ("\L$_" eq "$_") { $_ = "\U$_"; }
    $modes{$_}=1;
    $allmodes=0;
    print "mode '$_' added.\n" if ($v);
}

if ($help) {
    #Help mode
    print <<EOF;
Usage: stategraph [-h] [-v] [-d] [-o <out>] [op_mode1] ...
  -h       This help message
  -v       Verbose mode. Multiple -v options cause more verbosity.
  -d       Debug mode. Alias for -v.
  -o <out> Prefix for output filenames.

This program generates a graph of the state machines as defined in the
state_transitions and mode_transitions tables in the database. This
graph is generated from the current in the actual database, and is
always current. Output is saved into images named "out-vcg.ps" and
"out-dot.ps", where out defaults to "$defprefix".  
stategraph will show state machine diagrams for all operational modes
by default, or for a subset by specifying the desired modes on the
command line.
EOF

    die("\n");
}

my $filename="/tmp/stategraph-vcg-$$";
my $filename2="/tmp/stategraph-dot-$$";
open(TMP,">$filename");
open(TMPN,">$filename2");

print TMP "graph: {\n  orientation: top_to_bottom\n".
    "  title: \"Testbed State Machines Graph - ".$date."\"\n";
print TMP "  height: 500\n  width: 1000\n";
print TMP "  priority_phase: yes\n  straight_phase: yes\n";
print TMP "  arrowmode: fixed\n  node. shape:ellipse\n";
print TMP "  layoutalgorithm: maxdegree\n  port_sharing: no\n";

# Adjust the scale here...
print TMP "  display_edge_labels: yes\n  scaling: 1.0\n";

# Use one of the following to control layout... whichever works better...
print TMP "  crossingweight: medianbary\n  splines: yes\n";
#print TMP "  crossingweight: barymedian\n  splines: yes\n";

#print TMPN "digraph G {\n  node [shape=ellipse]\n  rotate=90\n";
print TMPN "digraph G {\n  node [shape=ellipse]\n";

my %states=();

my $cmd1 = "select * from state_transitions order by op_mode,state1,state2;";
my $cmd2 = "select * from mode_transitions order by op_mode1,state1,".
  "op_mode2,state2;";
my $lastmode="";
my $delim="_";

my $result = DBQueryFatal($cmd1);
while(@r=$result->fetchrow()) {
    $m=$r[0];
    print "mode='$m' lastmode='$lastmode'\n" if ($v>1);
    if (!($allmodes || (defined($modes{$m}) && $modes{$m}))) { next; }
    print "mode $m is on the list\n" if ($v && !$allmodes);
    if ($m ne $lastmode) {
	if ($lastmode ne "") { print TMPN "  }\n";}#print "Ending subgraph\n";}
	print TMPN "  subgraph cluster_$m {\n    label = \"$m\";\n";
	#print "Starting subgraph $m\n";
    }
    $lastmode = $m;
    $s1=$r[1];
    $s2=$r[2];
    mkstates([$m,$s1],[$m,$s2]);
    $n1 = $m.$delim.$s1;
    $n2 = $m.$delim.$s2;
    print TMPN "    $n1 -> $n2;\n";
    print TMP "  edge: { sourcename: \"$n1\" targetname: \"$n2\" }\n";
}

print TMPN "  }\n"; # end the last subgraph
my $modetrans=1;

$result = DBQueryFatal($cmd2);
while(@r=$result->fetchrow()) {
    $m1=$r[0];
    $s1=$r[1];
    $m2=$r[2];
    $s2=$r[3];
    print "Checking mode transition ($m1, $s1) -> ($m2, $s2)\n" if ($v);
    if (!( $allmodes || (defined($modes{$m1}) && $modes{$m1}) ||
	   (defined($modes{$m2}) && $modes{$m2}))) { next; }
    print "mode $m1 or $m2 is on the list\n" if ($v && !$allmodes);
    mkstates([$m1,$s1],[$m2,$s2]);
    $n1=$m1.$delim.$s1;
    $n2=$m2.$delim.$s2;
    print TMPN "  $n1 -> $n2;\n";
    print TMP "  edge: { sourcename: \"$n1\" targetname: \"$n2\" }\n";
}

print TMP "}\n";
close TMP;
print TMPN "}\n";
close TMPN;

print "Generating vcg graph...\n";
system("/usr/X11R6/bin/xvcg -silent -color -psoutput $prefix-vcg.ps $filename");
print "Generating dot graph...\n";
system("/usr/local/bin/dot -Tps -o $prefix-dot.ps $filename2");
print "Done.\n";

#exec "/bin/rm $filename";

sub mkstates {
    foreach $pair (@_) {
	my ($m, $s) = @$pair;
	$n = $m.$delim.$s;
	$l = $m."\n".$s;
	if (!defined($states{$n})) {
	    if ($modetrans) {
		# if we're doing modes and it isn't made yet, we don't
		# have a cluster for it, so label it better for TMPN
		$s=$m."\\n".$s;
	    }
	    print "Adding node '$n'\n" if ($v);
	    print TMP "  node: { title: \"$n\" label: \"$l\"}\n";
	    print TMPN "    $n [label=\"$s\"];\n";
	    $states{$n}=1;
	}
    }
}