2
0
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:
yangsong
2017-05-18 01:23:29 -05:00
committed by Bin Xu
parent 80e5e96542
commit 317845a04c
5 changed files with 287 additions and 71 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);