diff --git a/virtme/commands/run.py b/virtme/commands/run.py index 2a91b7e..6cbdeed 100644 --- a/virtme/commands/run.py +++ b/virtme/commands/run.py @@ -151,6 +151,12 @@ def make_parser() -> argparse.ArgumentParser: default=None, help="Set guest memory and qemu -m flag.", ) + g.add_argument( + "--numa", + action="append", + default=None, + help="Create NUMA nodes in the guest.", + ) g.add_argument( "--cpus", action="store", default=None, help="Set guest cpu and qemu -smp flag." ) @@ -643,11 +649,14 @@ def export_virtiofs( # Adjust qemu options to use virtiofsd fsid = "virtfs%d" % len(qemuargs) - if memory is None: - memory = "128M" + vhost_dev_type = arch.vhost_dev_type() qemuargs.extend(["-chardev", f"socket,id=char{fsid},path={virtio_fs.sock}"]) qemuargs.extend(["-device", f"{vhost_dev_type},chardev=char{fsid},tag={mount_tag}"]) + if memory is None: + memory = "128M" + elif memory == 0: + return True qemuargs.extend(["-object", f"memory-backend-memfd,id=mem,size={memory},share=on"]) qemuargs.extend(["-numa", "node,memdev=mem"]) @@ -724,7 +733,7 @@ def can_use_kvm(): def can_use_microvm(args): - return not args.disable_microvm and args.arch == "x86_64" and can_use_kvm() + return not args.disable_microvm and not args.numa and args.arch == "x86_64" and can_use_kvm() def has_read_acl(username, file_path): @@ -799,6 +808,16 @@ def do_it() -> int: args.memory += "M" qemuargs.extend(["-m", args.memory]) + # Parse NUMA settings. + if args.numa: + for i, numa in enumerate(args.numa, start=1): + size, cpus = numa.split(",", 1) if "," in numa else (numa, None) + cpus = f",{cpus}" if cpus else "" + qemuargs.extend([ + "-object", f"memory-backend-memfd,id=mem{i},size={size},share=on", + "-numa", f"node,memdev=mem{i}{cpus}" + ]) + if args.snaps: if args.root == "/": snapd_state = "/var/lib/snapd/state.json" @@ -853,7 +872,10 @@ def do_it() -> int: args.root, "ROOTFS", guest_tools_path=guest_tools_path, - memory=args.memory, + # virtiofsd requires a NUMA not, if --numa is specified simply use + # the user-defined NUMA node, otherwise create a NUMA node with all + # the memory. + memory=0 if args.numa else args.memory, verbose=args.verbose, ) if can_use_microvm(args) and use_virtiofs: diff --git a/virtme_ng/run.py b/virtme_ng/run.py index 409e1a0..e340fc8 100644 --- a/virtme_ng/run.py +++ b/virtme_ng/run.py @@ -280,6 +280,13 @@ def make_parser(): "--memory", "-m", action="store", help="Set guest memory size (qemu -m flag)" ) + parser.add_argument( + "--numa", + metavar="MEM[,cpus=FIRST_CPU1[-LAST_CPU1]][,cpus=FIRST_CPU2[-LAST_CPU2]]...", + action="append", + help="Create NUMA nodes in the guest (this implicitly disables the microvm architecture)" + ) + parser.add_argument( "--balloon", action="store_true", @@ -879,6 +886,13 @@ def _get_virtme_memory(self, args): else: self.virtme_param["memory"] = "--memory " + args.memory + def _get_virtme_numa(self, args): + if args.numa is not None: + numa_str = " ".join([f"--numa {numa}" for numa in args.numa]) + self.virtme_param["numa"] = numa_str + else: + self.virtme_param["numa"] = "" + def _get_virtme_balloon(self, args): if args.balloon: self.virtme_param["balloon"] = "--balloon" @@ -948,6 +962,7 @@ def run(self, args): self._get_virtme_append(args) self._get_virtme_cpus(args) self._get_virtme_memory(args) + self._get_virtme_numa(args) self._get_virtme_balloon(args) self._get_virtme_snaps(args) self._get_virtme_busybox(args) @@ -982,6 +997,7 @@ def run(self, args): + f'{self.virtme_param["append"]} ' + f'{self.virtme_param["cpus"]} ' + f'{self.virtme_param["memory"]} ' + + f'{self.virtme_param["numa"]} ' + f'{self.virtme_param["balloon"]} ' + f'{self.virtme_param["snaps"]} ' + f'{self.virtme_param["busybox"]} '