@@ -404,12 +404,12 @@ def get_vm_stats(self, previous_time=None, previous=None, only_vm=None):
404404 - ``cpu_usage_raw`` - CPU usage in %.
405405 - ``cpu_usage`` - CPU usage in % (normalized to number of vcpus).
406406
407- This function requires Xen hypervisor.
407+ This function requires Xen hypervisor for detailed overview .
408408
409409 ..warning:
410410
411411 This function may return info about implementation-specific VMs,
412- like stubdomains for HVM
412+ like stubdomains for HVM, aggregated to the connected domain.
413413
414414 :param previous: previous measurement
415415 :param previous_time: time of previous measurement
@@ -428,46 +428,106 @@ def get_vm_stats(self, previous_time=None, previous=None, only_vm=None):
428428
429429 current_time = time .time ()
430430 current = {}
431- if not self .app .vmm .is_xen :
432- raise NotImplementedError ("This function requires Xen hypervisor" )
433431 if only_vm :
434432 xid = only_vm .xid
435433 if xid < 0 :
436434 raise qubes .exc .QubesVMNotRunningError (only_vm )
437- info = self .app .vmm .xc .domain_getinfo (xid , 1 )
438- if info [0 ]["domid" ] != xid :
439- raise qubes .exc .QubesVMNotRunningError (only_vm )
435+ if self .app .vmm .is_xen :
436+ info = self .app .vmm .xc .domain_getinfo (xid , 1 )
437+ if info [0 ]["domid" ] != xid :
438+ raise qubes .exc .QubesVMNotRunningError (only_vm )
439+ if (
440+ only_vm_stubdom_xid := getattr (only_vm , "stubdom_xid" , - 1 )
441+ ) and only_vm_stubdom_xid > 0 :
442+ stubdom_info = self .app .vmm .xc .domain_getinfo (
443+ only_vm_stubdom_xid , 1
444+ )[0 ]
445+ info .append (stubdom_info )
446+ else :
447+ if not only_vm .libvirt_domain :
448+ raise qubes .exc .QubesVMNotRunningError (only_vm )
449+ dom_info = only_vm .libvirt_domain .info ()
450+ info = [
451+ {
452+ "domid" : only_vm .xid ,
453+ "maxmem_kb" : dom_info [1 ],
454+ "mem_kb" : dom_info [2 ],
455+ "online_vcpus" : dom_info [3 ],
456+ "cpu_time" : dom_info [4 ],
457+ }
458+ ]
440459 else :
441- info = self .app .vmm .xc .domain_getinfo (0 , 1024 )
442-
443- # TODO: add stubdomain stats to actual VMs
444- for vm in info :
445- domid = vm ["domid" ]
460+ if self .app .vmm .is_xen :
461+ info = self .app .vmm .xc .domain_getinfo (0 , 1024 )
462+ else :
463+ running = self .app .vmm .libvirt_conn .listAllDomains (
464+ libvirt .VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE
465+ )
466+ info = []
467+ for dom in running :
468+ dom_info = dom .info ()
469+ dom_info_dict = {
470+ "domid" : dom .ID (),
471+ "maxmem_kb" : dom_info [1 ],
472+ "mem_kb" : dom_info [2 ],
473+ "online_vcpus" : dom_info [3 ],
474+ "cpu_time" : dom_info [4 ],
475+ }
476+ info .append (dom_info_dict )
477+
478+ def sum_stubdom (key , info , domid , stubdom_xid ):
479+ data = info [domid ][key ]
480+ if stubdom_xid and stubdom_xid > 0 :
481+ data += info [stubdom_xid ][key ]
482+ return data
483+
484+ stubdoms = []
485+ info = sorted (info , key = lambda domain : domain ["domid" ])
486+ info = {v ["domid" ]: v for v in info }
487+ for domid in info .keys ():
488+ stubdom_xid = None
489+ if domid in stubdoms :
490+ continue
446491 current [domid ] = {}
447492 current [domid ].setdefault ("is_stubdom" , None )
493+
448494 if domid in previous :
449495 name = previous [domid ]["name" ]
450496 current [domid ]["is_stubdom" ] = previous [domid ]["is_stubdom" ]
497+ if current [domid ]["is_stubdom" ]:
498+ continue
451499 else :
452500 name = self .app .get_name_from_domid (domid )
453501 if name == "Domain-0" :
454502 name = "dom0"
455503 current [domid ]["name" ] = name
504+
456505 qube = None
457506 if current [domid ]["is_stubdom" ] in [None , False ]:
458507 try :
459508 qube = self .app .domains [current [domid ]["name" ]]
460509 except KeyError :
461510 current [domid ]["is_stubdom" ] = True
511+ if domid not in stubdoms :
512+ stubdoms .append (domid )
513+ continue
462514 else :
463515 current [domid ]["is_stubdom" ] = False
516+ if (
517+ qube
518+ and (stubdom_xid := getattr (qube , "stubdom_xid" , None ))
519+ and stubdom_xid > 0
520+ ):
521+ stubdoms .append (stubdom_xid )
464522
465523 if getattr (qube , "virt_mode" , None ) == "hvm" :
466524 # Consider videoram.
467525 memory_assigned_key = "maxmem_kb"
468526 else :
469527 memory_assigned_key = "mem_kb"
470- current [domid ]["memory_assigned_KiB" ] = vm [memory_assigned_key ]
528+ current [domid ]["memory_assigned_KiB" ] = sum_stubdom (
529+ memory_assigned_key , info , domid , stubdom_xid
530+ )
471531 current [domid ]["memory_kb" ] = current [domid ]["memory_assigned_KiB" ]
472532 current [domid ]["memory_used_KiB" ] = current [domid ][
473533 "memory_assigned_KiB"
@@ -485,8 +545,13 @@ def get_vm_stats(self, previous_time=None, previous=None, only_vm=None):
485545 current [domid ]["memory_used_KiB" ] = int (meminfo )
486546 else :
487547 del untrusted_meminfo
488- current [domid ]["online_vcpus" ] = max (vm ["online_vcpus" ], 1 )
489- current [domid ]["cpu_time" ] = round (vm ["cpu_time" ])
548+
549+ current [domid ]["online_vcpus" ] = max (
550+ sum_stubdom ("online_vcpus" , info , domid , stubdom_xid ), 1
551+ )
552+ current [domid ]["cpu_time" ] = round (
553+ sum_stubdom ("cpu_time" , info , domid , stubdom_xid )
554+ )
490555 if domid in previous :
491556 current [domid ]["cpu_usage_raw" ] = round (
492557 (current [domid ]["cpu_time" ] - previous [domid ]["cpu_time" ])
0 commit comments