88from drgn import cast
99from drgn import Object
1010from drgn import Program
11+ from drgn .helpers .common .type import enum_type_to_class
1112from drgn .helpers .linux .list import list_for_each_entry
1213from drgn .helpers .linux .pid import find_task
1314from drgn .helpers .linux .sched import task_state_to_char
1415from drgn .helpers .linux .xarray import xa_for_each
1516
1617from drgn_tools .corelens import CorelensModule
1718from drgn_tools .table import print_table
19+ from drgn_tools .util import enum_name_get
1820from drgn_tools .util import has_member
1921
2022
@@ -268,6 +270,203 @@ def print_memslot_info(prog: Program) -> None:
268270 print ("\n ## Total Pages: %d ##" % (nr_pages ))
269271
270272
273+ def print_ioeventfd_info (prog : Program ) -> None :
274+ """
275+ Print VM's ioeventfd information
276+ """
277+ vm_list = for_each_vm (prog )
278+
279+ rows = [["KVM" , "IOEVENTFD" , "ADDR" , "EVENTFD_CTX" , "KVM_IO_DEV" ]]
280+ nr_ioeventfds = 0
281+
282+ for vm in vm_list :
283+ iofd = list_for_each_entry (
284+ "struct _ioeventfd" , vm .ioeventfds .address_of_ (), "list"
285+ )
286+ for fd in iofd :
287+ addr = hex (fd .addr .value_ ())
288+ ioeventfd = hex (fd .eventfd .value_ ())
289+ dev = fd .dev .address_of_ ()
290+ nr_ioeventfds = nr_ioeventfds + 1
291+ rows .append (
292+ [hex (vm .value_ ()), hex (fd .value_ ()), addr , ioeventfd , hex (dev )]
293+ )
294+ print ("=============<< IOEVENTFDS >>=============" )
295+ print_table (rows )
296+ print ("\n ## Total ioeventfds: ##" , nr_ioeventfds )
297+
298+
299+ def print_iobus_info (prog : Program ) -> None :
300+ """
301+ Print iobus information of VM
302+ """
303+ rows = [
304+ ["KVM" , "IOBUS" , "BUS" , "DEV_COUNT" , "EVTFD_COUNT" , "KVM_IO_RANGE" ]
305+ ]
306+
307+ vm_list = for_each_vm (prog )
308+ kvm_bus_type = enum_type_to_class (
309+ prog .type ("enum kvm_bus" ), "kvm_bus_type"
310+ )
311+
312+ for vm in vm_list :
313+ iobus_iterator = iter (vm .buses )
314+ for i , bus in enumerate (iobus_iterator ):
315+ iobus = hex (bus .value_ ())
316+ dev_count = bus .dev_count .value_ ()
317+ eventfd_count = bus .ioeventfd_count .value_ ()
318+ bus_name = enum_name_get (
319+ kvm_bus_type ,
320+ i ,
321+ "UNKNOWN" ,
322+ )
323+ range = hex (bus .range .address_of_ ())
324+ rows .append (
325+ [
326+ hex (vm .value_ ()),
327+ iobus ,
328+ str (bus_name ),
329+ dev_count ,
330+ eventfd_count ,
331+ range ,
332+ ]
333+ )
334+ print ("=============<< IOBUS >>=============" )
335+ print_table (rows )
336+
337+
338+ def print_kvmstat_info (prog : Program ) -> None :
339+ """
340+ print vmstat and vcpustat information of a VM
341+ """
342+ vm_list = for_each_vm (prog )
343+
344+ for vm in vm_list :
345+ stat = vm .stat
346+ if has_member (stat , "generic" ):
347+ rtlab_flush = stat .generic .remote_tlb_flush .value_ ()
348+ else :
349+ rtlab_flush = stat .remote_tlb_flush .value_ ()
350+ if has_member (stat , "lpages" ):
351+ lpages = stat .lpages .value_ ()
352+ else :
353+ lpages = "NA"
354+ if has_member (stat , "pages_1g" ):
355+ pages_1g = stat .pages_1g .counter .value_ ()
356+ else :
357+ pages_1g = "NA"
358+ if has_member (stat , "pages_2m" ):
359+ pages_2m = stat .pages_2m .counter .value_ ()
360+ else :
361+ pages_2m = "NA"
362+ if has_member (stat , "pages_4k" ):
363+ pages_4k = stat .pages_4k .counter .value_ ()
364+ else :
365+ pages_4k = "NA"
366+
367+ print ("=============<< VMSTAT >>============= \n " )
368+ rows_mm = [
369+ ["KVM" , hex (vm .value_ ())],
370+ ["KVM_STAT" , hex (vm .stat .address_of_ ())],
371+ ["Remote TLB Flush" , rtlab_flush ],
372+ ["MMU Shadow Zapped" , stat .mmu_shadow_zapped .value_ ()],
373+ ["MMU PTE Write" , stat .mmu_pte_write .value_ ()],
374+ ["MMU PDE Zapped" , stat .mmu_pde_zapped .value_ ()],
375+ ["MMU Floaded" , stat .mmu_flooded .value_ ()],
376+ ["MMU Recycled" , stat .mmu_recycled .value_ ()],
377+ ["MMU Cache Miss" , stat .mmu_cache_miss .value_ ()],
378+ ["MMU Unsync" , stat .mmu_unsync .value_ ()],
379+ ["Lpages" , lpages ],
380+ ["NX Lpage Splits" , stat .nx_lpage_splits .value_ ()],
381+ [
382+ "Max MMU Page Hash Collisions" ,
383+ stat .max_mmu_page_hash_collisions .value_ (),
384+ ],
385+ ["Pages_1G" , pages_1g ],
386+ ["Pgaes_2M" , pages_2m ],
387+ ["Pages_4k" , pages_4k ],
388+ ]
389+ print_table (rows_mm )
390+
391+ print ("\n =============<< VCPU STAT >>============ \n " )
392+ for vcpu in for_each_vcpu (vm ):
393+ vcpu_stat = vcpu .stat
394+ rows_vcpu = [
395+ [
396+ "VCPU:" ,
397+ vcpu .vcpu_id .value_ (),
398+ "HALT_SUC:" ,
399+ vcpu_stat .generic .halt_successful_poll .value_ (),
400+ "HALT_ATTMPT:" ,
401+ vcpu_stat .generic .halt_attempted_poll .value_ (),
402+ "HALT_INV:" ,
403+ vcpu_stat .generic .halt_poll_invalid .value_ (),
404+ ],
405+ [
406+ "PF_FIXED:" ,
407+ vcpu_stat .pf_fixed .value_ (),
408+ "PF_GUEST:" ,
409+ vcpu_stat .pf_guest .value_ (),
410+ "TLB_FLUSH:" ,
411+ vcpu_stat .tlb_flush .value_ (),
412+ "INVLPG:" ,
413+ vcpu_stat .invlpg .value_ (),
414+ ],
415+ [
416+ "EXITS:" ,
417+ vcpu_stat .exits .value_ (),
418+ "IO_EXIT:" ,
419+ vcpu_stat .io_exits .value_ (),
420+ "MMIO_EXIT:" ,
421+ vcpu_stat .mmio_exits .value_ (),
422+ "SIG_EXIT:" ,
423+ vcpu_stat .signal_exits .value_ (),
424+ ],
425+ [
426+ "IRQ_WIN_EXIT:" ,
427+ vcpu_stat .irq_window_exits .value_ (),
428+ "NMI_WIN_EXIT:" ,
429+ vcpu_stat .nmi_window_exits .value_ (),
430+ "L1D_FLUSH:" ,
431+ vcpu_stat .l1d_flush .value_ (),
432+ "HALT_EXIT:" ,
433+ vcpu_stat .halt_exits .value_ (),
434+ ],
435+ [
436+ "REQ_IRQ_EXIT:" ,
437+ vcpu_stat .request_irq_exits .value_ (),
438+ "IRQ_EXITS:" ,
439+ vcpu_stat .irq_exits .value_ (),
440+ "HOST_STATE_RL:" ,
441+ vcpu_stat .host_state_reload .value_ (),
442+ "FPU_RL:" ,
443+ vcpu_stat .fpu_reload .value_ (),
444+ ],
445+ [
446+ "INSN_EMUL:" ,
447+ vcpu_stat .insn_emulation .value_ (),
448+ "INSN_EMUL_FAIL:" ,
449+ vcpu_stat .insn_emulation_fail .value_ (),
450+ "HYPERCALLS:" ,
451+ vcpu_stat .hypercalls .value_ (),
452+ "IRQ_INJ:" ,
453+ vcpu_stat .irq_injections .value_ (),
454+ ],
455+ [
456+ "NMI_INJ:" ,
457+ vcpu_stat .nmi_injections .value_ (),
458+ "REQ_EVENT:" ,
459+ vcpu_stat .req_event .value_ (),
460+ "PREEMPT_RPT:" ,
461+ vcpu_stat .preemption_reported .value_ (),
462+ "PREEMT_OTH:" ,
463+ vcpu_stat .preemption_other .value_ (),
464+ ],
465+ ]
466+ print ()
467+ print_table (rows_vcpu )
468+
469+
271470class KvmUtil (CorelensModule ):
272471 """
273472 Show all the VM related info from KVM host side
@@ -277,9 +476,7 @@ class KvmUtil(CorelensModule):
277476
278477 default_args = [
279478 [
280- "--vms" ,
281- "--vcpu" ,
282- "--mmslot" ,
479+ "--all" ,
283480 ]
284481 ]
285482
@@ -302,12 +499,41 @@ def add_args(self, parser: argparse.ArgumentParser) -> None:
302499 action = "store_true" ,
303500 help = "show all memslot info" ,
304501 )
502+ parser .add_argument (
503+ "--ioeventfd" ,
504+ dest = "ioeventfds" ,
505+ action = "store_true" ,
506+ help = "show all ioeventfds info" ,
507+ )
508+ parser .add_argument (
509+ "--iobus" ,
510+ dest = "iobus" ,
511+ action = "store_true" ,
512+ help = "show all iobus info" ,
513+ )
514+ parser .add_argument (
515+ "--kvmstat" ,
516+ dest = "kvmstat" ,
517+ action = "store_true" ,
518+ help = "show all iobus info" ,
519+ )
520+ parser .add_argument (
521+ "--all" ,
522+ action = "store_true" ,
523+ help = "show all of the above info" ,
524+ )
305525
306526 def run (self , prog : Program , args : argparse .Namespace ) -> None :
307- if args .list_vm :
527+ if args .list_vm or args . all :
308528 print_vm_list (prog )
309- if args .vcpu_list :
529+ if args .vcpu_list or args . all :
310530 print_vcpu_list (prog )
311- if args .memslot :
531+ if args .memslot or args . all :
312532 print_memslot_info (prog )
533+ if args .ioeventfds or args .all :
534+ print_ioeventfd_info (prog )
535+ if args .iobus or args .all :
536+ print_iobus_info (prog )
537+ if args .kvmstat or args .all :
538+ print_kvmstat_info (prog )
313539 return
0 commit comments