Skip to contentSkip to conversation

Add support for binding guest numa nodes to host numa nodes

PATCH In review Hu Tao 2 participants 15 messages Mar 4, 2014 Arm STM32

lore
Share & tools
lore

Hu Tao

author
#0 lore raw

v19 cover Add support for binding guest numa nodes to host numa nodes

Based on series `convert -numa to QemuOpts/OptsVisitor' posted by Igor at http://lists.nongnu.org/archive/html/qemu-devel/2014-02/msg02801.html.

You can also checkout this series out at
https://github.com/taohu/qemu/tree/numa-binding-v19, including all required patches.

changes in v19:

- use complete() method of user_creatable in memdev backend
- implement qmp query-memdev by walking through numa_info[...].node_memdev and using object_property_get to get information as suggested by Paolo
- implement info memdev
- drop ram_backend->relative
- make string output visitor parse int list
- introduce libnuma

Hu Tao (5):
qapi: make string input visitor parse int list
qapi: make string output visitor parse int list
hostmem backend: implement memory policy
qmp: add query-memdev
hmp: add info memdev

Igor Mammedov (2):
object_add: allow completion handler to get canonical path add memdev backend infrastructure

Paolo Bonzini (3):
pc: pass QEMUMachineInitArgs to pc_memory_init
numa: introduce memory_region_allocate_system_memory
numa: add -numa node,memdev= option

Wanlong Gao (1):
Add detection of libnuma (mostly contained in the numactl package)
to the configure script. Can be enabled or disabled on the command
line, default is use if available.

 backends/Makefile.objs             |   2 +
 backends/hostmem-ram.c             |  77 ++++++++++++++
 backends/hostmem.c                 | 202 +++++++++++++++++++++++++++++++++++++
 configure                          |  33 ++++++
 hmp.c                              |  27 +++++
 hmp.h                              |   1 +
 hw/i386/pc.c                       |  15 ++-
 hw/i386/pc_piix.c                  |   8 +-
 hw/i386/pc_q35.c                   |   4 +-
 include/hw/i386/pc.h               |   7 +-
 include/sysemu/hostmem.h           |  64 ++++++++++++
 include/sysemu/sysemu.h            |   8 ++
 monitor.c                          |   7 ++
 numa.c                             | 133 ++++++++++++++++++++++++
 qapi-schema.json                   |  57 ++++++++++-
 qapi/string-input-visitor.c        | 160 +++++++++++++++++++++++++++--
 qapi/string-output-visitor.c       | 156 +++++++++++++++++++++++++++-
 qmp-commands.hx                    |  32 ++++++
 qmp.c                              |   8 +-
 tests/test-string-input-visitor.c  |  21 ++++
 tests/test-string-output-visitor.c |  26 +++++
 vl.c                               |   9 +-
 22 files changed, 1017 insertions(+), 40 deletions(-)
 create mode 100644 backends/hostmem-ram.c
 create mode 100644 backends/hostmem.c
 create mode 100644 include/sysemu/hostmem.h
Signature · 1 line
1.8.5.2.229.g4448466
author
#1 lore raw

PATCH v19 1/11 object_add: allow completion handler to get canonical path

From: Igor Mammedov <[email protected]>

Add object to /objects before calling user_creatable_complete() handler, so that object might be able to call object_get_canonical_path() in its completion handler.

---
 qmp.c | 8 +++++---
 vl.c  | 9 +++++----
 2 files changed, 10 insertions(+), 7 deletions(-)
qmp.c +5 -3
index d0d98e7..2ff943d 100644
@@ -561,13 +561,15 @@ void object_add(const char *type, const char *id, const QDict *qdict,
         goto out;
     }
 
+    object_property_add_child(container_get(object_get_root(), "/objects"),
+                              id, obj, &local_err);
+
     user_creatable_complete(obj, &local_err);
     if (local_err) {
+        object_property_del(container_get(object_get_root(), "/objects"),
+                            id, &error_abort);
         goto out;
     }
-
-    object_property_add_child(container_get(object_get_root(), "/objects"),
-                              id, obj, &local_err);
 out:
     if (local_err) {
         error_propagate(errp, local_err);
vl.c +5 -4
index 899b63f..7d9ac8a 100644
@@ -2673,14 +2673,15 @@ static int object_create(QemuOpts *opts, void *opaque)
         goto out;
     }
 
+    object_property_add_child(container_get(object_get_root(), "/objects"),
+                              id, obj, &local_err);
+
     user_creatable_complete(obj, &local_err);
     if (local_err) {
+        object_property_del(container_get(object_get_root(), "/objects"),
+                            id, &error_abort);
         goto out;
     }
-
-    object_property_add_child(container_get(object_get_root(), "/objects"),
-                              id, obj, &local_err);
-
 out:
     object_unref(obj);
     if (local_err) {
Signature · 1 line
1.8.5.2.229.g4448466
author
#2 lore raw

PATCH v19 2/11 add memdev backend infrastructure

In reply to Hu Tao

From: Igor Mammedov <[email protected]>

Provides framework for splitting host RAM allocation/ policies into a separate backend that could be used by devices.

Initially only legacy RAM backend is provided, which uses memory_region_init_ram() allocator and compatible with every CLI option that affects memory_region_init_ram().

[override UserCreatableClass::complete in HostMemoryBackendRamClass]
---
 backends/Makefile.objs   |   2 +
 backends/hostmem-ram.c   |  77 +++++++++++++++++++++++++++++++++
 backends/hostmem.c       | 110 +++++++++++++++++++++++++++++++++++++++++++++++
 include/sysemu/hostmem.h |  60 ++++++++++++++++++++++++++
 4 files changed, 249 insertions(+)
 create mode 100644 backends/hostmem-ram.c
 create mode 100644 backends/hostmem.c
 create mode 100644 include/sysemu/hostmem.h
backends/Makefile.objs +2 -0
index 42557d5..e6bdc11 100644
@@ -6,3 +6,5 @@ common-obj-$(CONFIG_BRLAPI) += baum.o
 $(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) 
 
 common-obj-$(CONFIG_TPM) += tpm.o
+
+common-obj-y += hostmem.o hostmem-ram.o
backends/hostmem-ram.c new file +77 -0

77 lines not on this page · raw message

backends/hostmem.c new file +110 -0

110 lines not on this page · raw message

include/sysemu/hostmem.h new file +60 -0

60 lines not on this page · raw message

Signature · 1 line
1.8.5.2.229.g4448466
author
#3 lore raw

PATCH v19 3/11 pc: pass QEMUMachineInitArgs to pc_memory_init

In reply to Hu Tao

From: Paolo Bonzini <[email protected]>

---
 hw/i386/pc.c         | 11 +++++------
 hw/i386/pc_piix.c    |  8 +++-----
 hw/i386/pc_q35.c     |  4 +---
 include/hw/i386/pc.h |  7 +++----
 4 files changed, 12 insertions(+), 18 deletions(-)
hw/i386/pc.c +5 -6
index 42182f9..44ee3b8 100644
@@ -1145,10 +1145,8 @@ void pc_acpi_init(const char *default_dsdt)
     }
 }
 
-FWCfgState *pc_memory_init(MemoryRegion *system_memory,
-                           const char *kernel_filename,
-                           const char *kernel_cmdline,
-                           const char *initrd_filename,
+FWCfgState *pc_memory_init(QEMUMachineInitArgs *args,
+                           MemoryRegion *system_memory,
                            ram_addr_t below_4g_mem_size,
                            ram_addr_t above_4g_mem_size,
                            MemoryRegion *rom_memory,
@@ -1160,7 +1158,7 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
     MemoryRegion *ram_below_4g, *ram_above_4g;
     FWCfgState *fw_cfg;
 
-    linux_boot = (kernel_filename != NULL);
+    linux_boot = (args->kernel_filename != NULL);
 
     /* Allocate RAM.  We allocate it as a single memory region and use
      * aliases to address portions of it, mostly for backwards compatibility
@@ -1201,7 +1199,8 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
     rom_set_fw(fw_cfg);
 
     if (linux_boot) {
-        load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
+        load_linux(fw_cfg, args->kernel_filename, args->initrd_filename,
+                   args->kernel_cmdline, below_4g_mem_size);
     }
 
     for (i = 0; i < nb_option_roms; i++) {
hw/i386/pc_piix.c +3 -5
index d5dc1ef..96adc01 100644
@@ -151,11 +151,9 @@ static void pc_init1(QEMUMachineInitArgs *args,
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
-        fw_cfg = pc_memory_init(system_memory,
-                       args->kernel_filename, args->kernel_cmdline,
-                       args->initrd_filename,
-                       below_4g_mem_size, above_4g_mem_size,
-                       rom_memory, &ram_memory, guest_info);
+        fw_cfg = pc_memory_init(args, system_memory,
+                                below_4g_mem_size, above_4g_mem_size,
+                                rom_memory, &ram_memory, guest_info);
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
hw/i386/pc_q35.c +1 -3
index a7f6260..95fa01fc 100644
@@ -138,9 +138,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
-        pc_memory_init(get_system_memory(),
-                       args->kernel_filename, args->kernel_cmdline,
-                       args->initrd_filename,
+        pc_memory_init(args, get_system_memory(),
                        below_4g_mem_size, above_4g_mem_size,
                        rom_memory, &ram_memory, guest_info);
     }
include/hw/i386/pc.h +3 -4
index 9010246..8fc0527 100644
@@ -3,6 +3,7 @@
 
 #include "qemu-common.h"
 #include "exec/memory.h"
+#include "hw/boards.h"
 #include "hw/isa/isa.h"
 #include "hw/block/fdc.h"
 #include "net/net.h"
@@ -134,10 +135,8 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
 void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
                             MemoryRegion *pci_address_space);
 
-FWCfgState *pc_memory_init(MemoryRegion *system_memory,
-                           const char *kernel_filename,
-                           const char *kernel_cmdline,
-                           const char *initrd_filename,
+FWCfgState *pc_memory_init(QEMUMachineInitArgs *args,
+                           MemoryRegion *system_memory,
                            ram_addr_t below_4g_mem_size,
                            ram_addr_t above_4g_mem_size,
                            MemoryRegion *rom_memory,
Signature · 1 line
1.8.5.2.229.g4448466
author
#4 lore raw

PATCH v19 4/11 numa: introduce memory_region_allocate_system_memory

In reply to Hu Tao

From: Paolo Bonzini <[email protected]>

---
 hw/i386/pc.c            |  4 +---
 include/sysemu/sysemu.h |  5 +++++
 numa.c                  | 10 ++++++++++
 3 files changed, 16 insertions(+), 3 deletions(-)
hw/i386/pc.c +1 -3
index 44ee3b8..27f0f1f 100644
@@ -1165,9 +1165,7 @@ FWCfgState *pc_memory_init(QEMUMachineInitArgs *args,
      * with older qemus that used qemu_ram_alloc().
      */
     ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, NULL, "pc.ram",
-                           below_4g_mem_size + above_4g_mem_size);
-    vmstate_register_ram_global(ram);
+    memory_region_allocate_system_memory(ram, NULL, "pc.ram", args);
     *ram_memory = ram;
     ram_below_4g = g_malloc(sizeof(*ram_below_4g));
     memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ram,
include/sysemu/sysemu.h +5 -0
index 4c94cf5..e9da760 100644
@@ -10,6 +10,8 @@
 #include "qemu/notify.h"
 #include "qemu/main-loop.h"
 #include "qemu/bitmap.h"
+#include "qom/object.h"
+#include "hw/boards.h"
 
 /* vl.c */
 
@@ -144,6 +146,9 @@ void set_numa_nodes(void);
 void set_numa_modes(void);
 extern QemuOptsList qemu_numa_opts;
 int numa_init_func(QemuOpts *opts, void *opaque);
+void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
+                                          const char *name,
+                                          QEMUMachineInitArgs *args);
 
 #define MAX_OPTION_ROMS 16
 typedef struct QEMUOptionRom {
numa.c +10 -0
index 40c28b3..6441d14 100644
@@ -187,3 +187,13 @@ void set_numa_modes(void)
         }
     }
 }
+
+void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner,
+                                          const char *name,
+                                          QEMUMachineInitArgs *args)
+{
+    uint64_t ram_size = args->ram_size;
+
+    memory_region_init_ram(mr, owner, name, ram_size);
+    vmstate_register_ram_global(mr);
+}
Signature · 1 line
1.8.5.2.229.g4448466
author
#5 lore raw

PATCH v19 5/11 numa: add -numa node, memdev= option

In reply to Hu Tao

From: Paolo Bonzini <[email protected]>

This option provides the infrastructure for binding guest NUMA nodes to host NUMA nodes. For example:

-object memory-ram,size=1024M,policy=membind,host-nodes=0,id=ram-node0 \
-numa node,nodeid=0,cpus=0,memdev=ram-node0 \
-object memory-ram,size=1024M,policy=interleave,host-nodes=1-3,id=ram-node1 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1

The option replaces "-numa mem".

[don't include sysemu/hostmem.h in sysemu/sysemu.h to avoid mutual
inclusion.]

---
 include/sysemu/sysemu.h |  3 +++
 numa.c                  | 66 +++++++++++++++++++++++++++++++++++++++++++++++--
 qapi-schema.json        |  6 ++++-
 3 files changed, 72 insertions(+), 3 deletions(-)
include/sysemu/sysemu.h +3 -0
index e9da760..40f1df9 100644
@@ -137,9 +137,12 @@ extern QEMUClockType rtc_clock;
 #define MAX_NODES 128
 #define MAX_CPUMASK_BITS 255
 extern int nb_numa_nodes;
+struct HostMemoryBackend;
+typedef struct HostMemoryBackend HostMemoryBackend;
 typedef struct node_info {
     uint64_t node_mem;
     DECLARE_BITMAP(node_cpu, MAX_CPUMASK_BITS);
+    HostMemoryBackend *node_memdev;
 } NodeInfo;
 extern NodeInfo numa_info[MAX_NODES];
 void set_numa_nodes(void);
numa.c +64 -2

108 lines not on this page · raw message

qapi-schema.json +5 -1
index 951cc0a..62e0b83 100644
@@ -4542,6 +4542,9 @@
 #
 # @mem: #optional memory size of this node (equally divide total memory among
 #        nodes if omitted)
+# @memdev: #optional memory backend object.  If specified for one node,
+#          it must be specified for all nodes.
+#
 #
 # Since: 2.1
 ##
@@ -4549,4 +4552,5 @@
   'data': {
    '*nodeid': 'uint16',
    '*cpus':   ['uint16'],
-   '*mem':    'size' }}
+   '*mem':    'size',
+   '*memdev': 'str' }}
Signature · 1 line
1.8.5.2.229.g4448466
author
#6 lore raw

PATCH v19 6/11 qapi: make string input visitor parse int list

In reply to Hu Tao
Cc Laszlo Ersek <[email protected]>
---
 qapi/string-input-visitor.c       | 160 ++++++++++++++++++++++++++++++++++++--
 tests/test-string-input-visitor.c |  21 +++++
 2 files changed, 175 insertions(+), 6 deletions(-)
qapi/string-input-visitor.c +154 -6
index 793548a..24aab5e 100644
@@ -16,30 +16,175 @@
 #include "qapi/qmp/qerror.h"
 #include "qemu/option.h"
 
+enum ListMode {
+    LM_NONE,             /* not traversing a list of repeated options */
+    LM_STARTED,          /* start_list() succeeded */
+
+    LM_IN_PROGRESS,      /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently parsed QemuOpt instance of the repeated
+                          * option.
+                          *
+                          * Parsing a value into the list link will examine the
+                          * next QemuOpt instance of the repeated option, and
+                          * possibly enter LM_SIGNED_INTERVAL or
+                          * LM_UNSIGNED_INTERVAL.
+                          */
+
+    LM_SIGNED_INTERVAL,  /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently stored element from the signed interval,
+                          * parsed from the most recent QemuOpt instance of the
+                          * repeated option. This may consume QemuOpt itself
+                          * and return to LM_IN_PROGRESS.
+                          *
+                          * Parsing a value into the list link will store the
+                          * next element of the signed interval.
+                          */
+
+    LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
+
+    LM_END
+};
+
+typedef enum ListMode ListMode;
+
 struct StringInputVisitor
 {
     Visitor visitor;
+
+    ListMode list_mode;
+
+    /* When parsing a list of repeating options as integers, values of the form
+     * "a-b", representing a closed interval, are allowed. Elements in the
+     * range are generated individually.
+     */
+    union {
+        int64_t s;
+        uint64_t u;
+    } range_next, range_limit;
+
     const char *string;
 };
 
+static void
+start_list(Visitor *v, const char *name, Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+
+    /* we can't traverse a list in a list */
+    assert(siv->list_mode == LM_NONE);
+    siv->list_mode = LM_STARTED;
+}
+
+static GenericList *
+next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+    GenericList **link;
+
+    switch (siv->list_mode) {
+    case LM_STARTED:
+        siv->list_mode = LM_IN_PROGRESS;
+        link = list;
+        break;
+
+    case LM_SIGNED_INTERVAL:
+    case LM_UNSIGNED_INTERVAL:
+        link = &(*list)->next;
+
+        if (siv->list_mode == LM_SIGNED_INTERVAL) {
+            if (siv->range_next.s < siv->range_limit.s) {
+                ++siv->range_next.s;
+                break;
+            }
+        } else if (siv->range_next.u < siv->range_limit.u) {
+            ++siv->range_next.u;
+            break;
+        }
+        siv->list_mode = LM_END;
+        /* range has been completed, fall through */
+
+    case LM_END:
+        return NULL;
+
+    case LM_IN_PROGRESS:
+        link = &(*list)->next;
+        break;
+
+    default:
+        abort();
+    }
+
+    *link = g_malloc0(sizeof **link);
+    return *link;
+}
+
+static void
+end_list(Visitor *v, Error **errp)
+{
+    StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+
+    assert(siv->list_mode == LM_STARTED ||
+           siv->list_mode == LM_END ||
+           siv->list_mode == LM_IN_PROGRESS ||
+           siv->list_mode == LM_SIGNED_INTERVAL ||
+           siv->list_mode == LM_UNSIGNED_INTERVAL);
+    siv->list_mode = LM_NONE;
+}
+
 static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
                            Error **errp)
 {
     StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
-    char *endp = (char *) siv->string;
+    char *str = (char *) siv->string;
     long long val;
+    char *endptr;
 
-    errno = 0;
-    if (siv->string) {
-        val = strtoll(siv->string, &endp, 0);
+    if (siv->list_mode == LM_SIGNED_INTERVAL) {
+        *obj = siv->range_next.s;
+        return;
     }
-    if (!siv->string || errno || endp == siv->string || *endp) {
+
+    if (!siv->string) {
         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
                   "integer");
         return;
     }
 
-    *obj = val;
+    errno = 0;
+    val = strtoll(siv->string, &endptr, 0);
+
+    if (errno == 0 && endptr > str && INT64_MIN <= val && val <= INT64_MAX) {
+        if (*endptr == '\0') {
+            *obj = val;
+            siv->list_mode = LM_END;
+            return;
+        }
+        if (*endptr == '-' && siv->list_mode == LM_IN_PROGRESS) {
+            long long val2;
+
+            str = endptr + 1;
+            val2 = strtoll(str, &endptr, 0);
+            if (errno == 0 && endptr > str && *endptr == '\0' &&
+                INT64_MIN <= val2 && val2 <= INT64_MAX && val <= val2 &&
+                (val > INT64_MAX - 65536 ||
+                 val2 < val + 65536)) {
+                siv->range_next.s = val;
+                siv->range_limit.s = val2;
+                siv->list_mode = LM_SIGNED_INTERVAL;
+
+                /* as if entering on the top */
+                *obj = siv->range_next.s;
+                return;
+            }
+        }
+    }
+    error_set(errp, QERR_INVALID_PARAMETER_VALUE, name,
+              (siv->list_mode == LM_NONE) ? "an int64 value" :
+                                           "an int64 value or range");
 }
 
 static void parse_type_size(Visitor *v, uint64_t *obj, const char *name,
@@ -155,6 +300,9 @@ StringInputVisitor *string_input_visitor_new(const char *str)
     v->visitor.type_bool = parse_type_bool;
     v->visitor.type_str = parse_type_str;
     v->visitor.type_number = parse_type_number;
+    v->visitor.start_list = start_list;
+    v->visitor.next_list = next_list;
+    v->visitor.end_list = end_list;
     v->visitor.start_optional = parse_start_optional;
 
     v->string = str;
tests/test-string-input-visitor.c +21 -0
index d406263..31925cb 100644
@@ -64,6 +64,25 @@ static void test_visitor_in_int(TestInputVisitorData *data,
     g_assert_cmpint(res, ==, value);
 }
 
+static void test_visitor_in_intList(TestInputVisitorData *data,
+                                    const void *unused)
+{
+    int64_t value[] = {-2, -1, 0, 1, 2, 3, 4};
+    int16List *res = NULL;
+    Error *errp = NULL;
+    Visitor *v;
+    int i = 0;
+
+    v = visitor_input_test_init(data, "-2-4");
+
+    visit_type_int16List(v, &res, NULL, &errp);
+    g_assert(!error_is_set(&errp));
+    while (res && i < sizeof(value) / sizeof(value[0])) {
+        g_assert_cmpint(res->value, ==, value[i++]);
+        res = res->next;
+    }
+}
+
 static void test_visitor_in_bool(TestInputVisitorData *data,
                                  const void *unused)
 {
@@ -228,6 +247,8 @@ int main(int argc, char **argv)
 
     input_visitor_test_add("/string-visitor/input/int",
                            &in_visitor_data, test_visitor_in_int);
+    input_visitor_test_add("/string-visitor/input/intList",
+                           &in_visitor_data, test_visitor_in_intList);
     input_visitor_test_add("/string-visitor/input/bool",
                            &in_visitor_data, test_visitor_in_bool);
     input_visitor_test_add("/string-visitor/input/number",
Signature · 1 line
1.8.5.2.229.g4448466
author
#7 lore raw

PATCH v19 7/11 qapi: make string output visitor parse int list

In reply to Hu Tao

From: Hu Tao <[email protected]>

---
 qapi/string-output-visitor.c       | 156 +++++++++++++++++++++++++++++++++++--
 tests/test-string-output-visitor.c |  26 +++++++
 2 files changed, 177 insertions(+), 5 deletions(-)
qapi/string-output-visitor.c +151 -5
index fb1d2e8..bc9bb36 100644
@@ -17,11 +17,57 @@
 #include "qemu/host-utils.h"
 #include <math.h>
 
+enum ListMode {
+    LM_NONE,             /* not traversing a list of repeated options */
+    LM_STARTED,          /* start_list() succeeded */
+
+    LM_IN_PROGRESS,      /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently parsed QemuOpt instance of the repeated
+                          * option.
+                          *
+                          * Parsing a value into the list link will examine the
+                          * next QemuOpt instance of the repeated option, and
+                          * possibly enter LM_SIGNED_INTERVAL or
+                          * LM_UNSIGNED_INTERVAL.
+                          */
+
+    LM_SIGNED_INTERVAL,  /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently stored element from the signed interval,
+                          * parsed from the most recent QemuOpt instance of the
+                          * repeated option. This may consume QemuOpt itself
+                          * and return to LM_IN_PROGRESS.
+                          *
+                          * Parsing a value into the list link will store the
+                          * next element of the signed interval.
+                          */
+
+    LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
+
+    LM_END
+};
+
+typedef enum ListMode ListMode;
+
 struct StringOutputVisitor
 {
     Visitor visitor;
     bool human;
+    bool head;
     char *string;
+    ListMode list_mode;
+    /* When parsing a list of repeating options as integers, values of the form
+     * "a-b", representing a closed interval, are allowed. Elements in the
+     * range are generated individually.
+     */
+    union {
+        int64_t s;
+        uint64_t u;
+    } range_start, range_end;
+
 };
 
 static void string_output_set(StringOutputVisitor *sov, char *string)
@@ -34,13 +80,60 @@ static void print_type_int(Visitor *v, int64_t *obj, const char *name,
                            Error **errp)
 {
     StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
-    char *out;
+    char *out = NULL;
 
-    if (sov->human) {
-        out = g_strdup_printf("%lld (%#llx)", (long long) *obj, (long long) *obj);
-    } else {
-        out = g_strdup_printf("%lld", (long long) *obj);
+    switch (sov->list_mode) {
+    case LM_NONE:
+        if (sov->human) {
+            out = g_strdup_printf("%lld (%#llx)", (long long) *obj,
+                                  (long long) *obj);
+        } else {
+            out = g_strdup_printf("%lld", (long long) *obj);
+        }
+        sov->list_mode = LM_END;
+        break;
+
+    case LM_STARTED:
+        sov->range_start.s = *obj;
+        sov->range_end.s = *obj;
+        sov->list_mode = LM_IN_PROGRESS;
+        break;
+
+    case LM_IN_PROGRESS:
+        assert(sov->range_end.s + 1 == *obj);
+        sov->range_end.s++;
+        break;
+
+    case LM_END:
+        assert(sov->range_end.s + 1 == *obj);
+        sov->range_end.s++;
+        if (sov->range_end.s == sov->range_start.s) {
+            if (sov->human) {
+                out = g_strdup_printf("%lld (%#llx)",
+                                      (long long)sov->range_start.s,
+                                      (long long)sov->range_start.s);
+            } else {
+                out = g_strdup_printf("%lld", (long long)sov->range_start.s);
+            }
+        } else {
+            if (sov->human) {
+                out = g_strdup_printf("%lld(%#llx)-%lld(%#llx)",
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_end.s,
+                                      (long long) sov->range_end.s);
+            } else {
+                out = g_strdup_printf("%lld-%lld",
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_end.s);
+            }
+        }
+        break;
+
+    default:
+        abort();
     }
+
     string_output_set(sov, out);
 }
 
@@ -103,6 +196,56 @@ static void print_type_number(Visitor *v, double *obj, const char *name,
     string_output_set(sov, g_strdup_printf("%f", *obj));
 }
 
+static void
+start_list(Visitor *v, const char *name, Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+
+    /* we can't traverse a list in a list */
+    assert(sov->list_mode == LM_NONE);
+    sov->list_mode = LM_STARTED;
+    sov->head = true;
+}
+
+static GenericList *
+next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+    GenericList *ret = NULL;
+    if (*list) {
+        if (sov->head) {
+            ret = *list;
+        } else {
+            ret = (*list)->next;
+        }
+
+        if (sov->head) {
+            if (ret && ret->next == NULL) {
+                sov->list_mode = LM_NONE;
+            }
+            sov->head = false;
+        } else {
+            if (ret && ret->next == NULL) {
+                sov->list_mode = LM_END;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static void
+end_list(Visitor *v, Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+
+    assert(sov->list_mode == LM_STARTED ||
+           sov->list_mode == LM_END ||
+           sov->list_mode == LM_IN_PROGRESS);
+    sov->list_mode = LM_NONE;
+    sov->head = true;
+}
+
 char *string_output_get_string(StringOutputVisitor *sov)
 {
     char *string = sov->string;
@@ -134,6 +277,9 @@ StringOutputVisitor *string_output_visitor_new(bool human)
     v->visitor.type_bool = print_type_bool;
     v->visitor.type_str = print_type_str;
     v->visitor.type_number = print_type_number;
+    v->visitor.start_list = start_list;
+    v->visitor.next_list = next_list;
+    v->visitor.end_list = end_list;
 
     return v;
 }
tests/test-string-output-visitor.c +26 -0
index 22363d1..511ef14 100644
@@ -57,6 +57,30 @@ static void test_visitor_out_int(TestOutputVisitorData *data,
     g_free(str);
 }
 
+static void test_visitor_out_intList(TestOutputVisitorData *data,
+                                     const void *unused)
+{
+    int64_t value[] = {-2, -1, 0, 1, 2, 3, 4};
+    intList *list = NULL, **tmp = &list;
+    int i;
+    Error *errp = NULL;
+    char *str;
+
+    for (i = 0; i < sizeof(value) / sizeof(value[0]); i++) {
+        *tmp = g_malloc0(sizeof(**tmp));
+        (*tmp)->value = value[i];
+        tmp = &(*tmp)->next;
+    }
+
+    visit_type_intList(data->ov, &list, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    str = string_output_get_string(data->sov);
+    g_assert(str != NULL);
+    g_assert_cmpstr(str, ==, "-2-4");
+    g_free(str);
+}
+
 static void test_visitor_out_bool(TestOutputVisitorData *data,
                                   const void *unused)
 {
@@ -182,6 +206,8 @@ int main(int argc, char **argv)
                             &out_visitor_data, test_visitor_out_enum);
     output_visitor_test_add("/string-visitor/output/enum-errors",
                             &out_visitor_data, test_visitor_out_enum_errors);
+    output_visitor_test_add("/string-visitor/output/intList",
+                            &out_visitor_data, test_visitor_out_intList);
 
     g_test_run();
 
Signature · 1 line
1.8.5.2.229.g4448466
#8 lore raw

Re: [Qemu-devel] [PATCH v19 07/11] qapi: make string output visitor parse int list

Il 04/03/2014 08:28, Hu Tao ha scritto:

Quoted 111 lines

From: Hu Tao <[email protected]>

---
 qapi/string-output-visitor.c       | 156 +++++++++++++++++++++++++++++++++++--
 tests/test-string-output-visitor.c |  26 +++++++
 2 files changed, 177 insertions(+), 5 deletions(-)
qapi/string-output-visitor.c +77 -5
index fb1d2e8..bc9bb36 100644
@@ -17,11 +17,57 @@
 #include "qemu/host-utils.h"
 #include <math.h>
 
+enum ListMode {
+    LM_NONE,             /* not traversing a list of repeated options */
+    LM_STARTED,          /* start_list() succeeded */
+
+    LM_IN_PROGRESS,      /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently parsed QemuOpt instance of the repeated
+                          * option.
+                          *
+                          * Parsing a value into the list link will examine the
+                          * next QemuOpt instance of the repeated option, and
+                          * possibly enter LM_SIGNED_INTERVAL or
+                          * LM_UNSIGNED_INTERVAL.
+                          */
+
+    LM_SIGNED_INTERVAL,  /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently stored element from the signed interval,
+                          * parsed from the most recent QemuOpt instance of the
+                          * repeated option. This may consume QemuOpt itself
+                          * and return to LM_IN_PROGRESS.
+                          *
+                          * Parsing a value into the list link will store the
+                          * next element of the signed interval.
+                          */
+
+    LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
+
+    LM_END
+};
+
+typedef enum ListMode ListMode;
+
 struct StringOutputVisitor
 {
     Visitor visitor;
     bool human;
+    bool head;
     char *string;
+    ListMode list_mode;
+    /* When parsing a list of repeating options as integers, values of the form
+     * "a-b", representing a closed interval, are allowed. Elements in the
+     * range are generated individually.
+     */
+    union {
+        int64_t s;
+        uint64_t u;
+    } range_start, range_end;
+
 };
 
 static void string_output_set(StringOutputVisitor *sov, char *string)
@@ -34,13 +80,60 @@ static void print_type_int(Visitor *v, int64_t *obj, const char *name,
                            Error **errp)
 {
     StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
-    char *out;
+    char *out = NULL;
 
-    if (sov->human) {
-        out = g_strdup_printf("%lld (%#llx)", (long long) *obj, (long long) *obj);
-    } else {
-        out = g_strdup_printf("%lld", (long long) *obj);
+    switch (sov->list_mode) {
+    case LM_NONE:
+        if (sov->human) {
+            out = g_strdup_printf("%lld (%#llx)", (long long) *obj,
+                                  (long long) *obj);
+        } else {
+            out = g_strdup_printf("%lld", (long long) *obj);
+        }
+        sov->list_mode = LM_END;
+        break;
+
+    case LM_STARTED:
+        sov->range_start.s = *obj;
+        sov->range_end.s = *obj;
+        sov->list_mode = LM_IN_PROGRESS;
+        break;
+
+    case LM_IN_PROGRESS:
+        assert(sov->range_end.s + 1 == *obj);
+        sov->range_end.s++;
+        break;
+
+    case LM_END:
+        assert(sov->range_end.s + 1 == *obj);
+        sov->range_end.s++;
+        if (sov->range_end.s == sov->range_start.s) {
+            if (sov->human) {
+                out = g_strdup_printf("%lld (%#llx)",
+                                      (long long)sov->range_start.s,
+                                      (long long)sov->range_start.s);

qapi/string-output-visitor.c static void print_type_int(Visitor *v, int64_t *obj, const char *name, · line 124

Quoted 10 lines
qapi/string-output-visitor.c +10 -0
+            } else {
+                out = g_strdup_printf("%lld", (long long)sov->range_start.s);
+            }
+        } else {
+            if (sov->human) {
+                out = g_strdup_printf("%lld(%#llx)-%lld(%#llx)",
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_end.s,
+                                      (long long) sov->range_end.s);

Perhaps "10-15 (0xa-0xf)"?

qapi/string-output-visitor.c static void print_type_int(Visitor *v, int64_t *obj, const char *name, · line 130

Quoted 6 lines
qapi/string-output-visitor.c +6 -0
+            } else {
+                out = g_strdup_printf("%lld-%lld",
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_end.s);
+            }
+        }

This looks wrong. You do not insert any separator, and you do not handle things like "0-3,8-11". You probably should use a GString instead of string_output_set.

Paolo

Quoted 121 lines
qapi/string-output-visitor.c +58 -0
+        break;
+
+    default:
+        abort();
     }
+
     string_output_set(sov, out);
 }
 
@@ -103,6 +196,56 @@ static void print_type_number(Visitor *v, double *obj, const char *name,
     string_output_set(sov, g_strdup_printf("%f", *obj));
 }
 
+static void
+start_list(Visitor *v, const char *name, Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+
+    /* we can't traverse a list in a list */
+    assert(sov->list_mode == LM_NONE);
+    sov->list_mode = LM_STARTED;
+    sov->head = true;
+}
+
+static GenericList *
+next_list(Visitor *v, GenericList **list, Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+    GenericList *ret = NULL;
+    if (*list) {
+        if (sov->head) {
+            ret = *list;
+        } else {
+            ret = (*list)->next;
+        }
+
+        if (sov->head) {
+            if (ret && ret->next == NULL) {
+                sov->list_mode = LM_NONE;
+            }
+            sov->head = false;
+        } else {
+            if (ret && ret->next == NULL) {
+                sov->list_mode = LM_END;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static void
+end_list(Visitor *v, Error **errp)
+{
+    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
+
+    assert(sov->list_mode == LM_STARTED ||
+           sov->list_mode == LM_END ||
+           sov->list_mode == LM_IN_PROGRESS);
+    sov->list_mode = LM_NONE;
+    sov->head = true;
+}
+
 char *string_output_get_string(StringOutputVisitor *sov)
 {
     char *string = sov->string;
@@ -134,6 +277,9 @@ StringOutputVisitor *string_output_visitor_new(bool human)
     v->visitor.type_bool = print_type_bool;
     v->visitor.type_str = print_type_str;
     v->visitor.type_number = print_type_number;
+    v->visitor.start_list = start_list;
+    v->visitor.next_list = next_list;
+    v->visitor.end_list = end_list;
 
     return v;
 }
tests/test-string-output-visitor.c +26 -0
index 22363d1..511ef14 100644
@@ -57,6 +57,30 @@ static void test_visitor_out_int(TestOutputVisitorData *data,
     g_free(str);
 }
 
+static void test_visitor_out_intList(TestOutputVisitorData *data,
+                                     const void *unused)
+{
+    int64_t value[] = {-2, -1, 0, 1, 2, 3, 4};
+    intList *list = NULL, **tmp = &list;
+    int i;
+    Error *errp = NULL;
+    char *str;
+
+    for (i = 0; i < sizeof(value) / sizeof(value[0]); i++) {
+        *tmp = g_malloc0(sizeof(**tmp));
+        (*tmp)->value = value[i];
+        tmp = &(*tmp)->next;
+    }
+
+    visit_type_intList(data->ov, &list, NULL, &errp);
+    g_assert(error_is_set(&errp) == 0);
+
+    str = string_output_get_string(data->sov);
+    g_assert(str != NULL);
+    g_assert_cmpstr(str, ==, "-2-4");
+    g_free(str);
+}
+
 static void test_visitor_out_bool(TestOutputVisitorData *data,
                                   const void *unused)
 {
@@ -182,6 +206,8 @@ int main(int argc, char **argv)
                             &out_visitor_data, test_visitor_out_enum);
     output_visitor_test_add("/string-visitor/output/enum-errors",
                             &out_visitor_data, test_visitor_out_enum_errors);
+    output_visitor_test_add("/string-visitor/output/intList",
+                            &out_visitor_data, test_visitor_out_intList);
 
     g_test_run();
 
author
#9 lore raw

Re: [Qemu-devel] [PATCH v19 07/11] qapi: make string output visitor parse int list

Quoted 116 lines · Paolo Bonzini

Il 04/03/2014 08:28, Hu Tao ha scritto:

Quoted 115 lines

From: Hu Tao <[email protected]>

---
qapi/string-output-visitor.c | 156 +++++++++++++++++++++++++++++++++++--
tests/test-string-output-visitor.c | 26 +++++++

2 files changed, 177 insertions(+), 5 deletions(-)
qapi/string-output-visitor.c +35 -0
index fb1d2e8..bc9bb36 100644
@@ -17,11 +17,57 @@
 #include "qemu/host-utils.h"
 #include <math.h>
 
+enum ListMode {
+    LM_NONE,             /* not traversing a list of repeated options */
+    LM_STARTED,          /* start_list() succeeded */
+
+    LM_IN_PROGRESS,      /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently parsed QemuOpt instance of the repeated
+                          * option.
+                          *
+                          * Parsing a value into the list link will examine the
+                          * next QemuOpt instance of the repeated option, and
+                          * possibly enter LM_SIGNED_INTERVAL or
+                          * LM_UNSIGNED_INTERVAL.
+                          */
+
+    LM_SIGNED_INTERVAL,  /* next_list() has been called.
+                          *
+                          * Generating the next list link will consume the most
+                          * recently stored element from the signed interval,
+                          * parsed from the most recent QemuOpt instance of the
+                          * repeated option. This may consume QemuOpt itself
+                          * and return to LM_IN_PROGRESS.
+                          *
+                          * Parsing a value into the list link will store the
+                          * next element of the signed interval.
+                          */
+
+    LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
+
+    LM_END
+};
+
+typedef enum ListMode ListMode;
+

struct StringOutputVisitor

{
    Visitor visitor;
    bool human;
qapi/string-output-visitor.c +11 -0
+    bool head;
    char *string;
+    ListMode list_mode;
+    /* When parsing a list of repeating options as integers, values of the form
+     * "a-b", representing a closed interval, are allowed. Elements in the
+     * range are generated individually.
+     */
+    union {
+        int64_t s;
+        uint64_t u;
+    } range_start, range_end;
+

};

static void string_output_set(StringOutputVisitor *sov, char *string)

qapi/string-output-visitor.c +35 -5
@@ -34,13 +80,60 @@ static void print_type_int(Visitor *v, int64_t *obj, const char *name,
                           Error **errp)
 {
    StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v);
-    char *out;
+    char *out = NULL;
 
-    if (sov->human) {
-        out = g_strdup_printf("%lld (%#llx)", (long long) *obj, (long long) *obj);
-    } else {
-        out = g_strdup_printf("%lld", (long long) *obj);
+    switch (sov->list_mode) {
+    case LM_NONE:
+        if (sov->human) {
+            out = g_strdup_printf("%lld (%#llx)", (long long) *obj,
+                                  (long long) *obj);
+        } else {
+            out = g_strdup_printf("%lld", (long long) *obj);
+        }
+        sov->list_mode = LM_END;
+        break;
+
+    case LM_STARTED:
+        sov->range_start.s = *obj;
+        sov->range_end.s = *obj;
+        sov->list_mode = LM_IN_PROGRESS;
+        break;
+
+    case LM_IN_PROGRESS:
+        assert(sov->range_end.s + 1 == *obj);
+        sov->range_end.s++;
+        break;
+
+    case LM_END:
+        assert(sov->range_end.s + 1 == *obj);
+        sov->range_end.s++;
+        if (sov->range_end.s == sov->range_start.s) {
+            if (sov->human) {
+                out = g_strdup_printf("%lld (%#llx)",
+                                      (long long)sov->range_start.s,
+                                      (long long)sov->range_start.s);
+            } else {
+                out = g_strdup_printf("%lld", (long long)sov->range_start.s);
+            }
+        } else {
Quoted 8 lines

qapi/string-output-visitor.c static void print_type_int(Visitor *v, int64_t *obj, const char *name, · line 124

Quoted 6 lines
qapi/string-output-visitor.c +6 -0
+            if (sov->human) {
+                out = g_strdup_printf("%lld(%#llx)-%lld(%#llx)",
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_end.s,
+                                      (long long) sov->range_end.s);

Perhaps "10-15 (0xa-0xf)"?

Looks better.

Quoted 11 lines

qapi/string-output-visitor.c static void print_type_int(Visitor *v, int64_t *obj, const char *name, · line 130

Quoted 7 lines
qapi/string-output-visitor.c +6 -0
+            } else {
+                out = g_strdup_printf("%lld-%lld",
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_end.s);
+            }
+        }

This looks wrong. You do not insert any separator, and you do not handle things like "0-3,8-11". You probably should use a GString instead of string_output_set.

Right. We should also handle "0-3,8-11"-like lists in string input visitor and opts visitor.

#10 lore raw

Re: [Qemu-devel] [PATCH v19 07/11] qapi: make string output visitor parse int list

Il 04/03/2014 10:23, Hu Tao ha scritto:

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 7 lines
qapi/string-output-visitor.c +6 -0
+            } else {
+                out = g_strdup_printf("%lld-%lld",
+                                      (long long) sov->range_start.s,
+                                      (long long) sov->range_end.s);
+            }
+        }
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines

This looks wrong. You do not insert any separator, and you do not handle things like "0-3,8-11". You probably should use a GString instead of string_output_set.

Right. We should also handle "0-3,8-11"-like lists in string input visitor and opts visitor.

Ok, no big deal; let's do one thing at a time.

Regarding string input visitor, I believe we can avoid the code duplication by:

(1) using Qmp input/output visitors in query-memdev

(2) using OptsVisitor in -object

The string output visitor becomes more important than the string input visitor, but it is only needed for HMP so it is not urgent.

We can then work on making OptsVisitor use the string input visitor internally.

But I'm already applying patches 1-5, 8, 9, 10 (the latter with the above changes) to the numa tree.

Paolo

author
#11 lore raw

PATCH v19 8/11 Add Linux libnuma detection

In reply to Hu Tao

From: Wanlong Gao <[email protected]>

Add detection of libnuma (mostly contained in the numactl package) to the configure script. Can be enabled or disabled on the command line, default is use if available.

---
 configure | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
configure +33 -0
index 8ad03ea..585b40c 100755
@@ -303,6 +303,7 @@ tpm="no"
 libssh2=""
 vhdx=""
 quorum="no"
+numa=""
 
 # parse CC options first
 for opt do
@@ -1051,6 +1052,10 @@ for opt do
   ;;
   --enable-quorum) quorum="yes"
   ;;
+  --disable-numa) numa="no"
+  ;;
+  --enable-numa) numa="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -1310,6 +1315,8 @@ Advanced options (experts only):
   --enable-vhdx            enable support for the Microsoft VHDX image format
   --disable-quorum         disable quorum block filter support
   --enable-quorum          enable quorum block filter support
+  --disable-numa           disable libnuma support
+  --enable-numa            enable libnuma support
 
 NOTE: The object files are built at the place where configure is launched
 EOF
@@ -2983,6 +2990,27 @@ if compile_prog "" "" ; then
 fi
 
 ##########################################
+# libnuma probe
+
+if test "$numa" != "no" ; then
+  numa=no
+  cat > $TMPC << EOF
+#include <numa.h>
+int main(void) { return numa_available(); }
+EOF
+
+  if compile_prog "" "-lnuma" ; then
+    numa=yes
+    libs_softmmu="-lnuma $libs_softmmu"
+  else
+    if test "$numa" = "yes" ; then
+      feature_not_found "linux NUMA (install numactl?)"
+    fi
+    numa=no
+  fi
+fi
+
+##########################################
 # signalfd probe
 signalfd="no"
 cat > $TMPC << EOF
@@ -4045,6 +4073,7 @@ echo "TPM passthrough   $tpm_passthrough"
 echo "QOM debugging     $qom_cast_debug"
 echo "vhdx              $vhdx"
 echo "Quorum            $quorum"
+echo "NUMA host support $numa"
 
 if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -4983,6 +5012,10 @@ if [ "$dtc_internal" = "yes" ]; then
   echo "config-host.h: subdir-dtc" >> $config_host_mak
 fi
 
+if test "$numa" = "yes"; then
+  echo "CONFIG_NUMA=y" >> $config_host_mak
+fi
+
 # build tree in object directory in case the source is not in the current directory
 DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
 DIRS="$DIRS fsdev"
Signature · 1 line
1.8.5.2.229.g4448466
author
#12 lore raw

PATCH v19 9/11 hostmem backend: implement memory policy

In reply to Hu Tao
---
 backends/hostmem.c       | 97 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/sysemu/hostmem.h |  4 ++
 qapi-schema.json         | 20 ++++++++++
 3 files changed, 118 insertions(+), 3 deletions(-)
backends/hostmem.c +94 -3
index 0bd3900..077e8cc 100644
@@ -10,11 +10,14 @@
  * See the COPYING file in the top-level directory.
  */
 #include "sysemu/hostmem.h"
-#include "sysemu/sysemu.h"
 #include "qapi/visitor.h"
+#include "qapi-visit.h"
 #include "qapi/qmp/qerror.h"
 #include "qemu/config-file.h"
 #include "qom/object_interfaces.h"
+#ifdef CONFIG_NUMA
+#include <numaif.h>
+#endif
 
 static void
 hostmemory_backend_get_size(Object *obj, Visitor *v, void *opaque,
@@ -50,11 +53,85 @@ hostmemory_backend_set_size(Object *obj, Visitor *v, void *opaque,
     backend->size = value;
 }
 
+static void
+get_host_nodes(Object *obj, Visitor *v, void *opaque, const char *name,
+               Error **errp)
+{
+    HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+    uint16List *host_nodes = NULL;
+    uint16List **node = &host_nodes;
+    unsigned long value;
+
+    value = find_first_bit(backend->host_nodes, MAX_NODES);
+    if (value == MAX_NODES) {
+        return;
+    }
+
+    *node = g_malloc0(sizeof(**node));
+    (*node)->value = value;
+    node = &(*node)->next;
+
+    do {
+        value = find_next_bit(backend->host_nodes, MAX_NODES, value + 1);
+        if (value == MAX_NODES) {
+            break;
+        }
+
+        *node = g_malloc0(sizeof(**node));
+        (*node)->value = value;
+        node = &(*node)->next;
+    } while (true);
+
+    visit_type_uint16List(v, &host_nodes, name, errp);
+}
+
+static void
+set_host_nodes(Object *obj, Visitor *v, void *opaque, const char *name,
+               Error **errp)
+{
+    HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+    uint16List *l = NULL;
+
+    visit_type_uint16List(v, &l, name, errp);
+
+    while (l) {
+        bitmap_set(backend->host_nodes, l->value, 1);
+        l = l->next;
+    }
+}
+
+static void
+get_policy(Object *obj, Visitor *v, void *opaque, const char *name,
+           Error **errp)
+{
+    HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+    int policy = backend->policy;
+
+    visit_type_enum(v, &policy, HostMemPolicy_lookup, NULL, name, errp);
+}
+
+static void
+set_policy(Object *obj, Visitor *v, void *opaque, const char *name,
+           Error **errp)
+{
+    HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+    int policy;
+
+    visit_type_enum(v, &policy, HostMemPolicy_lookup, NULL, name, errp);
+    backend->policy = policy;
+}
+
 static void hostmemory_backend_initfn(Object *obj)
 {
     object_property_add(obj, "size", "int",
                         hostmemory_backend_get_size,
                         hostmemory_backend_set_size, NULL, NULL, NULL);
+    object_property_add(obj, "host-nodes", "int",
+                        get_host_nodes,
+                        set_host_nodes, NULL, NULL, NULL);
+    object_property_add(obj, "policy", "str",
+                        get_policy,
+                        set_policy, NULL, NULL, NULL);
 }
 
 static void hostmemory_backend_finalize(Object *obj)
@@ -69,8 +146,22 @@ static void hostmemory_backend_finalize(Object *obj)
 static void
 hostmemory_backend_memory_init(UserCreatable *uc, Error **errp)
 {
-    error_setg(errp, "memory_init is not implemented for type [%s]",
-               object_get_typename(OBJECT(uc)));
+#ifdef CONFIG_NUMA
+    HostMemoryBackend *backend = MEMORY_BACKEND(uc);
+    void *p = memory_region_get_ram_ptr(&backend->mr);
+    unsigned long maxnode = find_last_bit(backend->host_nodes, MAX_NODES);
+
+    /* This is a workaround for a long standing bug in Linux'
+     * mbind implementation, which cuts off the last specified
+     * node.
+     */
+    if (mbind(p, backend->size, backend->policy, backend->host_nodes,
+              maxnode + 2, 0)) {
+        error_setg_errno(errp, errno,
+                         "cannot bind memory to host NUMA nodes\n");
+        return;
+    }
+#endif
 }
 
 MemoryRegion *
include/sysemu/hostmem.h +4 -0
index bc3ffb3..a2b0702 100644
@@ -12,10 +12,12 @@
 #ifndef QEMU_RAM_H
 #define QEMU_RAM_H
 
+#include "sysemu/sysemu.h" /* for MAX_NODES */
 #include "qom/object.h"
 #include "qapi/error.h"
 #include "exec/memory.h"
 #include "qemu/option.h"
+#include "qemu/bitmap.h"
 
 #define TYPE_MEMORY_BACKEND "memory"
 #define MEMORY_BACKEND(obj) \
@@ -50,6 +52,8 @@ struct HostMemoryBackend {
 
     /* protected */
     uint64_t size;
+    DECLARE_BITMAP(host_nodes, MAX_NODES);
+    HostMemPolicy policy;
 
     MemoryRegion mr;
 };
qapi-schema.json +20 -0
index 62e0b83..86b78a5 100644
@@ -4554,3 +4554,23 @@
    '*cpus':   ['uint16'],
    '*mem':    'size',
    '*memdev': 'str' }}
+
+##
+# @HostMemPolicy
+#
+# Host memory policy types
+#
+# @default: restore default policy, remove any nondefault policy
+#
+# @preferred: set the preferred host nodes for allocation
+#
+# @membind: a strict policy that restricts memory allocation to the
+#           host nodes specified
+#
+# @interleave: memory allocations are interleaved across the set
+#              of host nodes specified
+#
+# Since 2.1
+##
+{ 'enum': 'HostMemPolicy',
+  'data': [ 'default', 'preferred', 'membind', 'interleave' ] }
Signature · 1 line
1.8.5.2.229.g4448466
author
#13 lore raw

PATCH v19 10/11 qmp: add query-memdev

In reply to Hu Tao

Add qmp command query-memdev to query for information of memory devices

---
 backends/hostmem.c |  1 +
 numa.c             | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qapi-schema.json   | 31 +++++++++++++++++++++++++++
 qmp-commands.hx    | 32 ++++++++++++++++++++++++++++
 4 files changed, 125 insertions(+)
backends/hostmem.c +1 -0
index 077e8cc..0d4f863 100644
@@ -18,6 +18,7 @@
 #ifdef CONFIG_NUMA
 #include <numaif.h>
 #endif
+#include "qmp-commands.h"
 
 static void
 hostmemory_backend_get_size(Object *obj, Visitor *v, void *opaque,
numa.c +61 -0

71 lines not on this page · raw message

qapi-schema.json +31 -0
index 86b78a5..b5dccfa 100644
@@ -4574,3 +4574,34 @@
 ##
 { 'enum': 'HostMemPolicy',
   'data': [ 'default', 'preferred', 'membind', 'interleave' ] }
+
+##
+# @Memdev:
+#
+# Information of memory device
+#
+# @size: memory device size
+#
+# @host-nodes: host nodes for its memory policy
+#
+# @policy: memory policy of memory device
+#
+# Since: 2.1
+##
+
+{ 'type': 'Memdev',
+  'data': {
+    'size':       'size',
+    'host-nodes': ['uint16'],
+    'policy':     'str' }}
+
+##
+# @query-memdev:
+#
+# Returns information for all memory devices.
+#
+# Returns: a list of @Memdev.
+#
+# Since: 2.1
+##
+{ 'command': 'query-memdev', 'returns': ['Memdev'] }
qmp-commands.hx +32 -0
index 8a0e832..903a48a 100644
@@ -3498,3 +3498,35 @@ Example:
                    } } ] }
 
 EQMP
+
+    {
+        .name       = "query-memdev",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_memdev,
+    },
+
+SQMP
+query-memdev
+------------
+
+Show memory devices information.
+
+
+Example (1):
+
+-> { "execute": "query-memdev" }
+<- { "return": [
+       {
+         "size": 536870912,
+         "host-nodes": [0, 1],
+         "policy": "bind"
+       },
+       {
+         "size": 536870912,
+         "host-nodes": [2, 3],
+         "policy": "preferred"
+       }
+     ]
+   }
+
+EQMP
Signature · 1 line
1.8.5.2.229.g4448466
author
#14 lore raw

PATCH v19 11/11 hmp: add info memdev

In reply to Hu Tao

This is the hmp counterpart of qmp query-memdev.

---
 hmp.c     | 27 +++++++++++++++++++++++++++
 hmp.h     |  1 +
 monitor.c |  7 +++++++
 3 files changed, 35 insertions(+)
hmp.c +27 -0
index e3ddd46..3bbe5ff 100644
@@ -22,6 +22,8 @@
 #include "qemu/sockets.h"
 #include "monitor/monitor.h"
 #include "qapi/opts-visitor.h"
+#include "qapi/string-output-visitor.h"
+#include "qapi-visit.h"
 #include "ui/console.h"
 #include "block/qapi.h"
 #include "qemu-io.h"
@@ -1644,3 +1646,28 @@ void hmp_object_del(Monitor *mon, const QDict *qdict)
     qmp_object_del(id, &err);
     hmp_handle_error(mon, &err);
 }
+
+void hmp_info_memdev(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+    MemdevList *memdev_list = qmp_query_memdev(&err);
+    MemdevList *m = memdev_list;
+    StringOutputVisitor *ov = string_output_visitor_new(false);
+    int i = 0;
+
+
+    while (m) {
+        visit_type_uint16List(string_output_get_visitor(ov),
+                              &m->value->host_nodes, NULL, NULL);
+        monitor_printf(mon, "memory device %d\n", i);
+        monitor_printf(mon, "  size: %ld\n", m->value->size);
+        monitor_printf(mon, "  policy: %s\n", m->value->policy);
+        monitor_printf(mon, "  host nodes: %s\n", string_output_get_string(ov));
+
+        m = m->next;
+        i++;
+    }
+
+    monitor_printf(mon, "\n");
+    string_output_visitor_cleanup(ov);
+}
hmp.h +1 -0
index ed58f0e..b6f5d02 100644
@@ -92,5 +92,6 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict);
 void hmp_cpu_add(Monitor *mon, const QDict *qdict);
 void hmp_object_add(Monitor *mon, const QDict *qdict);
 void hmp_object_del(Monitor *mon, const QDict *qdict);
+void hmp_info_memdev(Monitor *mon, const QDict *qdict);
 
 #endif
monitor.c +7 -0
index d7f1ade..fec4836 100644
@@ -2949,6 +2949,13 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.cmd = hmp_info_tpm,
     },
     {
+        .name       = "memdev",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show the memory device",
+        .mhandler.cmd = hmp_info_memdev,
+    },
+    {
         .name       = NULL,
     },
 };
Signature · 1 line
1.8.5.2.229.g4448466