1*d3c97224SAlexander Kolbasov#! /usr/perl5/bin/perl 2*d3c97224SAlexander Kolbasov# 3*d3c97224SAlexander Kolbasov# CDDL HEADER START 4*d3c97224SAlexander Kolbasov# 5*d3c97224SAlexander Kolbasov# The contents of this file are subject to the terms of the 6*d3c97224SAlexander Kolbasov# Common Development and Distribution License (the "License"). 7*d3c97224SAlexander Kolbasov# You may not use this file except in compliance with the License. 8*d3c97224SAlexander Kolbasov# 9*d3c97224SAlexander Kolbasov# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*d3c97224SAlexander Kolbasov# or http://www.opensolaris.org/os/licensing. 11*d3c97224SAlexander Kolbasov# See the License for the specific language governing permissions 12*d3c97224SAlexander Kolbasov# and limitations under the License. 13*d3c97224SAlexander Kolbasov# 14*d3c97224SAlexander Kolbasov# When distributing Covered Code, include this CDDL HEADER in each 15*d3c97224SAlexander Kolbasov# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*d3c97224SAlexander Kolbasov# If applicable, add the following below this CDDL HEADER, with the 17*d3c97224SAlexander Kolbasov# fields enclosed by brackets "[]" replaced with your own identifying 18*d3c97224SAlexander Kolbasov# information: Portions Copyright [yyyy] [name of copyright owner] 19*d3c97224SAlexander Kolbasov# 20*d3c97224SAlexander Kolbasov# CDDL HEADER END 21*d3c97224SAlexander Kolbasov# 22*d3c97224SAlexander Kolbasov 23*d3c97224SAlexander Kolbasov# 24*d3c97224SAlexander Kolbasov# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 25*d3c97224SAlexander Kolbasov# 26*d3c97224SAlexander Kolbasov 27*d3c97224SAlexander Kolbasov# 28*d3c97224SAlexander Kolbasov# pgstat - tool for displaying Processor Group statistics 29*d3c97224SAlexander Kolbasov# 30*d3c97224SAlexander Kolbasov 31*d3c97224SAlexander Kolbasovuse warnings; 32*d3c97224SAlexander Kolbasovuse strict; 33*d3c97224SAlexander Kolbasovuse File::Basename; 34*d3c97224SAlexander Kolbasovuse List::Util qw(first max min); 35*d3c97224SAlexander Kolbasovuse Errno; 36*d3c97224SAlexander Kolbasovuse POSIX qw(locale_h strftime); 37*d3c97224SAlexander Kolbasovuse Getopt::Long qw(:config no_ignore_case bundling auto_version); 38*d3c97224SAlexander Kolbasovuse Sun::Solaris::Utils qw(textdomain gettext); 39*d3c97224SAlexander Kolbasovuse Sun::Solaris::Pg; 40*d3c97224SAlexander Kolbasov 41*d3c97224SAlexander Kolbasov# 42*d3c97224SAlexander Kolbasov# Constants section 43*d3c97224SAlexander Kolbasov# 44*d3c97224SAlexander Kolbasov# It is possible that wnen trying to parse PG kstats, PG generation changes 45*d3c97224SAlexander Kolbasov# which will cause PG new method to fail with errno set to EAGAIN In this case 46*d3c97224SAlexander Kolbasov# we retry open up to RETRY_COUNT times pausing RETRY_DELAY seconds between each 47*d3c97224SAlexander Kolbasov# retry. 48*d3c97224SAlexander Kolbasov# 49*d3c97224SAlexander Kolbasov# When printing PGs we print them as a little tree with each PG shifted by 50*d3c97224SAlexander Kolbasov# LEVEL_OFFSET from each parent. For example: 51*d3c97224SAlexander Kolbasov# 52*d3c97224SAlexander Kolbasov# PG RELATIONSHIP CPUs 53*d3c97224SAlexander Kolbasov# 0 System 0-7 54*d3c97224SAlexander Kolbasov# 3 Socket 0 2 4 6 55*d3c97224SAlexander Kolbasov# 2 Cache 0 2 4 6 56*d3c97224SAlexander Kolbasov# 57*d3c97224SAlexander Kolbasov# 58*d3c97224SAlexander Kolbasov# DEFAULT_INTERVAL - interval in seconds between snapshot if none is specified 59*d3c97224SAlexander Kolbasov# DEFAULT_COUNT - Number of iterations if none is specified 60*d3c97224SAlexander Kolbasov# HWLOAD_UNKNOWN - Value that we use to represent unknown hardware load 61*d3c97224SAlexander Kolbasov# HWLOAD_UNDEF - Value that we use to represent undefined hardware load 62*d3c97224SAlexander Kolbasov# 63*d3c97224SAlexander Kolbasovuse constant { 64*d3c97224SAlexander Kolbasov VERSION => 1.1, 65*d3c97224SAlexander Kolbasov DEFAULT_INTERVAL => 1, 66*d3c97224SAlexander Kolbasov DEFAULT_COUNT => 1, 67*d3c97224SAlexander Kolbasov RETRY_COUNT => 4, 68*d3c97224SAlexander Kolbasov RETRY_DELAY => 0.25, 69*d3c97224SAlexander Kolbasov HWLOAD_UNKNOWN => -1, 70*d3c97224SAlexander Kolbasov HWLOAD_UNDEF => -2, 71*d3c97224SAlexander Kolbasov LEVEL_OFFSET => 1, 72*d3c97224SAlexander Kolbasov}; 73*d3c97224SAlexander Kolbasov 74*d3c97224SAlexander Kolbasov# 75*d3c97224SAlexander Kolbasov# Format for fields, showing percentage headers 76*d3c97224SAlexander Kolbasov# 77*d3c97224SAlexander Kolbasovmy $pcnt_fmt = "%6s"; 78*d3c97224SAlexander Kolbasov# 79*d3c97224SAlexander Kolbasov# Format for percentages field 80*d3c97224SAlexander Kolbasov# 81*d3c97224SAlexander Kolbasovmy $pcnt = "%5.1f"; 82*d3c97224SAlexander Kolbasov 83*d3c97224SAlexander Kolbasov# 84*d3c97224SAlexander Kolbasov# Return codes 85*d3c97224SAlexander Kolbasov# 86*d3c97224SAlexander Kolbasov# 0 Successful completion. 87*d3c97224SAlexander Kolbasov# 88*d3c97224SAlexander Kolbasov# 1 An error occurred. 89*d3c97224SAlexander Kolbasov# 90*d3c97224SAlexander Kolbasov# 2 Invalid command-line options were specified. 91*d3c97224SAlexander Kolbasov# 92*d3c97224SAlexander Kolbasovuse constant { 93*d3c97224SAlexander Kolbasov E_SUCCESS => 0, 94*d3c97224SAlexander Kolbasov E_ERROR => 1, 95*d3c97224SAlexander Kolbasov E_USAGE => 2, 96*d3c97224SAlexander Kolbasov}; 97*d3c97224SAlexander Kolbasov 98*d3c97224SAlexander Kolbasov# 99*d3c97224SAlexander Kolbasov# Valid sort keys for -s and -S options 100*d3c97224SAlexander Kolbasov# 101*d3c97224SAlexander Kolbasovmy @sort_keys = qw(pg hwload swload user sys idle depth breadth); 102*d3c97224SAlexander Kolbasov 103*d3c97224SAlexander Kolbasov# Set message locale 104*d3c97224SAlexander Kolbasovsetlocale(LC_ALL, ""); 105*d3c97224SAlexander Kolbasovtextdomain(TEXT_DOMAIN); 106*d3c97224SAlexander Kolbasov 107*d3c97224SAlexander Kolbasov# Get script name for error messages 108*d3c97224SAlexander Kolbasovour $cmdname = basename($0, ".pl"); 109*d3c97224SAlexander Kolbasov 110*d3c97224SAlexander Kolbasovmy @pg_list; # -P pg,... - PG arguments 111*d3c97224SAlexander Kolbasovmy @cpu_list; # -c cpu,... - CPU arguments 112*d3c97224SAlexander Kolbasovmy @sharing_filter_neg; # -R string,... - Prune PGs 113*d3c97224SAlexander Kolbasovmy @sharing_filter; # -r string,... - Matching sharing names 114*d3c97224SAlexander Kolbasovmy $do_aggregate; # -A - Show summary in the end 115*d3c97224SAlexander Kolbasovmy $do_cpu_utilization; # -C - Show per-CPU utilization 116*d3c97224SAlexander Kolbasovmy $do_physical; # -p - Show physical relationships 117*d3c97224SAlexander Kolbasovmy $do_timestamp; # -T - Print timestamp 118*d3c97224SAlexander Kolbasovmy $do_usage; # -h - Show usage 119*d3c97224SAlexander Kolbasovmy $do_version; # -V - Verbose output 120*d3c97224SAlexander Kolbasovmy $show_top; # -t - show top N 121*d3c97224SAlexander Kolbasovmy $sort_order_a; # -S key - Ascending sort order 122*d3c97224SAlexander Kolbasovmy $sort_order_d; # -s key - Descending sort order 123*d3c97224SAlexander Kolbasovmy $verbose; # -v - Verbose output; 124*d3c97224SAlexander Kolbasov 125*d3c97224SAlexander Kolbasov$verbose = 0; 126*d3c97224SAlexander Kolbasov 127*d3c97224SAlexander Kolbasov# Parse options from the command line 128*d3c97224SAlexander KolbasovGetOptions("aggregate|A" => \$do_aggregate, 129*d3c97224SAlexander Kolbasov "cpus|c=s" => \@cpu_list, 130*d3c97224SAlexander Kolbasov "showcpu|C" => \$do_cpu_utilization, 131*d3c97224SAlexander Kolbasov "help|h|?" => \$do_usage, 132*d3c97224SAlexander Kolbasov "pgs|P=s" => \@pg_list, 133*d3c97224SAlexander Kolbasov "physical|p" => \$do_physical, 134*d3c97224SAlexander Kolbasov "relationship|r=s" => \@sharing_filter, 135*d3c97224SAlexander Kolbasov "norelationship|R=s" => \@sharing_filter_neg, 136*d3c97224SAlexander Kolbasov "sort|s=s" => \$sort_order_d, 137*d3c97224SAlexander Kolbasov "Sort|S=s" => \$sort_order_a, 138*d3c97224SAlexander Kolbasov "top|t=i" => \$show_top, 139*d3c97224SAlexander Kolbasov "timestamp|T=s" => \$do_timestamp, 140*d3c97224SAlexander Kolbasov "version|V" => \$do_version, 141*d3c97224SAlexander Kolbasov "verbose+" => \$verbose, 142*d3c97224SAlexander Kolbasov "v+" => \$verbose, 143*d3c97224SAlexander Kolbasov) || usage(E_USAGE); 144*d3c97224SAlexander Kolbasov 145*d3c97224SAlexander Kolbasov# Print usage message when -h is given 146*d3c97224SAlexander Kolbasovusage(E_SUCCESS) if $do_usage; 147*d3c97224SAlexander Kolbasov 148*d3c97224SAlexander Kolbasovif ($do_version) { 149*d3c97224SAlexander Kolbasov printf gettext("%s version %s\n"), $cmdname, VERSION; 150*d3c97224SAlexander Kolbasov exit(E_SUCCESS); 151*d3c97224SAlexander Kolbasov} 152*d3c97224SAlexander Kolbasov 153*d3c97224SAlexander Kolbasov# 154*d3c97224SAlexander Kolbasov# Verify options 155*d3c97224SAlexander Kolbasov# 156*d3c97224SAlexander Kolbasov# -T should have either u or d argument 157*d3c97224SAlexander Kolbasovif (defined($do_timestamp) && !($do_timestamp eq 'u' || $do_timestamp eq 'd')) { 158*d3c97224SAlexander Kolbasov printf STDERR gettext("%s: Invalid -T %s argument\n"), 159*d3c97224SAlexander Kolbasov $cmdname, $do_timestamp; 160*d3c97224SAlexander Kolbasov usage(E_USAGE); 161*d3c97224SAlexander Kolbasov} 162*d3c97224SAlexander Kolbasov 163*d3c97224SAlexander Kolbasovif ($sort_order_a && $sort_order_d) { 164*d3c97224SAlexander Kolbasov printf STDERR gettext("%s: -S and -s flags can not be used together\n"), 165*d3c97224SAlexander Kolbasov $cmdname; 166*d3c97224SAlexander Kolbasov usage(E_USAGE); 167*d3c97224SAlexander Kolbasov} 168*d3c97224SAlexander Kolbasov 169*d3c97224SAlexander Kolbasovif (defined ($show_top) && $show_top <= 0) { 170*d3c97224SAlexander Kolbasov printf STDERR gettext("%s: -t should specify positive integer\n"), 171*d3c97224SAlexander Kolbasov $cmdname; 172*d3c97224SAlexander Kolbasov usage(E_USAGE); 173*d3c97224SAlexander Kolbasov} 174*d3c97224SAlexander Kolbasov 175*d3c97224SAlexander Kolbasov# 176*d3c97224SAlexander Kolbasov# Figure out requested sorting of the output 177*d3c97224SAlexander Kolbasov# By default 'depth-first' is used 178*d3c97224SAlexander Kolbasov# 179*d3c97224SAlexander Kolbasovmy $sort_key; 180*d3c97224SAlexander Kolbasovmy $sort_reverse; 181*d3c97224SAlexander Kolbasov 182*d3c97224SAlexander Kolbasovif (!($sort_order_a || $sort_order_d)) { 183*d3c97224SAlexander Kolbasov $sort_key = 'depth'; 184*d3c97224SAlexander Kolbasov $sort_reverse = 1; 185*d3c97224SAlexander Kolbasov} else { 186*d3c97224SAlexander Kolbasov $sort_key = $sort_order_d || $sort_order_a; 187*d3c97224SAlexander Kolbasov $sort_reverse = defined($sort_order_d); 188*d3c97224SAlexander Kolbasov} 189*d3c97224SAlexander Kolbasov 190*d3c97224SAlexander Kolbasov# 191*d3c97224SAlexander Kolbasov# Make sure sort key is valid 192*d3c97224SAlexander Kolbasov# 193*d3c97224SAlexander Kolbasovif (!list_match($sort_key, \@sort_keys, 1)) { 194*d3c97224SAlexander Kolbasov printf STDERR gettext("%s: invalid sort key %s\n"), 195*d3c97224SAlexander Kolbasov $cmdname, $sort_key; 196*d3c97224SAlexander Kolbasov usage(E_USAGE); 197*d3c97224SAlexander Kolbasov} 198*d3c97224SAlexander Kolbasov 199*d3c97224SAlexander Kolbasov# 200*d3c97224SAlexander Kolbasov# Convert -[Rr] string1,string2,... into list (string1, string2, ...) 201*d3c97224SAlexander Kolbasov# 202*d3c97224SAlexander Kolbasov@sharing_filter = map { split /,/ } @sharing_filter; 203*d3c97224SAlexander Kolbasov@sharing_filter_neg = map { split /,/ } @sharing_filter_neg; 204*d3c97224SAlexander Kolbasov 205*d3c97224SAlexander Kolbasov# 206*d3c97224SAlexander Kolbasov# We use two PG snapshot to compare utilization between them. One snapshot is 207*d3c97224SAlexander Kolbasov# kept behind another in time. 208*d3c97224SAlexander Kolbasov# 209*d3c97224SAlexander Kolbasovmy $p = Sun::Solaris::Pg->new(-cpudata => $do_cpu_utilization, 210*d3c97224SAlexander Kolbasov -swload => 1, 211*d3c97224SAlexander Kolbasov -tags => $do_physical, 212*d3c97224SAlexander Kolbasov -retry => RETRY_COUNT, 213*d3c97224SAlexander Kolbasov -delay => RETRY_DELAY); 214*d3c97224SAlexander Kolbasov 215*d3c97224SAlexander Kolbasovif (!$p) { 216*d3c97224SAlexander Kolbasov printf STDERR 217*d3c97224SAlexander Kolbasov gettext("%s: can not obtain Processor Group information: $!\n"), 218*d3c97224SAlexander Kolbasov $cmdname; 219*d3c97224SAlexander Kolbasov exit(E_ERROR); 220*d3c97224SAlexander Kolbasov} 221*d3c97224SAlexander Kolbasov 222*d3c97224SAlexander Kolbasovmy $p_initial = $p; 223*d3c97224SAlexander Kolbasovmy $p_dup = Sun::Solaris::Pg->new(-cpudata => $do_cpu_utilization, 224*d3c97224SAlexander Kolbasov -swload => 1, 225*d3c97224SAlexander Kolbasov -tags => $do_physical, 226*d3c97224SAlexander Kolbasov -retry => RETRY_COUNT, 227*d3c97224SAlexander Kolbasov -delay => RETRY_DELAY); 228*d3c97224SAlexander Kolbasov 229*d3c97224SAlexander Kolbasovif (!$p_dup) { 230*d3c97224SAlexander Kolbasov printf STDERR 231*d3c97224SAlexander Kolbasov gettext("%s: can not obtain Processor Group information: $!\n"), 232*d3c97224SAlexander Kolbasov $cmdname; 233*d3c97224SAlexander Kolbasov exit(E_ERROR); 234*d3c97224SAlexander Kolbasov} 235*d3c97224SAlexander Kolbasov 236*d3c97224SAlexander Kolbasov# 237*d3c97224SAlexander Kolbasov# Get interval and count 238*d3c97224SAlexander Kolbasov# 239*d3c97224SAlexander Kolbasovmy $count = DEFAULT_COUNT; 240*d3c97224SAlexander Kolbasovmy $interval = DEFAULT_INTERVAL; 241*d3c97224SAlexander Kolbasov 242*d3c97224SAlexander Kolbasovif (scalar @ARGV > 0) { 243*d3c97224SAlexander Kolbasov $interval = shift @ARGV; 244*d3c97224SAlexander Kolbasov if (scalar @ARGV > 0) { 245*d3c97224SAlexander Kolbasov $count = $ARGV[0]; 246*d3c97224SAlexander Kolbasov } else { 247*d3c97224SAlexander Kolbasov $count = 0; 248*d3c97224SAlexander Kolbasov } 249*d3c97224SAlexander Kolbasov} 250*d3c97224SAlexander Kolbasov 251*d3c97224SAlexander Kolbasovif (! ($interval=~ m/^\d+\.?\d*$/)) { 252*d3c97224SAlexander Kolbasov printf STDERR 253*d3c97224SAlexander Kolbasov gettext("%s: Invalid interval %s - should be numeric\n"), 254*d3c97224SAlexander Kolbasov $cmdname, $interval; 255*d3c97224SAlexander Kolbasov usage(E_USAGE); 256*d3c97224SAlexander Kolbasov} 257*d3c97224SAlexander Kolbasov 258*d3c97224SAlexander Kolbasovif ($count && ! ($count=~ m/^\d+$/)) { 259*d3c97224SAlexander Kolbasov printf STDERR 260*d3c97224SAlexander Kolbasov gettext("%s: Invalid count %s - should be numeric\n"), 261*d3c97224SAlexander Kolbasov $cmdname, $count; 262*d3c97224SAlexander Kolbasov usage(E_USAGE); 263*d3c97224SAlexander Kolbasov} 264*d3c97224SAlexander Kolbasov 265*d3c97224SAlexander Kolbasovmy $infinite = 1 unless $count; 266*d3c97224SAlexander Kolbasov 267*d3c97224SAlexander Kolbasov# 268*d3c97224SAlexander Kolbasov# Get list of all PGs 269*d3c97224SAlexander Kolbasov# 270*d3c97224SAlexander Kolbasovmy @all_pgs = $p->all_depth_first(); 271*d3c97224SAlexander Kolbasov 272*d3c97224SAlexander Kolbasov# 273*d3c97224SAlexander Kolbasov# get list of all CPUs in the system by looking at the root PG cpus 274*d3c97224SAlexander Kolbasov# 275*d3c97224SAlexander Kolbasovmy @all_cpus = $p->cpus($p->root()); 276*d3c97224SAlexander Kolbasov 277*d3c97224SAlexander Kolbasov# PGs to work with 278*d3c97224SAlexander Kolbasovmy @pgs = @all_pgs; 279*d3c97224SAlexander Kolbasov 280*d3c97224SAlexander Kolbasovmy $rc = E_SUCCESS; 281*d3c97224SAlexander Kolbasov 282*d3c97224SAlexander Kolbasov# 283*d3c97224SAlexander Kolbasov# Convert CPU and PG lists into proper Perl lists, converting things like 284*d3c97224SAlexander Kolbasov# 1-3,5 into (1, 2, 3, 5). Also convert 'all' into the list of all CPUs or PGs 285*d3c97224SAlexander Kolbasov# 286*d3c97224SAlexander Kolbasov@cpu_list = 287*d3c97224SAlexander Kolbasov map { $_ eq 'all' ? @all_cpus : $_ } # all -> (cpu1, cpu2, ...) 288*d3c97224SAlexander Kolbasov map { split /,/ } @cpu_list; # x,y -> (x, y) 289*d3c97224SAlexander Kolbasov 290*d3c97224SAlexander Kolbasov@cpu_list = $p->expand(@cpu_list); # 1-3 -> 1 2 3 291*d3c97224SAlexander Kolbasov 292*d3c97224SAlexander Kolbasov# Same drill for PGs 293*d3c97224SAlexander Kolbasov@pg_list = 294*d3c97224SAlexander Kolbasov map { $_ eq 'all' ? @all_pgs : $_ } 295*d3c97224SAlexander Kolbasov map { split /,/ } @pg_list; 296*d3c97224SAlexander Kolbasov 297*d3c97224SAlexander Kolbasov@pg_list = $p->expand(@pg_list); 298*d3c97224SAlexander Kolbasov 299*d3c97224SAlexander Kolbasov# 300*d3c97224SAlexander Kolbasov# Convert CPU list to list of PGs 301*d3c97224SAlexander Kolbasov# 302*d3c97224SAlexander Kolbasovif (scalar @cpu_list) { 303*d3c97224SAlexander Kolbasov 304*d3c97224SAlexander Kolbasov # 305*d3c97224SAlexander Kolbasov # Warn about any invalid CPU IDs in the arguments 306*d3c97224SAlexander Kolbasov # @bad_cpus is a list of invalid CPU IDs 307*d3c97224SAlexander Kolbasov # 308*d3c97224SAlexander Kolbasov my @bad_cpus = $p->set_subtract(\@all_cpus, \@cpu_list); 309*d3c97224SAlexander Kolbasov if (scalar @bad_cpus) { 310*d3c97224SAlexander Kolbasov printf STDERR 311*d3c97224SAlexander Kolbasov gettext("%s: Invalid processor IDs %s\n"), 312*d3c97224SAlexander Kolbasov $cmdname, $p->id_collapse(@bad_cpus); 313*d3c97224SAlexander Kolbasov $rc = E_ERROR; 314*d3c97224SAlexander Kolbasov } 315*d3c97224SAlexander Kolbasov 316*d3c97224SAlexander Kolbasov # 317*d3c97224SAlexander Kolbasov # Find all PGs which have at least some CPUs from @cpu_list 318*d3c97224SAlexander Kolbasov # 319*d3c97224SAlexander Kolbasov my @pgs_from_cpus = grep { 320*d3c97224SAlexander Kolbasov my @cpus = $p->cpus($_); 321*d3c97224SAlexander Kolbasov scalar($p->intersect(\@cpus, \@cpu_list)); 322*d3c97224SAlexander Kolbasov } @all_pgs; 323*d3c97224SAlexander Kolbasov 324*d3c97224SAlexander Kolbasov # Combine PGs from @pg_list (if any) with PGs we found 325*d3c97224SAlexander Kolbasov @pg_list = (@pg_list, @pgs_from_cpus); 326*d3c97224SAlexander Kolbasov} 327*d3c97224SAlexander Kolbasov 328*d3c97224SAlexander Kolbasov# 329*d3c97224SAlexander Kolbasov# If there are any PGs specified by the user, complain about invalid ones 330*d3c97224SAlexander Kolbasov# 331*d3c97224SAlexander Kolbasov@pgs = get_pg_list($p, \@pg_list, \@sharing_filter, \@sharing_filter_neg); 332*d3c97224SAlexander Kolbasov 333*d3c97224SAlexander Kolbasovif (scalar @pg_list > 0) { 334*d3c97224SAlexander Kolbasov # 335*d3c97224SAlexander Kolbasov # Warn about any invalid PG 336*d3c97224SAlexander Kolbasov # @bad_pgs is a list of invalid CPUs in the arguments 337*d3c97224SAlexander Kolbasov # 338*d3c97224SAlexander Kolbasov my @bad_pgs = $p->set_subtract(\@all_pgs, \@pg_list); 339*d3c97224SAlexander Kolbasov if (scalar @bad_pgs) { 340*d3c97224SAlexander Kolbasov printf STDERR 341*d3c97224SAlexander Kolbasov gettext("%s: warning: invalid PG IDs %s\n"), 342*d3c97224SAlexander Kolbasov $cmdname, $p->id_collapse(@bad_pgs); 343*d3c97224SAlexander Kolbasov } 344*d3c97224SAlexander Kolbasov} 345*d3c97224SAlexander Kolbasov 346*d3c97224SAlexander Kolbasov# Do we have any PGs left? 347*d3c97224SAlexander Kolbasovif (scalar(@pgs) == 0) { 348*d3c97224SAlexander Kolbasov printf STDERR 349*d3c97224SAlexander Kolbasov gettext("%s: No processor groups matching command line arguments\n"), 350*d3c97224SAlexander Kolbasov $cmdname; 351*d3c97224SAlexander Kolbasov exit(E_USAGE); 352*d3c97224SAlexander Kolbasov} 353*d3c97224SAlexander Kolbasov 354*d3c97224SAlexander Kolbasov# 355*d3c97224SAlexander Kolbasov# Set $do_levels if we should provide output identation by level It doesn't make 356*d3c97224SAlexander Kolbasov# sense to provide identation if PGs are sorted not in topology order. 357*d3c97224SAlexander Kolbasov# 358*d3c97224SAlexander Kolbasovmy $do_levels = ($sort_key eq 'breadth' || $sort_key eq 'depth'); 359*d3c97224SAlexander Kolbasov 360*d3c97224SAlexander Kolbasov# 361*d3c97224SAlexander Kolbasov# %name_of_pg hash keeps sharing name, possibly with physical tags appended to 362*d3c97224SAlexander Kolbasov# it for each PG. 363*d3c97224SAlexander Kolbasov# 364*d3c97224SAlexander Kolbasovmy %name_of_pg; 365*d3c97224SAlexander Kolbasov 366*d3c97224SAlexander Kolbasov# 367*d3c97224SAlexander Kolbasov# For calculating proper offsets we need to know minimum and maximum level for 368*d3c97224SAlexander Kolbasov# all PGs 369*d3c97224SAlexander Kolbasov# 370*d3c97224SAlexander Kolbasovmy $max_sharename_len = length('RELATIONSHIP'); 371*d3c97224SAlexander Kolbasov 372*d3c97224SAlexander Kolbasovmy $maxlevel; 373*d3c97224SAlexander Kolbasovmy $minlevel; 374*d3c97224SAlexander Kolbasov 375*d3c97224SAlexander Kolbasovif ($do_levels) { 376*d3c97224SAlexander Kolbasov my @levels = map { $p->level($_) } @pgs; # Levels for each PG 377*d3c97224SAlexander Kolbasov $maxlevel = max(@levels); 378*d3c97224SAlexander Kolbasov $minlevel = min(@levels); 379*d3c97224SAlexander Kolbasov} 380*d3c97224SAlexander Kolbasov 381*d3c97224SAlexander Kolbasov# 382*d3c97224SAlexander Kolbasov# Walk over all PGs and find out the string length that we need to represent 383*d3c97224SAlexander Kolbasov# sharing name + physical tags + indentation level. 384*d3c97224SAlexander Kolbasov# 385*d3c97224SAlexander Kolbasovforeach my $pg (@pgs) { 386*d3c97224SAlexander Kolbasov my $name = $p->sh_name ($pg) || "unknown"; 387*d3c97224SAlexander Kolbasov my $level = $p->level($pg) || 0 if $do_levels; 388*d3c97224SAlexander Kolbasov 389*d3c97224SAlexander Kolbasov if ($do_physical) { 390*d3c97224SAlexander Kolbasov my $tags = $p->tags($pg); 391*d3c97224SAlexander Kolbasov $name = "$name [$tags]" if $tags; 392*d3c97224SAlexander Kolbasov $name_of_pg{$pg} = $name; 393*d3c97224SAlexander Kolbasov } 394*d3c97224SAlexander Kolbasov 395*d3c97224SAlexander Kolbasov $name_of_pg{$pg} = $name; 396*d3c97224SAlexander Kolbasov my $length = length($name); 397*d3c97224SAlexander Kolbasov $length += $level - $minlevel if $do_levels; 398*d3c97224SAlexander Kolbasov $max_sharename_len = $length if $length > $max_sharename_len; 399*d3c97224SAlexander Kolbasov} 400*d3c97224SAlexander Kolbasov 401*d3c97224SAlexander Kolbasov# Maximum length of PG ID field 402*d3c97224SAlexander Kolbasovmy $max_pg_len = length(max(@pgs)) + 1; 403*d3c97224SAlexander Kolbasov$max_pg_len = length('PG') if ($max_pg_len) < length('PG'); 404*d3c97224SAlexander Kolbasov 405*d3c97224SAlexander Kolbasov# 406*d3c97224SAlexander Kolbasov# 407*d3c97224SAlexander Kolbasov# %pgs hash contains various statistics per PG that is used for sorting. 408*d3c97224SAlexander Kolbasovmy %pgs; 409*d3c97224SAlexander Kolbasov 410*d3c97224SAlexander Kolbasov# Total number of main loop iterations we actually do 411*d3c97224SAlexander Kolbasovmy $total_iterations = 0; 412*d3c97224SAlexander Kolbasov 413*d3c97224SAlexander Kolbasov# 414*d3c97224SAlexander Kolbasov# For summary, keep track of minimum and maximum data per PG 415*d3c97224SAlexander Kolbasov# 416*d3c97224SAlexander Kolbasovmy $history; 417*d3c97224SAlexander Kolbasov 418*d3c97224SAlexander Kolbasov# 419*d3c97224SAlexander Kolbasov# Provide summary output when aggregation is requested and user hits ^C 420*d3c97224SAlexander Kolbasov# 421*d3c97224SAlexander Kolbasov$SIG{'INT'} = \&print_totals if $do_aggregate; 422*d3c97224SAlexander Kolbasov 423*d3c97224SAlexander Kolbasov###################################################################### 424*d3c97224SAlexander Kolbasov# Main loop 425*d3c97224SAlexander Kolbasov########### 426*d3c97224SAlexander Kolbasov 427*d3c97224SAlexander Kolbasovwhile ($infinite || $count--) { 428*d3c97224SAlexander Kolbasov # 429*d3c97224SAlexander Kolbasov # Print timestamp if -T is specified 430*d3c97224SAlexander Kolbasov # 431*d3c97224SAlexander Kolbasov if ($do_timestamp) { 432*d3c97224SAlexander Kolbasov if ($do_timestamp eq 'u') { 433*d3c97224SAlexander Kolbasov print time(), "\n"; 434*d3c97224SAlexander Kolbasov } else { 435*d3c97224SAlexander Kolbasov my $date_str = strftime "%A, %B %e, %Y %r %Z", 436*d3c97224SAlexander Kolbasov localtime; 437*d3c97224SAlexander Kolbasov print "$date_str\n"; 438*d3c97224SAlexander Kolbasov } 439*d3c97224SAlexander Kolbasov } 440*d3c97224SAlexander Kolbasov 441*d3c97224SAlexander Kolbasov # 442*d3c97224SAlexander Kolbasov # Wait for the requested interval 443*d3c97224SAlexander Kolbasov # 444*d3c97224SAlexander Kolbasov select(undef, undef, undef, $interval); 445*d3c97224SAlexander Kolbasov 446*d3c97224SAlexander Kolbasov # 447*d3c97224SAlexander Kolbasov # Print headers 448*d3c97224SAlexander Kolbasov # There are two different output formats - one regular and one verbose 449*d3c97224SAlexander Kolbasov # 450*d3c97224SAlexander Kolbasov if (!$verbose) { 451*d3c97224SAlexander Kolbasov printf "%-${max_pg_len}s %-${max_sharename_len}s ". 452*d3c97224SAlexander Kolbasov "$pcnt_fmt $pcnt_fmt %-s\n", 453*d3c97224SAlexander Kolbasov 'PG', 'RELATIONSHIP', 'HW', 'SW', 'CPUS'; 454*d3c97224SAlexander Kolbasov } else { 455*d3c97224SAlexander Kolbasov printf "%-${max_pg_len}s %-${max_sharename_len}s" . 456*d3c97224SAlexander Kolbasov " $pcnt_fmt %4s %4s $pcnt_fmt $pcnt_fmt $pcnt_fmt $pcnt_fmt %s\n", 457*d3c97224SAlexander Kolbasov 'PG','RELATIONSHIP', 458*d3c97224SAlexander Kolbasov 'HW', 'UTIL', 'CAP', 459*d3c97224SAlexander Kolbasov 'SW', 'USR', 'SYS', 'IDLE', 'CPUS'; 460*d3c97224SAlexander Kolbasov } 461*d3c97224SAlexander Kolbasov 462*d3c97224SAlexander Kolbasov # 463*d3c97224SAlexander Kolbasov # Update the data in one of the snapshots 464*d3c97224SAlexander Kolbasov # 465*d3c97224SAlexander Kolbasov $p_dup->update(); 466*d3c97224SAlexander Kolbasov 467*d3c97224SAlexander Kolbasov # 468*d3c97224SAlexander Kolbasov # Do not show offlined CPUs 469*d3c97224SAlexander Kolbasov # 470*d3c97224SAlexander Kolbasov my @online_cpus = $p->online_cpus(); 471*d3c97224SAlexander Kolbasov 472*d3c97224SAlexander Kolbasov # 473*d3c97224SAlexander Kolbasov # Check whether both snapshots belong to the same generation 474*d3c97224SAlexander Kolbasov # 475*d3c97224SAlexander Kolbasov if ($p->generation() != $p_dup->generation()) { 476*d3c97224SAlexander Kolbasov printf gettext("Configuration changed!\n"); 477*d3c97224SAlexander Kolbasov # Swap $p and $p_dup; 478*d3c97224SAlexander Kolbasov $p = $p_dup; 479*d3c97224SAlexander Kolbasov $p_dup = Sun::Solaris::Pg->new( 480*d3c97224SAlexander Kolbasov -cpudata => $do_cpu_utilization, 481*d3c97224SAlexander Kolbasov -swload => 1, 482*d3c97224SAlexander Kolbasov -tags => $do_physical, 483*d3c97224SAlexander Kolbasov -retry => RETRY_COUNT, 484*d3c97224SAlexander Kolbasov -delay => RETRY_DELAY); 485*d3c97224SAlexander Kolbasov if (!$p_dup) { 486*d3c97224SAlexander Kolbasov printf STDERR gettext( 487*d3c97224SAlexander Kolbasov "%s: can not obtain Processor Group information: $!\n"), 488*d3c97224SAlexander Kolbasov $cmdname; 489*d3c97224SAlexander Kolbasov exit(E_ERROR); 490*d3c97224SAlexander Kolbasov } 491*d3c97224SAlexander Kolbasov # 492*d3c97224SAlexander Kolbasov # Recreate @pg_list since it may have changed 493*d3c97224SAlexander Kolbasov # 494*d3c97224SAlexander Kolbasov @pgs = get_pg_list($p, \@pg_list, 495*d3c97224SAlexander Kolbasov \@sharing_filter, \@sharing_filter_neg); 496*d3c97224SAlexander Kolbasov 497*d3c97224SAlexander Kolbasov next; 498*d3c97224SAlexander Kolbasov } 499*d3c97224SAlexander Kolbasov 500*d3c97224SAlexander Kolbasov %pgs = (); 501*d3c97224SAlexander Kolbasov 502*d3c97224SAlexander Kolbasov # 503*d3c97224SAlexander Kolbasov # Go over each PG and gets its utilization data 504*d3c97224SAlexander Kolbasov # 505*d3c97224SAlexander Kolbasov foreach my $pg (@pgs) { 506*d3c97224SAlexander Kolbasov my ($hwload, $utilization, $capacity, $accuracy) = 507*d3c97224SAlexander Kolbasov get_load($p, $p_dup, $pg); 508*d3c97224SAlexander Kolbasov my @cpus = $p->cpus ($pg); 509*d3c97224SAlexander Kolbasov my ($user, $sys, $idle, $swload) = 510*d3c97224SAlexander Kolbasov $p->sw_utilization($p_dup, $pg); 511*d3c97224SAlexander Kolbasov 512*d3c97224SAlexander Kolbasov # Adjust idle and swload based on rounding 513*d3c97224SAlexander Kolbasov ($swload, $idle) = get_swload($user, $sys); 514*d3c97224SAlexander Kolbasov 515*d3c97224SAlexander Kolbasov $pgs{$pg}->{pg} = $pg; 516*d3c97224SAlexander Kolbasov $pgs{$pg}->{hwload} = $hwload; 517*d3c97224SAlexander Kolbasov $pgs{$pg}->{swload} = $swload; 518*d3c97224SAlexander Kolbasov $pgs{$pg}->{user} = $user; 519*d3c97224SAlexander Kolbasov $pgs{$pg}->{sys} = $sys; 520*d3c97224SAlexander Kolbasov $pgs{$pg}->{idle} = $idle; 521*d3c97224SAlexander Kolbasov $pgs{$pg}->{utilization} = $utilization; 522*d3c97224SAlexander Kolbasov $pgs{$pg}->{capacity} = $capacity; 523*d3c97224SAlexander Kolbasov 524*d3c97224SAlexander Kolbasov # 525*d3c97224SAlexander Kolbasov # Record history 526*d3c97224SAlexander Kolbasov # 527*d3c97224SAlexander Kolbasov $history->{$pg}->{hwload} += $hwload if $hwload && $hwload >= 0; 528*d3c97224SAlexander Kolbasov $history->{$pg}->{swload} += $swload if $swload; 529*d3c97224SAlexander Kolbasov $history->{$pg}->{user} += $user if $user; 530*d3c97224SAlexander Kolbasov $history->{$pg}->{sys} += $sys if $sys; 531*d3c97224SAlexander Kolbasov $history->{$pg}->{idle} += $idle if $idle; 532*d3c97224SAlexander Kolbasov $history->{$pg}->{maxhwload} = $hwload if 533*d3c97224SAlexander Kolbasov !defined($history->{$pg}->{maxhwload}) || 534*d3c97224SAlexander Kolbasov $hwload > $history->{$pg}->{maxhwload}; 535*d3c97224SAlexander Kolbasov $history->{$pg}->{minhwload} = $hwload if 536*d3c97224SAlexander Kolbasov !defined($history->{$pg}->{minhwload}) || 537*d3c97224SAlexander Kolbasov $hwload < $history->{$pg}->{minhwload}; 538*d3c97224SAlexander Kolbasov $history->{$pg}->{maxswload} = $swload if 539*d3c97224SAlexander Kolbasov !defined($history->{$pg}->{maxswload}) || 540*d3c97224SAlexander Kolbasov $swload > $history->{$pg}->{maxswload}; 541*d3c97224SAlexander Kolbasov $history->{$pg}->{minswload} = $swload if 542*d3c97224SAlexander Kolbasov !defined($history->{$pg}->{minswload}) || 543*d3c97224SAlexander Kolbasov $swload < $history->{$pg}->{minswload}; 544*d3c97224SAlexander Kolbasov } 545*d3c97224SAlexander Kolbasov 546*d3c97224SAlexander Kolbasov # 547*d3c97224SAlexander Kolbasov # Sort the output 548*d3c97224SAlexander Kolbasov # 549*d3c97224SAlexander Kolbasov my @sorted_pgs; 550*d3c97224SAlexander Kolbasov my $npgs = scalar @pgs; 551*d3c97224SAlexander Kolbasov @sorted_pgs = pg_sort_by_key(\%pgs, $sort_key, $sort_reverse, @pgs); 552*d3c97224SAlexander Kolbasov 553*d3c97224SAlexander Kolbasov # 554*d3c97224SAlexander Kolbasov # Should only top N be displayed? 555*d3c97224SAlexander Kolbasov # 556*d3c97224SAlexander Kolbasov if ($show_top) { 557*d3c97224SAlexander Kolbasov $npgs = $show_top if $show_top < $npgs; 558*d3c97224SAlexander Kolbasov @sorted_pgs = @sorted_pgs[0..$npgs - 1]; 559*d3c97224SAlexander Kolbasov } 560*d3c97224SAlexander Kolbasov 561*d3c97224SAlexander Kolbasov # 562*d3c97224SAlexander Kolbasov # Now print everything 563*d3c97224SAlexander Kolbasov # 564*d3c97224SAlexander Kolbasov foreach my $pg (@sorted_pgs) { 565*d3c97224SAlexander Kolbasov my $shname = $name_of_pg{$pg}; 566*d3c97224SAlexander Kolbasov my $level; 567*d3c97224SAlexander Kolbasov 568*d3c97224SAlexander Kolbasov if ($do_levels) { 569*d3c97224SAlexander Kolbasov $level = $p->level($pg) - $minlevel; 570*d3c97224SAlexander Kolbasov $shname = (' ' x (LEVEL_OFFSET * $level)) . $shname; 571*d3c97224SAlexander Kolbasov } 572*d3c97224SAlexander Kolbasov 573*d3c97224SAlexander Kolbasov my $hwload = $pgs{$pg}->{hwload} || 0; 574*d3c97224SAlexander Kolbasov my $swload = $pgs{$pg}->{swload}; 575*d3c97224SAlexander Kolbasov 576*d3c97224SAlexander Kolbasov my @cpus = $p->cpus($pg); 577*d3c97224SAlexander Kolbasov @cpus = $p->intersect(\@cpus, \@online_cpus); 578*d3c97224SAlexander Kolbasov 579*d3c97224SAlexander Kolbasov my $cpus = $p->id_collapse(@cpus); 580*d3c97224SAlexander Kolbasov my $user = $pgs{$pg}->{user}; 581*d3c97224SAlexander Kolbasov my $sys = $pgs{$pg}->{sys}; 582*d3c97224SAlexander Kolbasov my $idle = $pgs{$pg}->{idle}; 583*d3c97224SAlexander Kolbasov my $utilization = $pgs{$pg}->{utilization}; 584*d3c97224SAlexander Kolbasov my $capacity = $pgs{$pg}->{capacity}; 585*d3c97224SAlexander Kolbasov 586*d3c97224SAlexander Kolbasov if (!$verbose) { 587*d3c97224SAlexander Kolbasov printf "%${max_pg_len}d %-${max_sharename_len}s " . 588*d3c97224SAlexander Kolbasov "%s %s %s\n", 589*d3c97224SAlexander Kolbasov $pg, $shname, 590*d3c97224SAlexander Kolbasov load2str($hwload), 591*d3c97224SAlexander Kolbasov load2str($swload), 592*d3c97224SAlexander Kolbasov $cpus; 593*d3c97224SAlexander Kolbasov } else { 594*d3c97224SAlexander Kolbasov printf 595*d3c97224SAlexander Kolbasov "%${max_pg_len}d %-${max_sharename_len}s " . 596*d3c97224SAlexander Kolbasov "%4s %4s %4s %4s %4s %4s %4s %s\n", 597*d3c97224SAlexander Kolbasov $pg, $shname, 598*d3c97224SAlexander Kolbasov load2str($hwload), 599*d3c97224SAlexander Kolbasov number_to_scaled_string($utilization), 600*d3c97224SAlexander Kolbasov number_to_scaled_string($capacity), 601*d3c97224SAlexander Kolbasov load2str($swload), 602*d3c97224SAlexander Kolbasov load2str($user), 603*d3c97224SAlexander Kolbasov load2str($sys), 604*d3c97224SAlexander Kolbasov load2str($idle), 605*d3c97224SAlexander Kolbasov $cpus; 606*d3c97224SAlexander Kolbasov } 607*d3c97224SAlexander Kolbasov 608*d3c97224SAlexander Kolbasov # 609*d3c97224SAlexander Kolbasov # If per-CPU utilization is requested, print it after each 610*d3c97224SAlexander Kolbasov # corresponding PG 611*d3c97224SAlexander Kolbasov # 612*d3c97224SAlexander Kolbasov if ($do_cpu_utilization) { 613*d3c97224SAlexander Kolbasov my $w = ${max_sharename_len} - length ('CPU'); 614*d3c97224SAlexander Kolbasov foreach my $cpu (sort {$a <=> $b } @cpus) { 615*d3c97224SAlexander Kolbasov my ($cpu_utilization, 616*d3c97224SAlexander Kolbasov $accuracy, $hw_utilization, 617*d3c97224SAlexander Kolbasov $swload) = 618*d3c97224SAlexander Kolbasov $p->cpu_utilization($p_dup, $pg, $cpu); 619*d3c97224SAlexander Kolbasov next unless defined $cpu_utilization; 620*d3c97224SAlexander Kolbasov my $cpuname = "CPU$cpu"; 621*d3c97224SAlexander Kolbasov if ($do_levels) { 622*d3c97224SAlexander Kolbasov $cpuname = 623*d3c97224SAlexander Kolbasov (' ' x (LEVEL_OFFSET * $level)) . 624*d3c97224SAlexander Kolbasov $cpuname; 625*d3c97224SAlexander Kolbasov 626*d3c97224SAlexander Kolbasov } 627*d3c97224SAlexander Kolbasov 628*d3c97224SAlexander Kolbasov printf "%-${max_pg_len}s " . 629*d3c97224SAlexander Kolbasov "%-${max_sharename_len}s ", 630*d3c97224SAlexander Kolbasov ' ', $cpuname; 631*d3c97224SAlexander Kolbasov if ($verbose) { 632*d3c97224SAlexander Kolbasov printf "%s %4s %4s\n", 633*d3c97224SAlexander Kolbasov load2str($cpu_utilization), 634*d3c97224SAlexander Kolbasov number_to_scaled_string($hw_utilization), 635*d3c97224SAlexander Kolbasov number_to_scaled_string($capacity); 636*d3c97224SAlexander Kolbasov } else { 637*d3c97224SAlexander Kolbasov printf "%s %s\n", 638*d3c97224SAlexander Kolbasov load2str($cpu_utilization), 639*d3c97224SAlexander Kolbasov load2str($swload); 640*d3c97224SAlexander Kolbasov } 641*d3c97224SAlexander Kolbasov } 642*d3c97224SAlexander Kolbasov } 643*d3c97224SAlexander Kolbasov } 644*d3c97224SAlexander Kolbasov 645*d3c97224SAlexander Kolbasov # 646*d3c97224SAlexander Kolbasov # Swap $p and $p_dup 647*d3c97224SAlexander Kolbasov # 648*d3c97224SAlexander Kolbasov ($p, $p_dup) = ($p_dup, $p); 649*d3c97224SAlexander Kolbasov 650*d3c97224SAlexander Kolbasov $total_iterations++; 651*d3c97224SAlexander Kolbasov} 652*d3c97224SAlexander Kolbasov 653*d3c97224SAlexander Kolbasovprint_totals() if $do_aggregate; 654*d3c97224SAlexander Kolbasov 655*d3c97224SAlexander Kolbasov 656*d3c97224SAlexander Kolbasov#################################### 657*d3c97224SAlexander Kolbasov# End of main loop 658*d3c97224SAlexander Kolbasov#################################### 659*d3c97224SAlexander Kolbasov 660*d3c97224SAlexander Kolbasov 661*d3c97224SAlexander Kolbasov# 662*d3c97224SAlexander Kolbasov# Support Subroutines 663*d3c97224SAlexander Kolbasov# 664*d3c97224SAlexander Kolbasov 665*d3c97224SAlexander Kolbasov# 666*d3c97224SAlexander Kolbasov# Print aggregated information in the end 667*d3c97224SAlexander Kolbasov# 668*d3c97224SAlexander Kolbasovsub print_totals 669*d3c97224SAlexander Kolbasov{ 670*d3c97224SAlexander Kolbasov exit ($rc) unless $total_iterations > 1; 671*d3c97224SAlexander Kolbasov 672*d3c97224SAlexander Kolbasov printf gettext("\n%s SUMMARY: UTILIZATION OVER %d SECONDS\n\n"), 673*d3c97224SAlexander Kolbasov ' ' x 10, 674*d3c97224SAlexander Kolbasov $total_iterations * $interval; 675*d3c97224SAlexander Kolbasov 676*d3c97224SAlexander Kolbasov my @sorted_pgs; 677*d3c97224SAlexander Kolbasov my $npgs = scalar @pgs; 678*d3c97224SAlexander Kolbasov 679*d3c97224SAlexander Kolbasov %pgs = (); 680*d3c97224SAlexander Kolbasov 681*d3c97224SAlexander Kolbasov # 682*d3c97224SAlexander Kolbasov # Collect data per PG 683*d3c97224SAlexander Kolbasov # 684*d3c97224SAlexander Kolbasov foreach my $pg (@pgs) { 685*d3c97224SAlexander Kolbasov $pgs{$pg}->{pg} = $pg; 686*d3c97224SAlexander Kolbasov 687*d3c97224SAlexander Kolbasov my ($hwload, $utilization, $capacity, $accuracy) = 688*d3c97224SAlexander Kolbasov get_load($p_initial, $p_dup, $pg); 689*d3c97224SAlexander Kolbasov 690*d3c97224SAlexander Kolbasov my @cpus = $p->cpus ($pg); 691*d3c97224SAlexander Kolbasov my ($user, $sys, $idle, $swload) = 692*d3c97224SAlexander Kolbasov $p_dup->sw_utilization($p_initial, $pg); 693*d3c97224SAlexander Kolbasov 694*d3c97224SAlexander Kolbasov # Adjust idle and swload based on rounding 695*d3c97224SAlexander Kolbasov ($swload, $idle) = get_swload($user, $sys); 696*d3c97224SAlexander Kolbasov 697*d3c97224SAlexander Kolbasov $pgs{$pg}->{pg} = $pg; 698*d3c97224SAlexander Kolbasov $pgs{$pg}->{swload} = $swload; 699*d3c97224SAlexander Kolbasov $pgs{$pg}->{user} = $user; 700*d3c97224SAlexander Kolbasov $pgs{$pg}->{sys} = $sys; 701*d3c97224SAlexander Kolbasov $pgs{$pg}->{idle} = $idle; 702*d3c97224SAlexander Kolbasov $pgs{$pg}->{hwload} = $hwload; 703*d3c97224SAlexander Kolbasov $pgs{$pg}->{utilization} = number_to_scaled_string($utilization); 704*d3c97224SAlexander Kolbasov $pgs{$pg}->{capacity} = number_to_scaled_string($capacity); 705*d3c97224SAlexander Kolbasov $pgs{$pg}->{minhwload} = $history->{$pg}->{minhwload}; 706*d3c97224SAlexander Kolbasov $pgs{$pg}->{maxhwload} = $history->{$pg}->{maxhwload}; 707*d3c97224SAlexander Kolbasov $pgs{$pg}->{minswload} = $history->{$pg}->{minswload} || 0; 708*d3c97224SAlexander Kolbasov $pgs{$pg}->{maxswload} = $history->{$pg}->{maxswload} || 0; 709*d3c97224SAlexander Kolbasov } 710*d3c97224SAlexander Kolbasov 711*d3c97224SAlexander Kolbasov # 712*d3c97224SAlexander Kolbasov # Sort PGs according to the sorting options 713*d3c97224SAlexander Kolbasov # 714*d3c97224SAlexander Kolbasov @sorted_pgs = pg_sort_by_key(\%pgs, $sort_key, $sort_reverse, @pgs); 715*d3c97224SAlexander Kolbasov 716*d3c97224SAlexander Kolbasov # 717*d3c97224SAlexander Kolbasov # Trim to top N if needed 718*d3c97224SAlexander Kolbasov # 719*d3c97224SAlexander Kolbasov if ($show_top) { 720*d3c97224SAlexander Kolbasov $npgs = $show_top if $show_top < $npgs; 721*d3c97224SAlexander Kolbasov @sorted_pgs = @sorted_pgs[0..$npgs - 1]; 722*d3c97224SAlexander Kolbasov } 723*d3c97224SAlexander Kolbasov 724*d3c97224SAlexander Kolbasov # 725*d3c97224SAlexander Kolbasov # Print headers 726*d3c97224SAlexander Kolbasov # 727*d3c97224SAlexander Kolbasov my $d = ' ' . '-' x 4; 728*d3c97224SAlexander Kolbasov if ($verbose) { 729*d3c97224SAlexander Kolbasov printf "%${max_pg_len}s %-${max_sharename_len}s %s " . 730*d3c97224SAlexander Kolbasov " ------HARDWARE------ ------SOFTWARE------\n", 731*d3c97224SAlexander Kolbasov ' ', ' ', ' ' x 8; 732*d3c97224SAlexander Kolbasov 733*d3c97224SAlexander Kolbasov printf "%-${max_pg_len}s %-${max_sharename_len}s", 734*d3c97224SAlexander Kolbasov 'PG', 'RELATIONSHIP'; 735*d3c97224SAlexander Kolbasov 736*d3c97224SAlexander Kolbasov printf " %4s %4s", 'UTIL', ' CAP'; 737*d3c97224SAlexander Kolbasov printf " $pcnt_fmt $pcnt_fmt $pcnt_fmt $pcnt_fmt $pcnt_fmt $pcnt_fmt %s\n", 738*d3c97224SAlexander Kolbasov 'MIN', 'AVG', 'MAX', 'MIN', 'AVG', 'MAX', 'CPUS'; 739*d3c97224SAlexander Kolbasov } else { 740*d3c97224SAlexander Kolbasov printf "%${max_pg_len}s %-${max_sharename_len}s " . 741*d3c97224SAlexander Kolbasov "------HARDWARE------" . 742*d3c97224SAlexander Kolbasov " ------SOFTWARE------\n", ' ', ' '; 743*d3c97224SAlexander Kolbasov 744*d3c97224SAlexander Kolbasov printf "%-${max_pg_len}s %-${max_sharename_len}s", 745*d3c97224SAlexander Kolbasov 'PG', 'RELATIONSHIP'; 746*d3c97224SAlexander Kolbasov 747*d3c97224SAlexander Kolbasov printf " $pcnt_fmt $pcnt_fmt $pcnt_fmt $pcnt_fmt $pcnt_fmt $pcnt_fmt %s\n", 748*d3c97224SAlexander Kolbasov 'MIN', 'AVG', 'MAX', 'MIN', 'AVG', 'MAX', 'CPUS'; 749*d3c97224SAlexander Kolbasov } 750*d3c97224SAlexander Kolbasov 751*d3c97224SAlexander Kolbasov # 752*d3c97224SAlexander Kolbasov # Print information per PG 753*d3c97224SAlexander Kolbasov # 754*d3c97224SAlexander Kolbasov foreach my $pg (@sorted_pgs) { 755*d3c97224SAlexander Kolbasov my $cpus = $p->cpus($pg); 756*d3c97224SAlexander Kolbasov 757*d3c97224SAlexander Kolbasov my $shname = $name_of_pg{$pg}; 758*d3c97224SAlexander Kolbasov if ($sort_key eq 'breadth' || $sort_key eq 'depth') { 759*d3c97224SAlexander Kolbasov my $level = $p->level($pg) - $minlevel; 760*d3c97224SAlexander Kolbasov $shname = (' ' x (LEVEL_OFFSET * $level)) . $shname; 761*d3c97224SAlexander Kolbasov } 762*d3c97224SAlexander Kolbasov 763*d3c97224SAlexander Kolbasov printf "%${max_pg_len}d %-${max_sharename_len}s ", 764*d3c97224SAlexander Kolbasov $pg, $shname; 765*d3c97224SAlexander Kolbasov 766*d3c97224SAlexander Kolbasov if ($verbose) { 767*d3c97224SAlexander Kolbasov printf "%4s %4s ", 768*d3c97224SAlexander Kolbasov number_to_scaled_string($pgs{$pg}->{utilization}), 769*d3c97224SAlexander Kolbasov number_to_scaled_string($pgs{$pg}->{capacity}); 770*d3c97224SAlexander Kolbasov } 771*d3c97224SAlexander Kolbasov 772*d3c97224SAlexander Kolbasov if (!defined($pgs{$pg}->{hwload}) || 773*d3c97224SAlexander Kolbasov $pgs{$pg}->{hwload} == HWLOAD_UNDEF) { 774*d3c97224SAlexander Kolbasov printf "$pcnt_fmt $pcnt_fmt $pcnt_fmt ", 775*d3c97224SAlexander Kolbasov '-', '-', '-'; 776*d3c97224SAlexander Kolbasov } else { 777*d3c97224SAlexander Kolbasov printf "%s %s %s ", 778*d3c97224SAlexander Kolbasov load2str($pgs{$pg}->{minhwload}), 779*d3c97224SAlexander Kolbasov load2str($pgs{$pg}->{hwload}), 780*d3c97224SAlexander Kolbasov load2str($pgs{$pg}->{maxhwload}); 781*d3c97224SAlexander Kolbasov } 782*d3c97224SAlexander Kolbasov printf "%s %s %s", 783*d3c97224SAlexander Kolbasov load2str($pgs{$pg}->{minswload}), 784*d3c97224SAlexander Kolbasov load2str($pgs{$pg}->{swload}), 785*d3c97224SAlexander Kolbasov load2str($pgs{$pg}->{maxswload}); 786*d3c97224SAlexander Kolbasov 787*d3c97224SAlexander Kolbasov printf " %s\n", $cpus; 788*d3c97224SAlexander Kolbasov } 789*d3c97224