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# pginfo - tool for displaying Processor Group information 29*d3c97224SAlexander Kolbasov# 30*d3c97224SAlexander Kolbasov 31*d3c97224SAlexander Kolbasovuse warnings; 32*d3c97224SAlexander Kolbasovuse strict; 33*d3c97224SAlexander Kolbasovuse File::Basename; 34*d3c97224SAlexander Kolbasovuse Errno; 35*d3c97224SAlexander Kolbasovuse POSIX qw(locale_h); 36*d3c97224SAlexander Kolbasovuse Getopt::Long qw(:config no_ignore_case bundling auto_version); 37*d3c97224SAlexander Kolbasovuse List::Util qw(first max min); 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 43*d3c97224SAlexander Kolbasov# 44*d3c97224SAlexander Kolbasov# It is possible that wnen trying to parse PG information, 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 Kolbasovuse constant { 59*d3c97224SAlexander Kolbasov VERSION => 1.1, 60*d3c97224SAlexander Kolbasov LEVEL_OFFSET => 1, 61*d3c97224SAlexander Kolbasov RETRY_COUNT => 4, 62*d3c97224SAlexander Kolbasov RETRY_DELAY => 0.25, 63*d3c97224SAlexander Kolbasov}; 64*d3c97224SAlexander Kolbasov 65*d3c97224SAlexander Kolbasov# 66*d3c97224SAlexander Kolbasov# Return codes 67*d3c97224SAlexander Kolbasov# 68*d3c97224SAlexander Kolbasov# 0 Successful completion. 69*d3c97224SAlexander Kolbasov# 70*d3c97224SAlexander Kolbasov# 1 An error occurred. 71*d3c97224SAlexander Kolbasov# 72*d3c97224SAlexander Kolbasov# 2 Invalid command-line options were specified. 73*d3c97224SAlexander Kolbasov# 74*d3c97224SAlexander Kolbasovuse constant { 75*d3c97224SAlexander Kolbasov E_SUCCESS => 0, 76*d3c97224SAlexander Kolbasov E_ERROR => 1, 77*d3c97224SAlexander Kolbasov E_USAGE => 2, 78*d3c97224SAlexander Kolbasov}; 79*d3c97224SAlexander Kolbasov 80*d3c97224SAlexander Kolbasov 81*d3c97224SAlexander Kolbasov# Set message locale 82*d3c97224SAlexander Kolbasovsetlocale(LC_ALL, ""); 83*d3c97224SAlexander Kolbasovtextdomain(TEXT_DOMAIN); 84*d3c97224SAlexander Kolbasov 85*d3c97224SAlexander Kolbasov# Get script name for error messages 86*d3c97224SAlexander Kolbasovour $cmdname = basename($0, ".pl"); 87*d3c97224SAlexander Kolbasov 88*d3c97224SAlexander Kolbasov# 89*d3c97224SAlexander Kolbasov# Process options 90*d3c97224SAlexander Kolbasov# 91*d3c97224SAlexander Kolbasovmy $do_cpulist; # -C - Show CPU IDs 92*d3c97224SAlexander Kolbasovmy $do_cpus; # -c - Treat args as CPU IDs 93*d3c97224SAlexander Kolbasovmy $do_physical; # -p - Show physical relationships 94*d3c97224SAlexander Kolbasovmy $do_sharing_only; # -S - Only show sharing relationships 95*d3c97224SAlexander Kolbasovmy $do_tree; # -T - Show ASCII tree 96*d3c97224SAlexander Kolbasovmy $do_usage; # -h - Show usage 97*d3c97224SAlexander Kolbasovmy $do_version; # -V - Show version 98*d3c97224SAlexander Kolbasovmy $script_mode; # -I - Only show IDs 99*d3c97224SAlexander Kolbasovmy $verbose = 0; # -v - Verbose output 100*d3c97224SAlexander Kolbasovmy @sharing_filter; # -r string,... 101*d3c97224SAlexander Kolbasovmy @sharing_filter_neg; # -R string,... 102*d3c97224SAlexander Kolbasov 103*d3c97224SAlexander Kolbasov# Exit code 104*d3c97224SAlexander Kolbasovmy $rc = E_SUCCESS; 105*d3c97224SAlexander Kolbasov 106*d3c97224SAlexander Kolbasov# Parse options from the command line 107*d3c97224SAlexander KolbasovGetOptions("cpus|c" => \$do_cpus, 108*d3c97224SAlexander Kolbasov "idlist|I" => \$script_mode, 109*d3c97224SAlexander Kolbasov "cpulist|C" => \$do_cpulist, 110*d3c97224SAlexander Kolbasov "physical|p" => \$do_physical, 111*d3c97224SAlexander Kolbasov "help|h|?" => \$do_usage, 112*d3c97224SAlexander Kolbasov "sharing|s" => \$do_sharing_only, 113*d3c97224SAlexander Kolbasov "relationship|r=s" => \@sharing_filter, 114*d3c97224SAlexander Kolbasov "norelationship|R=s" => \@sharing_filter_neg, 115*d3c97224SAlexander Kolbasov "tree|topology|T" => \$do_tree, 116*d3c97224SAlexander Kolbasov "version|V" => \$do_version, 117*d3c97224SAlexander Kolbasov "verbose+" => \$verbose, 118*d3c97224SAlexander Kolbasov "v+" => \$verbose, 119*d3c97224SAlexander Kolbasov) || usage(E_USAGE); 120*d3c97224SAlexander Kolbasov 121*d3c97224SAlexander Kolbasov# Print usage message when -h is given 122*d3c97224SAlexander Kolbasovusage(E_SUCCESS) if $do_usage; 123*d3c97224SAlexander Kolbasov 124*d3c97224SAlexander Kolbasovif ($do_version) { 125*d3c97224SAlexander Kolbasov # 126*d3c97224SAlexander Kolbasov # Print version information and exit 127*d3c97224SAlexander Kolbasov # 128*d3c97224SAlexander Kolbasov printf gettext("%s version %s\n"), $cmdname, VERSION; 129*d3c97224SAlexander Kolbasov exit(E_SUCCESS); 130*d3c97224SAlexander Kolbasov} 131*d3c97224SAlexander Kolbasov 132*d3c97224SAlexander Kolbasov# 133*d3c97224SAlexander Kolbasov# Verify options compatibility 134*d3c97224SAlexander Kolbasov# 135*d3c97224SAlexander Kolbasovif ($script_mode && $do_cpulist) { 136*d3c97224SAlexander Kolbasov printf STDERR 137*d3c97224SAlexander Kolbasov gettext("%s: options -I and -C can not be used at the same time\n"), 138*d3c97224SAlexander Kolbasov $cmdname; 139*d3c97224SAlexander Kolbasov usage(E_USAGE); 140*d3c97224SAlexander Kolbasov} 141*d3c97224SAlexander Kolbasov 142*d3c97224SAlexander Kolbasovif (($script_mode || $do_cpulist) && 143*d3c97224SAlexander Kolbasov ($do_physical || $do_sharing_only || 144*d3c97224SAlexander Kolbasov $do_tree)) { 145*d3c97224SAlexander Kolbasov printf STDERR 146*d3c97224SAlexander Kolbasov gettext("%s: options -C and -I can not be used with -p -s or -T\n"), 147*d3c97224SAlexander Kolbasov $cmdname; 148*d3c97224SAlexander Kolbasov usage(E_USAGE); 149*d3c97224SAlexander Kolbasov} 150*d3c97224SAlexander Kolbasov 151*d3c97224SAlexander Kolbasovif ($do_physical && $do_sharing_only) { 152*d3c97224SAlexander Kolbasov printf STDERR 153*d3c97224SAlexander Kolbasov gettext("%s: option -p can not be used with -s\n"), $cmdname; 154*d3c97224SAlexander Kolbasov usage(E_USAGE); 155*d3c97224SAlexander Kolbasov} 156*d3c97224SAlexander Kolbasov 157*d3c97224SAlexander Kolbasovif ($do_tree && $do_sharing_only) { 158*d3c97224SAlexander Kolbasov printf STDERR 159*d3c97224SAlexander Kolbasov gettext("%s: option -T can not be used with -s\n"), 160*d3c97224SAlexander Kolbasov $cmdname; 161*d3c97224SAlexander Kolbasov usage(E_USAGE); 162*d3c97224SAlexander Kolbasov} 163*d3c97224SAlexander Kolbasov 164*d3c97224SAlexander Kolbasovif ($verbose && !($script_mode || $do_cpulist || $do_sharing_only)) { 165*d3c97224SAlexander Kolbasov $do_tree = 1; 166*d3c97224SAlexander Kolbasov $do_physical = 1; 167*d3c97224SAlexander Kolbasov} 168*d3c97224SAlexander Kolbasov 169*d3c97224SAlexander Kolbasov# 170*d3c97224SAlexander Kolbasov# Get PG information 171*d3c97224SAlexander Kolbasov# 172*d3c97224SAlexander Kolbasovmy $p = Sun::Solaris::Pg->new(-tags => $do_physical, 173*d3c97224SAlexander Kolbasov -retry => RETRY_COUNT, 174*d3c97224SAlexander Kolbasov '-delay' => RETRY_DELAY); 175*d3c97224SAlexander Kolbasov 176*d3c97224SAlexander Kolbasovif (!$p) { 177*d3c97224SAlexander Kolbasov printf STDERR 178*d3c97224SAlexander Kolbasov gettext("%s: can not obtain Processor Group information: $!\n"), 179*d3c97224SAlexander Kolbasov $cmdname; 180*d3c97224SAlexander Kolbasov exit(E_ERROR); 181*d3c97224SAlexander Kolbasov} 182*d3c97224SAlexander Kolbasov 183*d3c97224SAlexander Kolbasov# 184*d3c97224SAlexander Kolbasov# Convert -[Rr] string1,string2,... into list (string1, string2, ...) 185*d3c97224SAlexander Kolbasov# 186*d3c97224SAlexander Kolbasov@sharing_filter = map { split /,/ } @sharing_filter; 187*d3c97224SAlexander Kolbasov@sharing_filter_neg = map { split /,/ } @sharing_filter_neg; 188*d3c97224SAlexander Kolbasov 189*d3c97224SAlexander Kolbasov# 190*d3c97224SAlexander Kolbasov# Get list of all PGs in the system 191*d3c97224SAlexander Kolbasov# 192*d3c97224SAlexander Kolbasovmy @all_pgs = $p->all_depth_first(); 193*d3c97224SAlexander Kolbasov 194*d3c97224SAlexander Kolbasovif (scalar(@all_pgs) == 0) { 195*d3c97224SAlexander Kolbasov printf STDERR 196*d3c97224SAlexander Kolbasov gettext("%s: this system does not have any Processor groups\n"), 197*d3c97224SAlexander Kolbasov $cmdname; 198*d3c97224SAlexander Kolbasov exit(E_ERROR); 199*d3c97224SAlexander Kolbasov} 200*d3c97224SAlexander Kolbasov 201*d3c97224SAlexander Kolbasov# 202*d3c97224SAlexander Kolbasov# @pgs is the list of PGs we are going to work with after all the option 203*d3c97224SAlexander Kolbasov# processing 204*d3c97224SAlexander Kolbasov# 205*d3c97224SAlexander Kolbasovmy @pgs = @all_pgs; 206*d3c97224SAlexander Kolbasov 207*d3c97224SAlexander Kolbasov# 208*d3c97224SAlexander Kolbasov# get list of all CPUs in the system by looking at the root PG cpus 209*d3c97224SAlexander Kolbasov# 210*d3c97224SAlexander Kolbasovmy @all_cpus = $p->cpus($p->root()); 211*d3c97224SAlexander Kolbasov 212*d3c97224SAlexander Kolbasov# 213*d3c97224SAlexander Kolbasov# If there are arguments in the command line, treat them as either PG IDs or as 214*d3c97224SAlexander Kolbasov# CPUs that should be converted to PG IDs. 215*d3c97224SAlexander Kolbasov# Arguments can be specified as x-y x,y,z and use special keyword 'all' 216*d3c97224SAlexander Kolbasov# 217*d3c97224SAlexander Kolbasovif (scalar @ARGV) { 218*d3c97224SAlexander Kolbasov # 219*d3c97224SAlexander Kolbasov # Convert 'all' in arguments to all CPUs or all PGs 220*d3c97224SAlexander Kolbasov # 221*d3c97224SAlexander Kolbasov my @args; 222*d3c97224SAlexander Kolbasov my @all = $do_cpus ? @all_cpus : @all_pgs; 223*d3c97224SAlexander Kolbasov @args = map { $_ eq 'all' ? @all : $_ } @ARGV; 224*d3c97224SAlexander Kolbasov 225*d3c97224SAlexander Kolbasov # Expand any x-y,z ranges 226*d3c97224SAlexander Kolbasov @args = $p->expand(@args); 227*d3c97224SAlexander Kolbasov 228*d3c97224SAlexander Kolbasov if ($do_cpus) { 229*d3c97224SAlexander Kolbasov # @bad_cpus is a list of invalid CPU IDs 230*d3c97224SAlexander Kolbasov my @bad_cpus = $p->set_subtract(\@all_cpus, \@args); 231*d3c97224SAlexander Kolbasov if (scalar @bad_cpus) { 232*d3c97224SAlexander Kolbasov printf STDERR 233*d3c97224SAlexander Kolbasov gettext("%s: Invalid processor IDs %s\n"), 234*d3c97224SAlexander Kolbasov $cmdname, $p->id_collapse(@bad_cpus); 235*d3c97224SAlexander Kolbasov $rc = E_ERROR; 236*d3c97224SAlexander Kolbasov } 237*d3c97224SAlexander Kolbasov # 238*d3c97224SAlexander Kolbasov # List of PGs is the list of any PGs that contain specified CPUs 239*d3c97224SAlexander Kolbasov # 240*d3c97224SAlexander Kolbasov @pgs = grep { 241*d3c97224SAlexander Kolbasov my @cpus = $p->cpus($_); 242*d3c97224SAlexander Kolbasov scalar($p->intersect(\@cpus, \@args)); 243*d3c97224SAlexander Kolbasov } @all_pgs; 244*d3c97224SAlexander Kolbasov } else { 245*d3c97224SAlexander Kolbasov # @pgs is a list of valid CPUs in the arguments 246*d3c97224SAlexander Kolbasov @pgs = $p->intersect(\@all_pgs, \@args); 247*d3c97224SAlexander Kolbasov # @bad_pgs is a list of invalid PG IDs 248*d3c97224SAlexander Kolbasov my @bad_pgs = $p->set_subtract(\@all_pgs, \@args); 249*d3c97224SAlexander Kolbasov if (scalar @bad_pgs) { 250*d3c97224SAlexander Kolbasov printf STDERR 251*d3c97224SAlexander Kolbasov gettext("%s: Invalid PG IDs %s\n"), 252*d3c97224SAlexander Kolbasov $cmdname, $p->id_collapse(@bad_pgs); 253*d3c97224SAlexander Kolbasov $rc = E_ERROR; 254*d3c97224SAlexander Kolbasov } 255*d3c97224SAlexander Kolbasov } 256*d3c97224SAlexander Kolbasov} 257*d3c97224SAlexander Kolbasov 258*d3c97224SAlexander Kolbasov# 259*d3c97224SAlexander Kolbasov# Now we have list of PGs to work with. Now apply filtering. First list only 260*d3c97224SAlexander Kolbasov# those matching -R 261*d3c97224SAlexander Kolbasov# 262*d3c97224SAlexander Kolbasov@pgs = grep { list_match($p->sh_name($_), @sharing_filter) } @pgs if 263*d3c97224SAlexander Kolbasov scalar @sharing_filter; 264*d3c97224SAlexander Kolbasov 265*d3c97224SAlexander Kolbasov# Remove any that doesn't match -r 266*d3c97224SAlexander Kolbasov@pgs = grep { !list_match($p->sh_name($_), @sharing_filter_neg) } @pgs if 267*d3c97224SAlexander Kolbasov scalar @sharing_filter_neg; 268*d3c97224SAlexander Kolbasov 269*d3c97224SAlexander Kolbasov# Do we have any PGs left? 270*d3c97224SAlexander Kolbasovif (scalar(@pgs) == 0) { 271*d3c97224SAlexander Kolbasov printf STDERR 272*d3c97224SAlexander Kolbasov gettext("%s: no processor groups matching command line arguments %s\n"), 273*d3c97224SAlexander Kolbasov $cmdname, "@ARGV"; 274*d3c97224SAlexander Kolbasov exit(E_ERROR); 275*d3c97224SAlexander Kolbasov} 276*d3c97224SAlexander Kolbasov 277*d3c97224SAlexander Kolbasov# 278*d3c97224SAlexander Kolbasov# Global list of PGs that should be excluded from the output - it is only used 279*d3c97224SAlexander Kolbasov# when tree mode is specified. 280*d3c97224SAlexander Kolbasov# 281*d3c97224SAlexander Kolbasovmy @exclude_pgs; 282*d3c97224SAlexander Kolbasovif ($do_tree) { 283*d3c97224SAlexander Kolbasov @exclude_pgs = grep { 284*d3c97224SAlexander Kolbasov list_match($p->sh_name($_), @sharing_filter_neg) 285*d3c97224SAlexander Kolbasov } @all_pgs; 286*d3c97224SAlexander Kolbasov 287*d3c97224SAlexander Kolbasov # 288*d3c97224SAlexander Kolbasov # In tree mode add PGs that are in the lineage of given PGs 289*d3c97224SAlexander Kolbasov # 290*d3c97224SAlexander Kolbasov @pgs = pg_lineage($p, @pgs) 291*d3c97224SAlexander Kolbasov} 292*d3c97224SAlexander Kolbasov 293*d3c97224SAlexander Kolbasov# 294*d3c97224SAlexander Kolbasov# -I is specified, print list of all PGs 295*d3c97224SAlexander Kolbasov# 296*d3c97224SAlexander Kolbasovif ($script_mode) { 297*d3c97224SAlexander Kolbasov if (scalar(@pgs)) { 298*d3c97224SAlexander Kolbasov @pgs = sort { $a <=> $b } @pgs; 299*d3c97224SAlexander Kolbasov print "@pgs\n"; 300*d3c97224SAlexander Kolbasov } else { 301*d3c97224SAlexander Kolbasov print "none\n"; 302*d3c97224SAlexander Kolbasov } 303*d3c97224SAlexander Kolbasov exit($rc); 304*d3c97224SAlexander Kolbasov} 305*d3c97224SAlexander Kolbasov 306*d3c97224SAlexander Kolbasov# 307*d3c97224SAlexander Kolbasov# -C is specified, print list of all CPUs belonging to PGs 308*d3c97224SAlexander Kolbasov# 309*d3c97224SAlexander Kolbasovif ($do_cpulist) { 310*d3c97224SAlexander Kolbasov my @cpu_list = $p->uniqsort(map { $p->cpus($_) } @pgs); 311*d3c97224SAlexander Kolbasov print "@cpu_list\n"; 312*d3c97224SAlexander Kolbasov exit($rc); 313*d3c97224SAlexander Kolbasov} 314*d3c97224SAlexander Kolbasov 315*d3c97224SAlexander Kolbasov# Mapping of relationships to list of PGs 316*d3c97224SAlexander Kolbasovmy %pgs_by_relationship; 317*d3c97224SAlexander Kolbasov 318*d3c97224SAlexander Kolbasov# Maximum length of all sharing names 319*d3c97224SAlexander Kolbasovmy $max_sharename_len = length('RELATIONSHIP'); 320*d3c97224SAlexander Kolbasov 321*d3c97224SAlexander Kolbasov# Maximum length of PG ID 322*d3c97224SAlexander Kolbasovmy $max_pg_len = length(max(@pgs)) + 1; 323*d3c97224SAlexander Kolbasov 324*d3c97224SAlexander Kolbasov# 325*d3c97224SAlexander Kolbasov# For calculating proper offsets we need to know minimum and maximum level for 326*d3c97224SAlexander Kolbasov# all PGs 327*d3c97224SAlexander Kolbasov# 328*d3c97224SAlexander Kolbasovmy @levels = map { $p->level($_) } @pgs; 329*d3c97224SAlexander Kolbasovmy $maxlevel = max(@levels); 330*d3c97224SAlexander Kolbasovmy $minlevel = min(@levels); 331*d3c97224SAlexander Kolbasov 332*d3c97224SAlexander Kolbasov# Calculate maximum string length that should be used to represent PGs 333*d3c97224SAlexander Kolbasovforeach my $pg (@pgs) { 334*d3c97224SAlexander Kolbasov my $name = $p->sh_name ($pg) || "unknown"; 335*d3c97224SAlexander Kolbasov my $level = $p->level($pg) || 0; 336*d3c97224SAlexander Kolbasov 337*d3c97224SAlexander Kolbasov if ($do_physical) { 338*d3c97224SAlexander Kolbasov my $tags = $p->tags($pg); 339*d3c97224SAlexander Kolbasov $name = "$name [$tags]" if $tags; 340*d3c97224SAlexander Kolbasov } 341*d3c97224SAlexander Kolbasov 342*d3c97224SAlexander Kolbasov my $length = length($name) + $level - $minlevel; 343*d3c97224SAlexander Kolbasov $max_sharename_len = $length if $length > $max_sharename_len; 344*d3c97224SAlexander Kolbasov} 345*d3c97224SAlexander Kolbasov 346*d3c97224SAlexander Kolbasovif ($do_sharing_only) { 347*d3c97224SAlexander Kolbasov # 348*d3c97224SAlexander Kolbasov # -s - only print sharing relationships 349*d3c97224SAlexander Kolbasov 350*d3c97224SAlexander Kolbasov # Get list of sharing relationships 351*d3c97224SAlexander Kolbasov my @relationships = $p->sharing_relationships(@pgs); 352*d3c97224SAlexander Kolbasov 353*d3c97224SAlexander Kolbasov if ($verbose) { 354*d3c97224SAlexander Kolbasov printf "%-${max_sharename_len}s %s\n", 355*d3c97224SAlexander Kolbasov 'RELATIONSHIP', 'PGs'; 356*d3c97224SAlexander Kolbasov foreach my $rel (@relationships) { 357*d3c97224SAlexander Kolbasov my @pg_rel = grep { $p->sh_name($_) eq $rel } 358*d3c97224SAlexander Kolbasov @pgs; 359*d3c97224SAlexander Kolbasov my $pg_rel = $p->id_collapse (@pg_rel); 360*d3c97224SAlexander Kolbasov $pgs_by_relationship{$rel} = \@pg_rel; 361*d3c97224SAlexander Kolbasov } 362*d3c97224SAlexander Kolbasov } 363*d3c97224SAlexander Kolbasov 364*d3c97224SAlexander Kolbasov foreach my $rel (@relationships) { 365*d3c97224SAlexander Kolbasov printf "%-${max_sharename_len}s", $rel; 366*d3c97224SAlexander Kolbasov if ($verbose) { 367*d3c97224SAlexander Kolbasov my @pgs = @{$pgs_by_relationship{$rel}}; 368*d3c97224SAlexander Kolbasov my $pgs = $p->id_collapse (@pgs); 369*d3c97224SAlexander Kolbasov print ' ', $pgs; 370*d3c97224SAlexander Kolbasov } 371*d3c97224SAlexander Kolbasov print "\n"; 372*d3c97224SAlexander Kolbasov } 373*d3c97224SAlexander Kolbasov 374*d3c97224SAlexander Kolbasov # we are done 375*d3c97224SAlexander Kolbasov exit($rc); 376*d3c97224SAlexander Kolbasov} 377*d3c97224SAlexander Kolbasov 378*d3c97224SAlexander Kolbasov# 379*d3c97224SAlexander Kolbasov# Print PGs either in list form or tree form 380*d3c97224SAlexander Kolbasov# 381*d3c97224SAlexander Kolbasovif (!$do_tree) { 382*d3c97224SAlexander Kolbasov my $header; 383*d3c97224SAlexander Kolbasov 384*d3c97224SAlexander Kolbasov $header = sprintf "%-${max_pg_len}s %-${max_sharename_len}s" . 385*d3c97224SAlexander Kolbasov " %s\n", 386*d3c97224SAlexander Kolbasov 'PG', 'RELATIONSHIP', 'CPUs'; 387*d3c97224SAlexander Kolbasov 388*d3c97224SAlexander Kolbasov print $header; 389*d3c97224SAlexander Kolbasov map { pg_print ($p, $_) } @pgs; 390*d3c97224SAlexander Kolbasov} else { 391*d3c97224SAlexander Kolbasov # 392*d3c97224SAlexander Kolbasov # Construct a tree from PG hierarchy and prune any PGs that are 393*d3c97224SAlexander Kolbasov # specified with -R option 394*d3c97224SAlexander Kolbasov # 395*d3c97224SAlexander Kolbasov my $pg_tree = pg_make_tree($p); 396*d3c97224SAlexander Kolbasov map { pg_remove_from_tree($pg_tree, $_) } @exclude_pgs; 397*d3c97224SAlexander Kolbasov 398*d3c97224SAlexander Kolbasov # Find top-level PGs 399*d3c97224SAlexander Kolbasov my @top_level = grep { 400*d3c97224SAlexander Kolbasov $pg_tree->{$_} && !defined($pg_tree->{$_}->{parent}) 401*d3c97224SAlexander Kolbasov } @pgs; 402*d3c97224SAlexander Kolbasov 403*d3c97224SAlexander Kolbasov # Print each top-level node as ASCII tree 404*d3c97224SAlexander Kolbasov foreach my $pg (@top_level) { 405*d3c97224SAlexander Kolbasov my $children = $pg_tree->{$pg}->{children}; 406*d3c97224SAlexander Kolbasov my @children = $children ? @{$children} : (); 407*d3c97224SAlexander Kolbasov @children = $p->intersect(\@children, \@pgs); 408*d3c97224SAlexander Kolbasov pg_print_tree($p, $pg_tree, $pg, '', '', scalar @children); 409*d3c97224SAlexander Kolbasov } 410*d3c97224SAlexander Kolbasov} 411*d3c97224SAlexander Kolbasov 412*d3c97224SAlexander Kolbasov# We are done! 413*d3c97224SAlexander Kolbasovexit($rc); 414*d3c97224SAlexander Kolbasov 415*d3c97224SAlexander Kolbasov###################################################################### 416*d3c97224SAlexander Kolbasov# Internal functions 417*d3c97224SAlexander Kolbasov# 418*d3c97224SAlexander Kolbasov 419*d3c97224SAlexander Kolbasov# 420*d3c97224SAlexander Kolbasov# pg_print(cookie, pg) 421*d3c97224SAlexander Kolbasov# print PG information in list mode 422*d3c97224SAlexander Kolbasov# 423*d3c97224SAlexander Kolbasovsub pg_print 424*d3c97224SAlexander Kolbasov{ 425*d3c97224SAlexander Kolbasov my $p = shift; 426*d3c97224SAlexander Kolbasov my $pg = shift; 427*d3c97224SAlexander Kolbasov my $sharing = $p->sh_name($pg); 428*d3c97224SAlexander Kolbasov if ($do_physical) { 429*d3c97224SAlexander Kolbasov my $tags = $p->tags($pg); 430*d3c97224SAlexander Kolbasov $sharing = "$sharing [$tags]" if $tags; 431*d3c97224SAlexander Kolbasov } 432*d3c97224SAlexander Kolbasov my $level = $p->level($pg) - $minlevel; 433*d3c97224SAlexander Kolbasov $sharing = (' ' x (LEVEL_OFFSET * $level)) . $sharing; 434*d3c97224SAlexander Kolbasov my $cpus = $p->cpus($pg); 435*d3c97224SAlexander Kolbasov printf "%-${max_pg_len}d %-${max_sharename_len}s", $pg, $sharing; 436*d3c97224SAlexander Kolbasov print " $cpus"; 437*d3c97224SAlexander Kolbasov print "\n"; 438*d3c97224SAlexander Kolbasov} 439*d3c97224SAlexander Kolbasov 440*d3c97224SAlexander Kolbasov# 441*d3c97224SAlexander Kolbasov# pg_showcpus(cookie, pg) 442*d3c97224SAlexander Kolbasov# Print CPUs in the current PG 443*d3c97224SAlexander Kolbasov# 444*d3c97224SAlexander Kolbasovsub pg_showcpus 445*d3c97224SAlexander Kolbasov{ 446*d3c97224SAlexander Kolbasov my $p = shift; 447*d3c97224SAlexander Kolbasov my $pg = shift; 448*d3c97224SAlexander Kolbasov 449*d3c97224SAlexander Kolbasov my @cpus = $p->cpus($pg); 450*d3c97224SAlexander Kolbasov my $ncpus = scalar @cpus; 451*d3c97224SAlexander Kolbasov return 0 unless $ncpus; 452*d3c97224SAlexander Kolbasov my $cpu_string = $p->cpus($pg); 453*d3c97224SAlexander Kolbasov return (($ncpus == 1) ? 454*d3c97224SAlexander Kolbasov "CPU: $cpu_string": 455*d3c97224SAlexander Kolbasov "CPUs: $cpu_string"); 456*d3c97224SAlexander Kolbasov} 457*d3c97224SAlexander Kolbasov 458*d3c97224SAlexander Kolbasov# 459*d3c97224SAlexander Kolbasov# pg_print_node(cookie, pg) 460*d3c97224SAlexander Kolbasov# print PG as ASCII tree node 461*d3c97224SAlexander Kolbasov# 462*d3c97224SAlexander Kolbasovsub pg_print_node 463*d3c97224SAlexander Kolbasov{ 464*d3c97224SAlexander Kolbasov my $p = shift; 465*d3c97224SAlexander Kolbasov my $pg = shift; 466*d3c97224SAlexander Kolbasov 467*d3c97224SAlexander Kolbasov my $sharing = $p->sh_name($pg); 468*d3c97224SAlexander Kolbasov if ($do_physical) { 469*d3c97224SAlexander Kolbasov my $tags = $p->tags($pg); 470*d3c97224SAlexander Kolbasov $sharing = "$sharing [$tags]" if $tags; 471*d3c97224SAlexander Kolbasov } 472*d3c97224SAlexander Kolbasov 473*d3c97224SAlexander Kolbasov print "$pg ($sharing)"; 474*d3c97224SAlexander Kolbasov my $cpus = pg_showcpus($p, $pg); 475*d3c97224SAlexander Kolbasov print " $cpus"; 476*d3c97224SAlexander Kolbasov print "\n"; 477*d3c97224SAlexander Kolbasov} 478*d3c97224SAlexander Kolbasov 479*d3c97224SAlexander Kolbasov# 480*d3c97224SAlexander Kolbasov# pg_print_tree(cookie, tree, pg, prefix, childprefix, npeers) 481*d3c97224SAlexander Kolbasov# print ASCII tree of PGs in the tree 482*d3c97224SAlexander Kolbasov# prefix should be used for the current node, childprefix for children nodes 483*d3c97224SAlexander Kolbasov# npeers is the number of peers of the current node 484*d3c97224SAlexander Kolbasov# 485*d3c97224SAlexander Kolbasovsub pg_print_tree 486*d3c97224SAlexander Kolbasov{ 487*d3c97224SAlexander Kolbasov my $p = shift; 488*d3c97224SAlexander Kolbasov my $pg_tree = shift; 489*d3c97224SAlexander Kolbasov my $pg = shift; 490*d3c97224SAlexander Kolbasov return unless defined ($pg); # done! 491*d3c97224SAlexander Kolbasov my $prefix = shift; 492*d3c97224SAlexander Kolbasov my $childprefix = shift; 493*d3c97224SAlexander Kolbasov my $npeers = shift; 494*d3c97224SAlexander Kolbasov 495*d3c97224SAlexander Kolbasov # Get list of my children 496*d3c97224SAlexander Kolbasov my $children = $pg_tree->{$pg}->{children}; 497*d3c97224SAlexander Kolbasov my @children = $children ? @{$children} : (); 498*d3c97224SAlexander Kolbasov @children = $p->intersect(\@children, \@pgs); 499*d3c97224SAlexander Kolbasov my $nchildren = scalar @children; 500*d3c97224SAlexander Kolbasov 501*d3c97224SAlexander Kolbasov my $printprefix = "$childprefix"; 502*d3c97224SAlexander Kolbasov my $printpostfix = $npeers ? "| " : " "; 503*d3c97224SAlexander Kolbasov 504*d3c97224SAlexander Kolbasov my $bar = $npeers ? "|" : "`"; 505*d3c97224SAlexander Kolbasov 506*d3c97224SAlexander Kolbasov print $childprefix ? $childprefix : ""; 507*d3c97224SAlexander Kolbasov print $prefix ? "$bar" . "-- " : ""; 508*d3c97224SAlexander Kolbasov pg_print_node ($p, $pg); 509*d3c97224SAlexander Kolbasov 510*d3c97224SAlexander Kolbasov my $new_prefix = $npeers ? $prefix : " "; 511*d3c97224SAlexander Kolbasov 512*d3c97224SAlexander Kolbasov # Print the subtree with a new offset, starting from each child 513*d3c97224SAlexander Kolbasov map { 514*d3c97224SAlexander Kolbasov pg_print_tree($p, $pg_tree, $_, "| ", 515*d3c97224SAlexander Kolbasov "$childprefix$new_prefix", --$nchildren) 516*d3c97224SAlexander Kolbasov } @children; 517*d3c97224SAlexander Kolbasov} 518*d3c97224SAlexander Kolbasov 519*d3c97224SAlexander Kolbasov# 520*d3c97224SAlexander Kolbasov# list_match(arg, list) 521*d3c97224SAlexander Kolbasov# Return arg if argument matches any of the elements on the list 522*d3c97224SAlexander Kolbasov# 523*d3c97224SAlexander Kolbasovsub list_match 524*d3c97224SAlexander Kolbasov{ 525*d3c97224SAlexander Kolbasov my $arg = shift; 526*d3c97224SAlexander Kolbasov 527*d3c97224SAlexander Kolbasov return first { $arg =~ m/$_/i } @_; 528*d3c97224SAlexander Kolbasov} 529*d3c97224SAlexander Kolbasov 530*d3c97224SAlexander Kolbasov# 531*d3c97224SAlexander Kolbasov# Make a version of PG parent-children relationships from cookie 532*d3c97224SAlexander Kolbasov# 533*d3c97224SAlexander Kolbasovsub pg_make_tree 534*d3c97224SAlexander Kolbasov{ 535*d3c97224SAlexander Kolbasov my $p = shift; 536*d3c97224SAlexander Kolbasov my $pg_tree = (); 537*d3c97224SAlexander Kolbasov 538*d3c97224SAlexander Kolbasov foreach my $pg ($p->all()) { 539*d3c97224SAlexander Kolbasov my @children = $p->children($pg); 540*d3c97224SAlexander Kolbasov $pg_tree->{$pg}->{parent} = $p->parent($pg); 541*d3c97224SAlexander Kolbasov $pg_tree->{$pg}->{children} = \@children; 542*d3c97224SAlexander Kolbasov } 543*d3c97224SAlexander Kolbasov 544*d3c97224SAlexander Kolbasov return ($pg_tree); 545*d3c97224SAlexander Kolbasov} 546*d3c97224SAlexander Kolbasov 547*d3c97224SAlexander Kolbasov# 548*d3c97224SAlexander Kolbasov# pg_remove_from_tree(tree, pg) 549*d3c97224SAlexander Kolbasov# Prune PG from the tree 550*d3c97224SAlexander Kolbasov# 551*d3c97224SAlexander Kolbasovsub pg_remove_from_tree 552*d3c97224SAlexander Kolbasov{ 553*d3c97224SAlexander Kolbasov my $pg_tree = shift; 554*d3c97224SAlexander Kolbasov my $pg = shift; 555*d3c97224SAlexander Kolbasov my $node = $pg_tree->{$pg}; 556*d3c97224SAlexander Kolbasov return unless $node; 557*d3c97224SAlexander Kolbasov 558*d3c97224SAlexander Kolbasov my @children = @{$node->{children}}; 559*d3c97224SAlexander Kolbasov my $parent = $node->{parent}; 560*d3c97224SAlexander Kolbasov my $parent_node; 561*d3c97224SAlexander Kolbasov 562*d3c97224SAlexander Kolbasov # 563*d3c97224SAlexander Kolbasov # Children have a new parent 564*d3c97224SAlexander Kolbasov # 565*d3c97224SAlexander Kolbasov map { $pg_tree->{$_}->{parent} = $parent } @children; 566*d3c97224SAlexander Kolbasov 567*d3c97224SAlexander Kolbasov # 568*d3c97224SAlexander Kolbasov # All children move to the parent (if there is one) 569*d3c97224SAlexander Kolbasov # 570*d3c97224SAlexander Kolbasov if (defined($parent) && ($parent_node = $pg_tree->{$parent})) { 571*d3c97224SAlexander Kolbasov # 572*d3c97224SAlexander Kolbasov # Merge children from parent and @children list 573*d3c97224SAlexander Kolbasov # 574*d3c97224SAlexander Kolbasov my @parent_children = @{$parent_node->{children}}; 575*d3c97224SAlexander Kolbasov # 576*d3c97224SAlexander Kolbasov # Remove myself from parent children 577*d3c97224SAlexander Kolbasov # 578*d3c97224SAlexander Kolbasov @parent_children = grep { $_ != $pg } @parent_children; 579*d3c97224SAlexander Kolbasov @parent_children = $p->nsort(@parent_children, @children); 580*d3c97224SAlexander Kolbasov $parent_node->{children} = \@parent_children; 581*d3c97224SAlexander Kolbasov } 582*d3c97224SAlexander Kolbasov 583*d3c97224SAlexander Kolbasov # Remove current node 584*d3c97224SAlexander Kolbasov delete $pg_tree->{$pg}; 585*d3c97224SAlexander Kolbasov} 586*d3c97224SAlexander Kolbasov 587*d3c97224SAlexander Kolbasov# 588*d3c97224SAlexander Kolbasov# For a given list of PGs return the full lineage 589*d3c97224SAlexander Kolbasov# 590*d3c97224SAlexander Kolbasovsub pg_lineage 591*d3c97224SAlexander Kolbasov{ 592*d3c97224SAlexander Kolbasov my $p = shift; 593*d3c97224SAlexander Kolbasov return unless scalar @_; 594*d3c97224SAlexander Kolbasov 595*d3c97224SAlexander Kolbasov my @parents = grep { defined($_) } map { $p->parent ($_) } @_; 596*d3c97224SAlexander Kolbasov 597*d3c97224SAlexander Kolbasov return ($p->uniq(@_, @parents, pg_lineage ($p, @parents))); 598*d3c97224SAlexander Kolbasov} 599*d3c97224SAlexander Kolbasov 600*d3c97224SAlexander Kolbasov# 601*d3c97224SAlexander Kolbasov# Print usage information and exit with the return code specified 602*d3c97224SAlexander Kolbasov# 603*d3c97224SAlexander Kolbasovsub usage 604*d3c97224SAlexander Kolbasov{ 605*d3c97224SAlexander Kolbasov my $rc = shift; 606*d3c97224SAlexander Kolbasov printf STDERR 607*d3c97224SAlexander Kolbasov gettext("Usage:\t%s [-T] [-p] [-v] [-r string] [-R string] [pg ... | -c processor_id ...]\n\n"), 608*d3c97224SAlexander Kolbasov $cmdname; 609*d3c97224SAlexander Kolbasov printf STDERR 610*d3c97224SAlexander Kolbasov gettext("\t%s -s [-v] [-r string] [-R string] [pg ... | -c processor_id ...]\n\n"), $cmdname; 611*d3c97224SAlexander Kolbasov printf STDERR gettext("\t%s -C | -I [-r string] [-R string] [pg ... | -c processor_id ...]\n\n"), 612*d3c97224SAlexander Kolbasov $cmdname; 613*d3c97224SAlexander Kolbasov printf STDERR gettext("\t%s -h\n\n"), $cmdname; 614*d3c97224SAlexander Kolbasov 615*d3c97224SAlexander Kolbasov exit($rc); 616*d3c97224SAlexander Kolbasov} 617*d3c97224SAlexander Kolbasov 618*d3c97224SAlexander Kolbasov__END__ 619