mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-06-24 15:05:36 +00:00
merge 2.13.perfopt branch to master branch (#3044)
* Add trace point for perf tool in xcatd (#903) This patch aims to enable nytprof library to analyze the performance of xcat code in statement level. - Add perf trace point in xcatd - Add sleep time for db prcess to solve the race condition when - perf instraction is used. More reference To enable prof: perl -dt:NYTProf /opt/xcat/sbin/xcatd -f Some perf test sample: https://github.com/chenglch/xcatperf * refine the performance of makedhcp (#2901), it including: - refine the code logic in getSNList to get better performance - refine the getipaddr, cache the dns lookup result - refine noderangecontainsMn - refine ishostinsubnet
This commit is contained in:
@ -16,6 +16,7 @@ use xCAT::Utils;
|
||||
#use locale;
|
||||
use Socket;
|
||||
use File::Path;
|
||||
use constant PERF_LOG => "/var/log/xcat/perf.log";
|
||||
|
||||
$::NOK = -1;
|
||||
$::OK = 0;
|
||||
@ -823,5 +824,65 @@ sub trace() {
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------
|
||||
|
||||
=head3 _perf_log
|
||||
Libary function to write the perf log. Do not use it directly.
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
sub _perf_log
|
||||
{
|
||||
my $type = shift;
|
||||
my $msg = shift;
|
||||
my $fh;
|
||||
my $ret = open($fh, '>>', PERF_LOG);
|
||||
if (!$ret) {
|
||||
xCAT::MsgUtils->message("S", "Open perf log file error: $!");
|
||||
}
|
||||
my $line = localtime()."\t$type\t$msg\n";
|
||||
print $fh $line;
|
||||
close $fh;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------
|
||||
|
||||
=head3 perf_log_info
|
||||
Trace information for perf
|
||||
Argument:
|
||||
$msg (trace message)
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
sub perf_log_info
|
||||
{
|
||||
shift;
|
||||
my $msg = shift;
|
||||
_perf_log('info', $msg);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------
|
||||
|
||||
=head3 perf_log_process
|
||||
Trace process information for perf
|
||||
Arguments:
|
||||
$process_type (immediate, plugin, etc)
|
||||
$req (xcat reqeust)
|
||||
$msg (additional message, optional)
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
sub perf_log_process
|
||||
{
|
||||
shift;
|
||||
my ($process_type, $req, $msg, $pid) = @_;
|
||||
if (defined($req)) {
|
||||
my $command = $req->{command}->[0];
|
||||
_perf_log($process_type, "$$\t$command\t$msg");
|
||||
} else {
|
||||
_perf_log($process_type, "$pid\t$msg");
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
@ -19,8 +19,7 @@ use File::Path;
|
||||
use Math::BigInt;
|
||||
use Socket;
|
||||
use xCAT::GlobalDef;
|
||||
|
||||
#use Data::Dumper;
|
||||
use Sys::Hostname;
|
||||
use strict;
|
||||
use warnings "all";
|
||||
my $socket6support = eval { require Socket6 };
|
||||
@ -229,6 +228,9 @@ sub gethostname()
|
||||
hostname
|
||||
Optional:
|
||||
GetNumber=>1 (return the address as a BigInt instead of readable string)
|
||||
GetAllAddresses=>1 (return the )
|
||||
OnlyV6=>1 ()
|
||||
OnlyV4=> ()
|
||||
Returns: ip address
|
||||
Globals:
|
||||
cache: %::hostiphash
|
||||
@ -270,69 +272,117 @@ sub getipaddr
|
||||
# #pass in an ip and only want an ip??
|
||||
# return $iporhost;
|
||||
#}
|
||||
my $isip=0;
|
||||
if ($iporhost and ($iporhost =~ /\d+\.\d+\.\d+\.\d+/) || ($iporhost =~ /:/)){
|
||||
$isip=1;
|
||||
}
|
||||
|
||||
|
||||
#print "============================\n";
|
||||
#print Dumper(\%::hostiphash);
|
||||
#print "\n";
|
||||
#print Dumper(\%extraarguments);
|
||||
#print "\n";
|
||||
#print "iporhost=$iporhost";
|
||||
#print "\n";
|
||||
#print "============================\n";
|
||||
|
||||
#cache, do not lookup DNS each time
|
||||
if ($::hostiphash and defined($::hostiphash{$iporhost}) && $::hostiphash{$iporhost})
|
||||
if (
|
||||
((not $extraarguments{OnlyV6}) and (not $extraarguments{GetAllAddresses})) and defined($::hostiphash{$iporhost}) and $::hostiphash{$iporhost})
|
||||
{
|
||||
return $::hostiphash{$iporhost};
|
||||
|
||||
if($extraarguments{GetNumber} ) {
|
||||
if($::hostiphash{$iporhost}{Number}){
|
||||
#print "YYYYYYYYYY GetNumber Cache Hit!!!YYYYYYYYY\n";
|
||||
return $::hostiphash{$iporhost}{Number};
|
||||
}
|
||||
} elsif($::hostiphash{$iporhost}{hostip}) {
|
||||
#print "YYYYYYYYYY dns Cache Hit!!!YYYYYYYYY\n";
|
||||
return $::hostiphash{$iporhost}{hostip};
|
||||
}
|
||||
}
|
||||
|
||||
if ($socket6support) # the getaddrinfo and getnameinfo supports both IPv4 and IPv6
|
||||
{
|
||||
my @returns;
|
||||
my $reqfamily = AF_UNSPEC;
|
||||
if ($extraarguments{OnlyV6}) {
|
||||
$reqfamily = AF_INET6;
|
||||
} elsif ($extraarguments{OnlyV4}) {
|
||||
$reqfamily = AF_INET;
|
||||
}
|
||||
my @addrinfo;
|
||||
if($isip) {
|
||||
@addrinfo=Socket6::getaddrinfo($iporhost, 0, $reqfamily, SOCK_STREAM, 6,Socket6::AI_NUMERICHOST());
|
||||
}else{
|
||||
@addrinfo=Socket6::getaddrinfo($iporhost, 0, $reqfamily, SOCK_STREAM, 6);
|
||||
}
|
||||
my ($family, $socket, $protocol, $ip, $name) = splice(@addrinfo, 0, 5);
|
||||
unless($reqfamily == AF_INET6){
|
||||
if($isip){
|
||||
if($name){
|
||||
$::hostiphash{$iporhost}{hostip}=$name;
|
||||
}
|
||||
}elsif($ip){
|
||||
$::hostiphash{$iporhost}{hostip}=$ip;
|
||||
}
|
||||
}
|
||||
while ($ip)
|
||||
{
|
||||
if ($extraarguments{GetNumber}) { #return a BigInt for compare, e.g. for comparing ip addresses for determining if they are in a common network or range
|
||||
my $ip = (Socket6::getnameinfo($ip, Socket6::NI_NUMERICHOST()))[0];
|
||||
my $bignumber = Math::BigInt->new(0);
|
||||
foreach (unpack("N*", Socket6::inet_pton($family, $ip))) { #if ipv4, loop will iterate once, for v6, will go 4 times
|
||||
$bignumber->blsft(32);
|
||||
$bignumber->badd($_);
|
||||
}
|
||||
push(@returns, $bignumber);
|
||||
$::hostiphash{$iporhost}{Number}=$returns[0];
|
||||
} else {
|
||||
push @returns, (Socket6::getnameinfo($ip, Socket6::NI_NUMERICHOST()))[0];
|
||||
$::hostiphash{$iporhost}{hostip}=$returns[0];
|
||||
}
|
||||
if (scalar @addrinfo and $extraarguments{GetAllAddresses}) {
|
||||
($family, $socket, $protocol, $ip, $name) = splice(@addrinfo, 0, 5);
|
||||
} else {
|
||||
$ip = 0;
|
||||
}
|
||||
}
|
||||
unless ($extraarguments{GetAllAddresses}) {
|
||||
return $returns[0];
|
||||
}
|
||||
return @returns;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($socket6support) # the getaddrinfo and getnameinfo supports both IPv4 and IPv6
|
||||
{
|
||||
my @returns;
|
||||
my $reqfamily = AF_UNSPEC;
|
||||
if ($extraarguments{OnlyV6}) {
|
||||
$reqfamily = AF_INET6;
|
||||
} elsif ($extraarguments{OnlyV4}) {
|
||||
$reqfamily = AF_INET;
|
||||
}
|
||||
my @addrinfo = Socket6::getaddrinfo($iporhost, 0, $reqfamily, SOCK_STREAM, 6);
|
||||
my ($family, $socket, $protocol, $ip, $name) = splice(@addrinfo, 0, 5);
|
||||
while ($ip)
|
||||
{
|
||||
if ($extraarguments{GetNumber}) { #return a BigInt for compare, e.g. for comparing ip addresses for determining if they are in a common network or range
|
||||
my $ip = (Socket6::getnameinfo($ip, Socket6::NI_NUMERICHOST()))[0];
|
||||
my $bignumber = Math::BigInt->new(0);
|
||||
foreach (unpack("N*", Socket6::inet_pton($family, $ip))) { #if ipv4, loop will iterate once, for v6, will go 4 times
|
||||
$bignumber->blsft(32);
|
||||
$bignumber->badd($_);
|
||||
}
|
||||
push(@returns, $bignumber);
|
||||
} else {
|
||||
push @returns, (Socket6::getnameinfo($ip, Socket6::NI_NUMERICHOST()))[0];
|
||||
}
|
||||
if (scalar @addrinfo and $extraarguments{GetAllAddresses}) {
|
||||
($family, $socket, $protocol, $ip, $name) = splice(@addrinfo, 0, 5);
|
||||
} else {
|
||||
$ip = 0;
|
||||
}
|
||||
}
|
||||
unless ($extraarguments{GetAllAddresses}) {
|
||||
return $returns[0];
|
||||
}
|
||||
return @returns;
|
||||
}
|
||||
else
|
||||
{
|
||||
#return inet_ntoa(inet_aton($iporhost))
|
||||
#TODO, what if no scoket6 support, but passing in a IPv6 hostname?
|
||||
if ($iporhost =~ /:/) { #ipv6
|
||||
return undef;
|
||||
#return inet_ntoa(inet_aton($iporhost))
|
||||
#TODO, what if no scoket6 support, but passing in a IPv6 hostname?
|
||||
if ($iporhost =~ /:/) { #ipv6
|
||||
return undef;
|
||||
|
||||
#die "Attempt to process IPv6 address, but system does not have requisite IPv6 perl support";
|
||||
}
|
||||
my $packed_ip;
|
||||
$iporhost and $packed_ip = inet_aton($iporhost);
|
||||
if (!$packed_ip)
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
if ($extraarguments{GetNumber}) { #only 32 bits, no for loop needed.
|
||||
return Math::BigInt->new(unpack("N*", $packed_ip));
|
||||
}
|
||||
return inet_ntoa($packed_ip);
|
||||
#die "Attempt to process IPv6 address, but system does not have requisite IPv6 perl support";
|
||||
}
|
||||
my $packed_ip;
|
||||
$iporhost and $packed_ip = inet_aton($iporhost);
|
||||
if (!$packed_ip)
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $myip=inet_ntoa($packed_ip);
|
||||
|
||||
unless($isip) {
|
||||
$::hostiphash{$iporhost}{hostip}=$myip;
|
||||
}
|
||||
|
||||
if ($extraarguments{GetNumber}) { #only 32 bits, no for loop needed.
|
||||
my $number=Math::BigInt->new(unpack("N*", $packed_ip));
|
||||
$::hostiphash{$iporhost}{Number}=$number;
|
||||
return $number;
|
||||
}
|
||||
|
||||
return $myip;
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,7 +467,7 @@ sub linklocaladdr {
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
sub ishostinsubnet {
|
||||
sub ishostinsubnet{
|
||||
my ($class, $ip, $mask, $subnet) = @_;
|
||||
|
||||
#safe guard
|
||||
@ -425,6 +475,40 @@ sub ishostinsubnet {
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $maskType=0;
|
||||
|
||||
#CIDR notation supported
|
||||
if ($subnet && ($subnet =~ /\//)) {
|
||||
($subnet, $mask) = split /\//, $subnet, 2;
|
||||
$subnet =~ s/\/.*$//;
|
||||
$maskType=1;
|
||||
}elsif ($mask) {
|
||||
if ($mask =~ /\//) {
|
||||
$mask =~ s/^\///;
|
||||
$maskType=1;
|
||||
} elsif($mask =~ /^0x/i ) {
|
||||
$maskType=2;
|
||||
}
|
||||
}
|
||||
|
||||
my $ret=xCAT::NetworkUtils::isInSameSubnet( $ip, $subnet, $mask, $maskType);
|
||||
if(defined $ret and $ret==1){
|
||||
return 1;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub ishostinsubnet_orig {
|
||||
my ($class, $ip, $mask, $subnet) = @_;
|
||||
|
||||
#safe guard
|
||||
if (!defined($ip) || !defined($mask) || !defined($subnet))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $numbits = 32;
|
||||
if ($ip =~ /:/) { #ipv6
|
||||
$numbits = 128;
|
||||
@ -1314,7 +1398,7 @@ sub formatNetmask
|
||||
|
||||
Returns:
|
||||
1: they are in same subnet
|
||||
2: not in same subnet
|
||||
undef: not in same subnet
|
||||
|
||||
Globals:
|
||||
none
|
||||
@ -1853,16 +1937,13 @@ sub get_subnet_aix
|
||||
sub determinehostname
|
||||
{
|
||||
my $hostname;
|
||||
my $hostnamecmd = "/bin/hostname";
|
||||
my @thostname = xCAT::Utils->runcmd($hostnamecmd, 0);
|
||||
if ($::RUNCMD_RC != 0)
|
||||
{ # could not get hostname
|
||||
xCAT::MsgUtils->message("S",
|
||||
"Error $::RUNCMD_RC from $hostnamecmd command\n");
|
||||
exit $::RUNCMD_RC;
|
||||
eval {
|
||||
$hostname = hostname;
|
||||
};
|
||||
if($@){
|
||||
xCAT::MsgUtils->message("S","Fail to get hostname: $@\n");
|
||||
exit -1;
|
||||
}
|
||||
$hostname = $thostname[0];
|
||||
|
||||
#get all potentially valid abbreviations, and pick the one that is ok
|
||||
#by 'noderange'
|
||||
my @hostnamecandidates;
|
||||
|
@ -14,7 +14,6 @@ if ($^O =~ /^aix/i) {
|
||||
}
|
||||
use lib "$::XCATROOT/lib/perl";
|
||||
use strict;
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
=head3 readSNInfo
|
||||
@ -353,6 +352,37 @@ sub getSNandNodes
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
sub getSNList
|
||||
{
|
||||
require xCAT::Table;
|
||||
require xCAT::NodeRange;
|
||||
my ($class, $service, $options) = @_;
|
||||
my @servicenodes;
|
||||
my $servicenodetab = xCAT::Table->new('servicenode');
|
||||
my $nodetab = xCAT::Table->new('nodelist');
|
||||
unless ($servicenodetab) # no servicenode table
|
||||
{
|
||||
xCAT::MsgUtils->message('I', "Unable to open servicenode table.\n");
|
||||
$servicenodetab->close;
|
||||
return @servicenodes;
|
||||
}
|
||||
|
||||
|
||||
if($service){
|
||||
@servicenodes = $servicenodetab->getAllAttribsWhere(["$service==1"],'node');
|
||||
}else{
|
||||
@servicenodes = $servicenodetab->getAllAttribs(('node'));
|
||||
}
|
||||
|
||||
@servicenodes=xCAT::NodeRange::noderange(join(',',map {$_->{node}} @servicenodes));
|
||||
if($options eq "ALL"){
|
||||
return @servicenodes;
|
||||
}
|
||||
|
||||
@servicenodes = $nodetab->getAllAttribsWhere("node in ("."\'".join("\',\'", @servicenodes)."\'".") and groups not like '%__mgmtnode%'",'node');
|
||||
return map {$_->{node}} @servicenodes;
|
||||
}
|
||||
|
||||
sub getSNList_orig
|
||||
{
|
||||
require xCAT::Table;
|
||||
my ($class, $service, $options) = @_;
|
||||
@ -367,6 +397,7 @@ sub getSNList
|
||||
}
|
||||
my @nodes = $servicenodetab->getAllNodeAttribs([$service]);
|
||||
$servicenodetab->close;
|
||||
|
||||
foreach my $node (@nodes)
|
||||
{
|
||||
if (!defined($service) || ($service eq "")) # want all the service nodes
|
||||
|
@ -3306,10 +3306,25 @@ sub isSELINUX
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
sub noderangecontainsMn
|
||||
{
|
||||
my ($class, @noderange) = @_;
|
||||
|
||||
# check if any node in the noderange is the Management Node return the
|
||||
# name
|
||||
my @mnames; # management node names in the database, members of __mgmtnode
|
||||
my $tab = xCAT::Table->new('nodelist');
|
||||
|
||||
my @nodelist = $tab->getAllAttribsWhere("node in ("."\'".join("\',\'", @noderange)."\'".") and groups like '%__mgmtnode%'",'node');
|
||||
return map {$_->{node}} @nodelist; # if no MN in the noderange, return nothing
|
||||
}
|
||||
|
||||
sub noderangecontainsMn_orig
|
||||
{
|
||||
my ($class, @noderange) = @_;
|
||||
|
||||
# check if any node in the noderange is the Management Node return the
|
||||
# name
|
||||
my @mnames; # management node names in the database, members of __mgmtnode
|
||||
|
@ -221,6 +221,20 @@ my $cmdlog_alllog = "====================================================\n";
|
||||
my $cmdlog_starttime=undef;
|
||||
|
||||
# ----used for command log end---------
|
||||
my $enable_perf = $sitetab->getAttribs({'key'=>'enableperf'},'value');
|
||||
if($enable_perf) {
|
||||
# Enabled by user, check whether nytperf library is enabled
|
||||
if (!defined(&DB::disable_profile)) {
|
||||
xCAT::MsgUtils->message("S", "Perf is enabled in sitetable, but can not load the library.");
|
||||
$enable_perf = 0;
|
||||
} else {
|
||||
if ($enable_perf) {
|
||||
xCAT::MsgUtils->perf_log_info("start profiling");
|
||||
DB::enable_profile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$sitetab->close;
|
||||
|
||||
@ -926,7 +940,9 @@ unless ($foreground) {
|
||||
}
|
||||
|
||||
$dbmaster = xCAT::Table::init_dbworker;
|
||||
|
||||
if ($enable_perf) {
|
||||
xCAT::MsgUtils->perf_log_process( "db", undef, "dbprocess", $dbmaster );
|
||||
}
|
||||
# Make sure DB process is ready.
|
||||
wait_db_process();
|
||||
my $CHILDPID = 0; # Global for reapers
|
||||
@ -1026,7 +1042,9 @@ $SIG{TERM} = $SIG{INT} = sub {
|
||||
if ($cmdlog_svrpid) {
|
||||
kill 'INT', $cmdlog_svrpid;
|
||||
}
|
||||
|
||||
if ($enable_perf) {
|
||||
# DB::finish_profile();
|
||||
}
|
||||
# ----used for command log end---------
|
||||
};
|
||||
|
||||
@ -1525,6 +1543,10 @@ until ($quit) {
|
||||
if ($sslfudgefactor) { $sslfudgefactor -= 1; }
|
||||
$sslclients++; # THROTTLE
|
||||
$cnnection->close();
|
||||
if ($enable_perf) {
|
||||
xCAT::MsgUtils->perf_log_info("stop profiling");
|
||||
# DB::disable_profile();
|
||||
}
|
||||
}
|
||||
if (open($mainpidfile, "<", "/var/run/xcat/mainservice.pid")) {
|
||||
my $pid = <$mainpidfile>;
|
||||
@ -1949,6 +1971,9 @@ sub plugin_command {
|
||||
}
|
||||
}
|
||||
$$progname = $oldprogname;
|
||||
if ($enable_perf) {
|
||||
xCAT::MsgUtils->perf_log_process('plugin', $req, "modname:$modname");
|
||||
}
|
||||
$parent_fd = $org_parent_fd;
|
||||
if ($sock) {
|
||||
close($parent_fd);
|
||||
@ -2689,6 +2714,9 @@ sub service_connection {
|
||||
$req = get_request($sock, $globalencode, $line);
|
||||
unless ($req) { last; }
|
||||
|
||||
if ($enable_perf) {
|
||||
xCAT::MsgUtils->perf_log_process('immediate', $req);
|
||||
}
|
||||
# ----used for command log start----------
|
||||
$cmdlog_starttime = time();
|
||||
my ($sec, $min, $hour, $mday, $mon, $year) = localtime($cmdlog_starttime);
|
||||
|
Reference in New Issue
Block a user