[pve-devel] [PATCH qemu-server 5/8] property string update: numa*

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Mar 30 12:20:10 CEST 2016


Additionally since the cpu and host node list isn't
restricted to a single range one can now provide multipel
ranges separated by semicolons. (eg. cpus=0-3;5;7)
---
 PVE/QemuServer.pm | 117 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 65 insertions(+), 52 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index bb9624b..bb8a94d 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -467,10 +467,38 @@ my $MAX_NUMA = 8;
 my $MAX_MEM = 4194304;
 my $STATICMEM = 1024;
 
+my $numa_fmt = {
+    cpus => {
+	type => "string",
+	pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
+	description => "CPUs accessing this numa node.",
+	format_description => "id[-id];...",
+    },
+    memory => {
+	type => "number",
+	description => "Amount of memory this numa node provides.",
+	format_description => "mb",
+	optional => 1,
+    },
+    hostnodes => {
+	type => "string",
+	pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
+	description => "host numa nodes to use",
+	format_description => "id[-id];...",
+	optional => 1,
+    },
+    policy => {
+	type => 'string',
+	enum => [qw(preferred bind interleave)],
+	format_description => 'preferred|bind|interleave',
+	description => "numa allocation policy.",
+	optional => 1,
+    },
+};
+PVE::JSONSchema::register_format('pve-qm-numanode', $numa_fmt);
 my $numadesc = {
     optional => 1,
-    type => 'string', format => 'pve-qm-numanode',
-    typetext => "cpus=<id[-id],memory=<mb>[[,hostnodes=<id[-id]>] [,policy=<preferred|bind|interleave>]]",
+    type => 'string', format => $numa_fmt,
     description => "numa topology",
 };
 PVE::JSONSchema::register_standard_option("pve-qm-numanode", $numadesc);
@@ -1469,28 +1497,26 @@ sub drive_is_cdrom {
 
 }
 
+sub parse_number_sets {
+    my ($set) = @_;
+    my $res = [];
+    foreach my $part (split(/;/, $set)) {
+	if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
+	    die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
+	    push @$res, [ $1, $2 ];
+	} else {
+	    die "invalid range: $part\n";
+	}
+    }
+    return $res;
+}
+
 sub parse_numa {
     my ($data) = @_;
 
-    my $res = {};
-
-    foreach my $kvp (split(/,/, $data)) {
-
-	if ($kvp =~ m/^memory=(\S+)$/) {
-	    $res->{memory} = $1;
-	} elsif ($kvp =~ m/^policy=(preferred|bind|interleave)$/) {
-	    $res->{policy} = $1;
-	} elsif ($kvp =~ m/^cpus=(\d+)(-(\d+))?$/) {
-	    $res->{cpus}->{start} = $1;
-	    $res->{cpus}->{end} = $3;
-	} elsif ($kvp =~ m/^hostnodes=(\d+)(-(\d+))?$/) {
-	    $res->{hostnodes}->{start} = $1;
-	    $res->{hostnodes}->{end} = $3;
-	} else {
-	    return undef;
-	}
-    }
-
+    my $res = PVE::JSONSchema::parse_property_string($numa_fmt, $data);
+    $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
+    $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
     return $res;
 }
 
@@ -1758,17 +1784,6 @@ sub verify_bootdisk {
     die "invalid boot disk '$value'\n";
 }
 
-PVE::JSONSchema::register_format('pve-qm-numanode', \&verify_numa);
-sub verify_numa {
-    my ($value, $noerr) = @_;
-
-    return $value if parse_numa($value);
-
-    return undef if $noerr;
-
-    die "unable to parse numa options\n";
-}
-
 PVE::JSONSchema::register_format('pve-qm-net', \&verify_net);
 sub verify_net {
     my ($value, $noerr) = @_;
@@ -3076,28 +3091,26 @@ sub config_to_command {
 	    my $numa_object = "memory-backend-ram,id=ram-node$i,size=${numa_memory}M";
 
 	    # cpus
-	    my $cpus_start = $numa->{cpus}->{start};
-	    die "missing numa node$i cpus\n" if !defined($cpus_start);
-	    my $cpus_end = $numa->{cpus}->{end} if defined($numa->{cpus}->{end});
-	    my $cpus = $cpus_start;
-	    if (defined($cpus_end)) {
-		$cpus .= "-$cpus_end";
-		die "numa node$i :  cpu range $cpus is incorrect\n" if $cpus_end <= $cpus_start;
-	    }
+	    my $cpulists = $numa->{cpus};
+	    die "missing numa node$i cpus\n" if !defined($cpulists);
+	    my $cpus = join(',', map {
+		my ($start, $end) = @$_;
+		defined($end) ? "$start-$end" : $start
+	    } @$cpulists);
 
 	    # hostnodes
-	    my $hostnodes_start = $numa->{hostnodes}->{start};
-	    if (defined($hostnodes_start)) {
-		my $hostnodes_end = $numa->{hostnodes}->{end} if defined($numa->{hostnodes}->{end});
-		my $hostnodes = $hostnodes_start;
-		if (defined($hostnodes_end)) {
-		    $hostnodes .= "-$hostnodes_end";
-		    die "host node $hostnodes range is incorrect\n" if $hostnodes_end <= $hostnodes_start;
-		}
-
-		my $hostnodes_end_range = defined($hostnodes_end) ? $hostnodes_end : $hostnodes_start;
-		for (my $i = $hostnodes_start; $i <= $hostnodes_end_range; $i++ ) {
-		    die "host numa node$i don't exist\n" if ! -d "/sys/devices/system/node/node$i/";
+	    my $hostnodelists = $numa->{hostnodes};
+	    if (defined($hostnodelists)) {
+		my $hostnodes;
+		foreach my $hostnoderange (@$hostnodelists) {
+		    my ($start, $end) = @$hostnoderange;
+		    $hostnodes .= ',' if $hostnodes;
+		    $hostnodes .= $start;
+		    $hostnodes .= "-$end" if defined($end);
+		    $end //= $start;
+		    for (my $i = $start; $i <= $end; ++$i ) {
+			die "host numa node$i don't exist\n" if ! -d "/sys/devices/system/node/node$i/";
+		    }
 		}
 
 		# policy
-- 
2.1.4





More information about the pve-devel mailing list