[pve-devel] [RFC qemu-server 4/6] Add QEMU CPU flag querying helpers
Fabian Grünbichler
f.gruenbichler at proxmox.com
Tue Jul 30 13:58:55 CEST 2019
approach looks good, some style / code re-use comments inline.
On Wed, Jul 17, 2019 at 03:03:46PM +0200, Stefan Reiter wrote:
> * query_understood_cpu_flags returns all flags that QEMU/KVM knows about
> * query_supported_cpu_flags returns all flags that QEMU/KVM can use on
> this particular host.
>
> To get supported flags, a temporary VM is started with QEMU, so we can
> issue the "query-cpu-model-expansion" QMP command. This is how libvirt
> queries supported flags for its "host-passthrough" CPU type.
>
> query_supported_cpu_flags is thus rather slow and shouldn't be called
> unnecessarily.
>
> Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
> ---
> PVE/QemuServer.pm | 79 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 79 insertions(+)
>
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 9f29927..9ee9722 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -3448,6 +3448,85 @@ sub get_command_for_arch($) {
> return $cmd;
> }
>
> +sub query_understood_cpu_flags {
> + my $flags = [];
> + my $flag_section = 0;
> +
> + run_command(
> + [get_command_for_arch('x86_64'), '-cpu', 'help'],
> + noerr => 1,
> + quiet => 1,
> + outfunc => sub {
> + my ($line) = @_;
> +
> + if ($flag_section) {
> + return if $line =~ m/^\s*$/;
> + $line =~ m/^\s*(.+?)\s*$/;
> + ($line = $1) =~ s/-|\./_/g;
> + my @flags_line = split(m/\s+/, $line);
> + @$flags = (@$flags, @flags_line);
this is a bit confusing to read, how about the following:
return if $line =~ m/^\s*$/;
$line =~ s/^\s*|\s*$//g;
$line =~ s/-|\./_/g;
push @$flags, split /\s+/, $line;
I assume replacing - and . with _ is to be compatible with
/proc/cpuinfo? wouldn't it make more sense to keep the Qemu-provided
values in the format that Qemu uses and understands, and just do the
conversion when we want to check for membership/intersections between
the two sets?
> + } elsif ($line =~ m/^\s*Recognized CPUID flags:\s*$/) {
> + $flag_section = 1;
> + }
last } is wrongly indented in the block above, it closes the elsif, not
the sub block
> + });
> +
> + return $flags;
> +}
> +
a comment here that query_supported_cpu_flags is very expensive, and
that the information is available via pvestatd/pmxcfs/node_kv "for free"
would be nice to prevent future misuse ;)
> +sub query_supported_cpu_flags {
> + my $flags = [];
> +
> + my $pidfile = '/var/run/qemu-server/-1.pid';
please re-use "pidfile_name" to avoid problems in the future, and move
the special '-1' value into a variable.
> +
> + # We start a temporary (frozen) VM with vmid -1 to allow us to send a QMP command
this is missing locking, otherwise you get races and failing calls. I
think you can re-use the regular local flock for the VM config
(QemuConfig->lock_config), and don't need to invent anything special.
> + my $rc = run_command([
> + get_command_for_arch('x86_64'),
> + '-cpu', 'kvm64',
> + '-display', 'none',
> + '-chardev', 'socket,id=qmp,path=/var/run/qemu-server/-1.qmp,server,nowait',
> + '-mon', 'chardev=qmp,mode=control',
> + '-pidfile', $pidfile,
> + '-S',
> + '-daemonize'
> + ], noerr => 1, quiet => 1);
> + return [] if $rc;
I wonder whether we could do better error handling here? maybe also let
pvestatd not overwrite potentially existing values in the KV store if
this dies/returns empty?
> +
> + my $qmpclient = PVE::QMPClient->new();
> + $qmpclient->queue_cmd(
> + -1,
> + sub {
> + my ($vmid, $response) = @_;
> +
> + return if %{$response->{error}};
> +
> + my $props = $response->{return}->{model}->{props};
> + return if !%$props;
> +
> + foreach my $prop_raw (keys %$props) {
> + (my $prop = $prop_raw) =~ s/-|\./_/g;
same as above with the conversion
> + push @$flags, $prop if "$props->{$prop_raw}" eq '1';
> + }
> + },
> + 'query-cpu-model-expansion',
> + type => 'full',
> + model => { name => 'host' });
> + $qmpclient->queue_cmd(-1, undef, 'quit');
why not re-use vm_stop with $nocheck? it does all the waiting, kill
with increasingly heavy signals, etc.pp.
> + $qmpclient->queue_execute(3, 2);
> +
> + # Wait for QEMU to terminate
> + sleep 1;
> +
> + if (-e $pidfile) {
> + $rc = run_command([
> + 'pkill', '-F', $pidfile
> + ], noerr => 1, quiet => 1);
> +
> + warn 'QEMU instance used for host CPU flag detection could not be killed\n' if $rc;
all of this would then just be an eval + proper error message ;) you
could also use a simple vm_mon_cmd_nocheck instead of the whole queue
thing.
> + }
> +
> + return $flags;
> +}
> +
> sub get_cpu_options {
> my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
>
> --
> 2.20.1
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel at pve.proxmox.com
> https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
More information about the pve-devel
mailing list