[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v12 2/3] tools/tests: introduce unit tests for domain ID allocator


  • To: <dmkhn@xxxxxxxxx>, <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Alejandro Vallejo <alejandro.garciavallejo@xxxxxxx>
  • Date: Wed, 30 Jul 2025 16:27:58 +0200
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=proton.me smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=5/haCqET5t2Vzfy+fMw+44LSkR6n7C28ZyTot2+Zaug=; b=hN1cvAdT5QwgXwtqn6srEbaY4/53js/G6eFRkpKiKlhMa6Kqc9ChTVrUjtaAFcMDiatA85murSVqWbgfriZ5ugxmO8esrxgmeAm9jqMnJOA6xH3ppqL2ckXs9RUYkP7y58o74ZfPYf2kBr/tYoNwHf98eYbifYKO0GUbGdzynYcDN8t8uEH+zuVSZEAJbiyAwurOIf5LnQSP2Bz8knYNJF0R0uqk3HgW0vxLT/auEoQBTbtFBGlQxSc0CjU0aHHRw5SjZAH5EACjAQJi8Tdz6bUePa2OIpHogHNlIyhkaIQoQE/mDgzRy2FhVomuoEjGnBGz2zsUYMIwvvZCbE477w==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=hI6H0ZdYRa2Xo0iHojcSrgeW2DCC5tjYg/pQv6hhd8bJgPTvEz7Q0qBk0WcxK2oiV+HnYZMtR2yveF4OWw82mgutWiGugX2HbrwD1G2LBc/zC2XeFOcYy/rQ7FbQ76wXgE55dOyb0AMuHDoqrcMaR1tLIB//9aUyqGMvHoMr4PuoT5SeVxPLJ2wD5TJmZbhRDKa1/pdCim5TyD7o1NgXEqXxgBVNE3Pu0jf3ITxvFiKGrJd9sjVyRmt6rlo1FEPCF9lRbzpEdH+zd4emHb9RF2lUWJ9UcNjnbGW9skRA5xriHUmK1phSdvPnKcvqwLVe76vcK+qUj8eikVL4uRH0gQ==
  • Cc: <andrew.cooper3@xxxxxxxxxx>, <anthony.perard@xxxxxxxxxx>, <jbeulich@xxxxxxxx>, <julien@xxxxxxx>, <michal.orzel@xxxxxxx>, <roger.pau@xxxxxxxxxx>, <sstabellini@xxxxxxxxxx>, <dmukhin@xxxxxxxx>
  • Delivery-date: Wed, 30 Jul 2025 14:28:21 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On Wed Jul 30, 2025 at 5:34 AM CEST, dmkhn wrote:
> From: Denis Mukhin <dmukhin@xxxxxxxx> 
>
> Introduce some basic infrastructure for doing domain ID allocation unit tests,
> and add a few tests that ensure correctness of the domain ID allocator.
>
> Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
> ---
> Changes since v11:
> - simplified test, dropped dom0less variant
> ---
>  tools/tests/Makefile                   |   2 +-
>  tools/tests/domid/.gitignore           |   2 +
>  tools/tests/domid/Makefile             |  51 ++++++++++
>  tools/tests/domid/include/xen/domain.h | 135 +++++++++++++++++++++++++
>  tools/tests/domid/test-domid.c         |  78 ++++++++++++++
>  5 files changed, 267 insertions(+), 1 deletion(-)
>  create mode 100644 tools/tests/domid/.gitignore
>  create mode 100644 tools/tests/domid/Makefile
>  create mode 100644 tools/tests/domid/include/xen/domain.h
>  create mode 100644 tools/tests/domid/test-domid.c
>
> diff --git a/tools/tests/Makefile b/tools/tests/Makefile
> index 36928676a666..ff1666425436 100644
> --- a/tools/tests/Makefile
> +++ b/tools/tests/Makefile
> @@ -1,7 +1,7 @@
>  XEN_ROOT = $(CURDIR)/../..
>  include $(XEN_ROOT)/tools/Rules.mk
>  
> -SUBDIRS-y :=
> +SUBDIRS-y := domid
>  SUBDIRS-y += resource
>  SUBDIRS-$(CONFIG_X86) += cpu-policy
>  SUBDIRS-$(CONFIG_X86) += tsx
> diff --git a/tools/tests/domid/.gitignore b/tools/tests/domid/.gitignore
> new file mode 100644
> index 000000000000..91ac43232518
> --- /dev/null
> +++ b/tools/tests/domid/.gitignore
> @@ -0,0 +1,2 @@
> +*.o
> +test-domid-*
> diff --git a/tools/tests/domid/Makefile b/tools/tests/domid/Makefile
> new file mode 100644
> index 000000000000..9a817bb70c36
> --- /dev/null
> +++ b/tools/tests/domid/Makefile
> @@ -0,0 +1,51 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Unit tests for domain ID allocator.
> +#
> +# Copyright 2025 Ford Motor Company
> +
> +XEN_ROOT=$(CURDIR)/../../..
> +include $(XEN_ROOT)/tools/Rules.mk
> +
> +TESTS := test-domid
> +
> +vpath domid.c $(XEN_ROOT)/xen/common/
> +
> +.PHONY: all
> +all: $(TESTS)
> +
> +.PHONY: run
> +run: $(TESTS)
> +     $(foreach t,$(TESTS),./$(t);)
> +
> +.PHONY: clean
> +clean:
> +     $(RM) -- *.o $(TESTS) $(DEPS_RM)
> +
> +.PHONY: distclean
> +distclean: clean
> +     $(RM) -- *~
> +
> +.PHONY: install
> +install: all
> +     $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC)/tests
> +     $(INSTALL_PROG) test-domid $(DESTDIR)$(LIBEXEC)/tests
> +
> +.PHONY: uninstall
> +uninstall:
> +     $(RM) -- $(DESTDIR)$(LIBEXEC)/tests/test-domid
> +
> +CFLAGS += -D__XEN_TOOLS__
> +CFLAGS += $(APPEND_CFLAGS)
> +CFLAGS += $(CFLAGS_xeninclude)
> +CFLAGS += -I./include/
> +
> +LDFLAGS += $(APPEND_LDFLAGS)
> +
> +%.o: %.c
> +     $(CC) $(CFLAGS) -c $^ -o $@ $(LDFLAGS)
> +
> +test-domid: domid.o test-domid.o
> +     $(CC) $^ -o $@ $(LDFLAGS)
> +
> +-include $(DEPS_INCLUDE)

I think the Makefile is off. If I try to recompile after modifying the header it
doesn't compile anymore.

> diff --git a/tools/tests/domid/include/xen/domain.h 
> b/tools/tests/domid/include/xen/domain.h
> new file mode 100644
> index 000000000000..396c3bab9d26
> --- /dev/null
> +++ b/tools/tests/domid/include/xen/domain.h

I wish this could be the real one. Alas, I've been in that boat and I'm aware
you can't. Just came here to whine online.

> @@ -0,0 +1,135 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Unit test harness for domain ID allocator.
> + *
> + * Copyright 2025 Ford Motor Company
> + */
> +
> +#ifndef _TEST_HARNESS_
> +#define _TEST_HARNESS_
> +
> +#include <assert.h>
> +#include <errno.h> <======= not needed
> +#include <stdbool.h>
> +#include <stddef.h> <======= not needed
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h> <======= not needed
> +#include <string.h> <======= not needed

Bunch un headers are not required.

> +
> +#include <xen-tools/common-macros.h>
> +
> +#define BUG_ON(x)               assert(!(x))
> +#define ASSERT(x)               assert(x)
> +
> +#define __xen_mk_uint(x)        x ## U
> +#define xen_mk_uint(x)          __xen_mk_uint(x)

Do you need these, if...

> +
> +#define DOMID_FIRST_RESERVED    xen_mk_uint(10)
> +#define DOMID_INVALID           xen_mk_uint(11)

... these were just 10 and 11 without being wrapped?

> +
> +#define DEFINE_SPINLOCK(x)      unsigned long *(x)
> +#define spin_lock(x)            ((*(x))++)
> +#define spin_unlock(x)          ((*(x))--)
> +
> +#define BITS_PER_LONG           sizeof(unsigned long)
> +#define BITS_PER_WORD           (8U * BITS_PER_LONG)
> +#define BITS_TO_LONGS(bits) \
> +    (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
> +#define DECLARE_BITMAP(name, bits) \
> +    unsigned long name[BITS_TO_LONGS(bits)]
> +
> +static inline int __test_and_set_bit(unsigned int nr, unsigned long *addr)
> +{
> +    unsigned long mask = 1UL << (nr % BITS_PER_WORD);
> +    unsigned long *p = addr + (nr / BITS_PER_WORD);
> +    int old = (*p & mask) != 0;
> +
> +    *p |= mask;
> +
> +    return old;
> +}
> +
> +static inline int __test_and_clear_bit(unsigned int nr, unsigned long *addr)
> +{
> +    unsigned long mask = 1UL << (nr % BITS_PER_WORD);
> +    unsigned long *p = addr + (nr / BITS_PER_WORD);
> +    int old = (*p & mask) != 0;
> +
> +    *p &= ~mask;
> +
> +    return old;
> +}
> +
> +static inline void __set_bit(unsigned int nr, volatile unsigned long *addr)
> +{
> +    unsigned long mask = 1UL << (nr % BITS_PER_WORD);
> +    unsigned long *p = (unsigned long *)addr + (nr / BITS_PER_WORD);
> +
> +    *p |= mask;
> +}
> +
> +static inline void __clear_bit(unsigned int nr, volatile unsigned long *addr)
> +{
> +    unsigned long mask = 1UL << (nr % BITS_PER_WORD);
> +    unsigned long *p = (unsigned long *)addr + (nr / BITS_PER_WORD);
> +
> +    *p &= ~mask;
> +}
> +
> +static inline unsigned long find_next_zero_bit(const unsigned long *addr,
> +                                               unsigned long size,
> +                                               unsigned long offset)
> +{
> +    unsigned long idx = offset / BITS_PER_WORD;
> +    unsigned long bit = offset % BITS_PER_WORD;
> +
> +    if (offset >= size)
> +        return size;
> +
> +    while (offset < size)
> +    {
> +        unsigned long val = addr[idx] | (~0UL >> (BITS_PER_WORD - bit));
> +
> +        if (~val)
> +        {
> +            unsigned long pos = __builtin_ffsl(~val);
> +
> +            if (pos > 0)
> +            {
> +                unsigned long rc = idx * BITS_PER_WORD + (pos - 1);
> +
> +                if (rc < size)
> +                    return rc;
> +            }
> +        }
> +
> +        offset = (idx + 1) * BITS_PER_WORD;
> +        idx++;
> +        bit = 0;
> +    }
> +
> +    return size;
> +}
> +
> +#define printk printf
> +
> +#define cf_check

No longer needed

> +
> +typedef bool spinlock_t;
> +typedef uint16_t domid_t;
> +
> +/* See include/xen/domain.h */
> +extern domid_t domid_alloc(domid_t domid);
> +extern void domid_free(domid_t domid);
> +
> +#endif /* _TEST_HARNESS_ */
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/tools/tests/domid/test-domid.c b/tools/tests/domid/test-domid.c
> new file mode 100644
> index 000000000000..ed041bb56d89
> --- /dev/null
> +++ b/tools/tests/domid/test-domid.c
> @@ -0,0 +1,78 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Unit tests for domain ID allocator.
> + *
> + * Copyright 2025 Ford Motor Company
> + */
> +
> +/* Local test include replicating hypervisor includes. */
> +#include <xen/domain.h>
> +
> +int main(int argc, char **argv)
> +{
> +    domid_t expected, allocated;
> +
> +    printk("%s DOMID_FIRST_RESERVED=%u DOMID_INVALID=%u\n",
> +            argv[0], DOMID_FIRST_RESERVED, DOMID_INVALID);

nit; IMO, argv[0] is inconsequential.

also, printf seeing how this is a unit test. I know it's #define'd, but it's
just easier to eyeball you're in userspace when you don't have printks around.

> +    /* Test ID#0 cannot be allocated twice. */
> +    allocated = domid_alloc(0);
> +    printk("TEST 1: expected %u allocated %u\n", 0, allocated);
> +    ASSERT(allocated == 0);
> +    allocated = domid_alloc(0);
> +    printk("TEST 1: expected %u allocated %u\n", DOMID_INVALID, allocated);
> +    ASSERT(allocated == DOMID_INVALID);
> +
> +    /* Ensure ID is not allocated. */
> +    domid_free(0);
> +
> +    /*
> +     * Test that that two consecutive calls of domid_alloc(DOMID_INVALID)
> +     * will never return the same ID.
> +     * NB: ID#0 is reserved and shall not be allocated by
> +     * domid_alloc(DOMID_INVALID).
> +     */
> +    for ( expected = 0; expected < DOMID_FIRST_RESERVED - 1; expected++ )

If this starts on 1...

> +    {
> +        allocated = domid_alloc(DOMID_INVALID);
> +        printk("TEST 2: expected %u allocated %u\n", expected + 1, 
> allocated);
> +        ASSERT(allocated == expected + 1);

... these two doen't have to have it. Which is a bit easier to read and 
unserstand.

"expect" should match the expectation, IMO.

> +    }
> +    for ( expected = 0; expected < DOMID_FIRST_RESERVED; expected++ )
> +    {
> +        allocated = domid_alloc(DOMID_INVALID);
> +        printk("TEST 2: expected %u allocated %u\n", DOMID_INVALID, 
> allocated);
> +        ASSERT(allocated == DOMID_INVALID);
> +    }
> +
> +    /* Re-allocate first ID from [1..DOMID_FIRST_RESERVED - 1]. */
> +    expected = 1;
> +    domid_free(1);
> +    allocated = domid_alloc(DOMID_INVALID);
> +    printk("TEST 3: expected %u allocated %u\n", expected, allocated);
> +    ASSERT(allocated == expected);
> +
> +    /* Re-allocate last ID from [1..DOMID_FIRST_RESERVED - 1]. */
> +    expected = DOMID_FIRST_RESERVED - 1;
> +    domid_free(DOMID_FIRST_RESERVED - 1);
> +    allocated = domid_alloc(DOMID_INVALID);
> +    printk("TEST 4: expected %u allocated %u\n", expected, allocated);
> +    ASSERT(allocated == expected);
> +
> +    /* Allocate an invalid ID. */
> +    expected = DOMID_INVALID;
> +    allocated = domid_alloc(DOMID_FIRST_RESERVED);
> +    printk("TEST 5: expected %u allocated %u\n", expected, allocated);
> +    ASSERT(allocated == expected);
> +
> +    return 0;
> +}

As far as the test cases go, they seem pretty extensive. I like it.

Cheers,
Alejandro



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.