From nobody Mon May 20 21:40:27 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1614590765; cv=none; d=zohomail.com; s=zohoarc; b=jon3yoRu0doPxxw6jCHOR4/PYUDhjGt7CZ/XHKPKQxvyzfXez67so2exIy5Zazo4b4b3RpLaQxJFxdOd1xl0qoAJcrQ1ytxEZsiXGNmUFhpkEbZtTJHg4fSjEQ0MlQNUIwyt1Tla6pfmGuNCn/HSDzIZZcJoq9IgYKtjeayT/qA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1614590765; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To; bh=eggz2Umc0qNeTJbGU7LqW0yV7ij/d5/HEbjXqa7nG4M=; b=cGfYMH+Bzq56NL39dJEMXsey7+gGLupzMTFTVYOGToy0uKXuYUCr82YeZLqmrlj6ENpxZYeBcaful1uwy6m1Lp5SSsak33WbUXROgsf9TIccp3+Cb9rsYc1nce+kIfBDNKAMgb/iORYCWeoctt8P80crfiCSI4WsdMAuavTgwPU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1614590765189454.5133568463716; Mon, 1 Mar 2021 01:26:05 -0800 (PST) Received: from localhost ([::1]:49056 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lGeoW-0004z3-1w for importer@patchew.org; Mon, 01 Mar 2021 04:26:04 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:56502) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lGenE-000494-Gq for qemu-devel@nongnu.org; Mon, 01 Mar 2021 04:24:44 -0500 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:51262) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1lGenB-0000xb-Kn for qemu-devel@nongnu.org; Mon, 01 Mar 2021 04:24:44 -0500 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-172-bc4j4eY9N2-G_8Tn7pEWlA-1; Mon, 01 Mar 2021 04:24:37 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 5A4D5874980 for ; Mon, 1 Mar 2021 09:24:36 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-113-17.ams2.redhat.com [10.36.113.17]) by smtp.corp.redhat.com (Postfix) with ESMTP id CAD5F60636; Mon, 1 Mar 2021 09:24:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1614590680; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=eggz2Umc0qNeTJbGU7LqW0yV7ij/d5/HEbjXqa7nG4M=; b=FFHT7bC7TLavuNtccs+KnRykS2dKMkcoB+ORVZE+zm39GFRMTo7d/2OZoq6aRxjxSbrIYr oo4iq8OXDGdpeXsjavUOnQ7Ra7jKndtu+w2fcLe9zZ7o3kh6O7u1pmCgZQ9m54E8VTfBBT ByKNy+lhQwoid9QESnGlPkEQ7k+KkhU= X-MC-Unique: bc4j4eY9N2-G_8Tn7pEWlA-1 From: Emanuele Giuseppe Esposito To: qemu-devel@nongnu.org Subject: [PATCH] docs/devel/qgraph: improve qgraph documentation Date: Mon, 1 Mar 2021 10:24:32 +0100 Message-Id: <20210301092432.20342-1-eesposit@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=eesposit@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=63.128.21.124; envelope-from=eesposit@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -30 X-Spam_score: -3.1 X-Spam_bar: --- X-Spam_report: (-3.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.248, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, WEIRD_QUOTING=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Paolo Bonzini , Thomas Huth Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Improve current qgraph documentation with a more concrete example and clearer motivation. This patch depends on the previous serie "libqos/qgraph: format qgraph comments for sphinx documentation" Signed-off-by: Emanuele Giuseppe Esposito --- docs/devel/qgraph.rst | 509 +++++++++++++++++++++++++++++++++--------- 1 file changed, 408 insertions(+), 101 deletions(-) diff --git a/docs/devel/qgraph.rst b/docs/devel/qgraph.rst index 62a45cbcbf..a9aff167ad 100644 --- a/docs/devel/qgraph.rst +++ b/docs/devel/qgraph.rst @@ -4,14 +4,37 @@ Qtest Driver Framework =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 -This Qgraph API provides all basic functions to create a graph -and instantiate nodes representing machines, drivers and tests -representing their relations with ``CONSUMES``, ``PRODUCES``, and -``CONTAINS`` edges. +In order to test a specific driver, plain libqos tests need to +take care of booting QEMU with the right machine and devices. +This makes each test "hardcoded" for a specific configuration, reducing +the possible coverage that it can reach. + +For example, the sdhci device is supported on both x86_64 and ARM boards, +therefore a generic sdhci test should test all machines and drivers that +support that device. +Using only libqos APIs, the test has to manually take care of +covering all the setups, and build the correct command line. + +This also introduces backward compability issues: if a device/driver comma= nd +line name is changed, all tests that use that will not work +properly anymore and need to be adjusted. + +The aim of qgraph is to create a graph of drivers, machines and tests such= that +a test aimed to a certain driver does not have to care of +booting the right QEMU machine, pick the right device, build the command l= ine +and so on. Instead, it only defines what type of device it is testing +(interface in qgraph terms) and the framework takes care of +covering all supported types of devices and machine architectures. + +Following the above example, an interface would be ``sdhci``, +so the sdhci-test should only care of linking its qgraph node with +that interface. In this way, if the command line of a sdhci driver +is changed, only the respective qgraph driver node has to be adjusted. + +The graph is composed by nodes that represent machines, drivers, tests +and edges that define the relationships between them (``CONSUMES``, ``PROD= UCES``, and +``CONTAINS``). =20 -The idea is to have a framework where each test asks for a specific -driver, and the framework takes care of allocating the proper devices -required and passing the correct command line arguments to QEMU. =20 Nodes ^^^^^^ @@ -24,8 +47,11 @@ A node can be of four types: drivers). An interface is not explicitly created, it will be automatically instantiated when a node consumes or produces it. -- **QNODE_TEST**: for example ``sdhci-test``, consumes an interface a= nd - tests the functions provided. + An interface is simply a struct that abstracts the various drivers + for the same type of device, and offers an API to the nodes that + use it ("consume" relation in qgraph terms) that is implemented/backed u= p by the drivers that implement it ("produce" relation in qgraph terms). +- **QNODE_TEST**: for example ``sdhci-test``. A test consumes an inte= rface + and tests the functions provided by it. =20 Notes for the nodes: =20 @@ -69,136 +95,415 @@ available and only test that are reached by them will= be executed. Creating a new driver and its interface """"""""""""""""""""""""""""""""""""""""" =20 -.. code:: +Here we continue the ``sdhci`` use case, with the following scenario: + +- ``sdhci-test`` aims to test the ``read[q,w], writeq`` functions + offered by the ``sdhci`` drivers. +- The current ``sdhci`` device is supported by both ``x86_64/pc`` and ``AR= M`` + (in this example we focus on the ``arm-raspi2``) machines. +- QEMU offers 2 types of drivers: ``QSDHCI_MemoryMapped`` for ``ARM`` and + ``QSDHCI_PCI`` for ``x86_64/pc``. Both implement the + ``read[q,w], writeq`` functions. + +In order to implement such scenario in qgraph, the test developer needs to: + +- Create the ``x86_64/pc`` machine node. This machine uses the + ``pci-bus`` architecture so it ``contains`` a PCI driver, + ``pci-bus-pc``. The actual path is + + ``x86_64/pc --contains--> 1440FX-pcihost --contains--> + pci-bus-pc --produces--> pci-bus``. + + For the sake of this example, + we do not focus on the PCI interface implementation. +- Create the ``sdhci-pci`` driver node, representing ``QSDHCI_PCI``. + The driver uses the PCI bus (and its API), + so it must ``consume`` the ``pci-bus`` generic interface (which abstracts + all the pci drivers available) + + ``sdhci-pci --consumes--> pci-bus`` +- Create an ``arm/raspi2`` machine node. This machine ``contains`` + a ``generic-sdhci`` memory mapped ``sdhci`` driver node, representing + ``QSDHCI_MemoryMapped``. + + ``arm/raspi2 --contains--> generic-sdhci`` +- Create the ``sdhci`` interface node. This interface offers the + functions that are shared by all ``sdhci`` devices. + The interface is produced by ``sdhci-pci`` and ``generic-sdhci``, + the available architecture-specific drivers. + + ``sdhci-pci --produces--> sdhci`` + + ``generic-sdhci --produces--> sdhci`` +- Create the ``sdhci-test`` test node. The test ``consumes`` the + ``sdhci`` interface, using its API. It doesn't need to look at + the supported machines or drivers. + + ``sdhci-test --consumes--> sdhci`` + +``arm-raspi2`` machine, simplified from +``tests/qtest/libqos/arm-raspi2-machine.c``:: =20 #include "qgraph.h" =20 - struct My_driver { + struct QRaspi2Machine { QOSGraphObject obj; - Node_produced prod; - Node_contained cont; + QGuestAllocator alloc; + QSDHCI_MemoryMapped sdhci; + }; + + static void *raspi2_get_driver(void *object, const char *interface) + { + QRaspi2Machine *machine =3D object; + if (!g_strcmp0(interface, "memory")) { + return &machine->alloc; + } + + fprintf(stderr, "%s not present in arm/raspi2\n", interface); + g_assert_not_reached(); + } + + static QOSGraphObject *raspi2_get_device(void *obj, + const char *device) + { + QRaspi2Machine *machine =3D obj; + if (!g_strcmp0(device, "generic-sdhci")) { + return &machine->sdhci.obj; + } + + fprintf(stderr, "%s not present in arm/raspi2\n", device); + g_assert_not_reached(); } =20 - static void my_destructor(QOSGraphObject *obj) + static void *qos_create_machine_arm_raspi2(QTestState *qts) { - g_free(obj); + QRaspi2Machine *machine =3D g_new0(QRaspi2Machine, 1); + + alloc_init(&machine->alloc, ...); + + /* Get node(s) contained inside (CONTAINS) */ + machine->obj.get_device =3D raspi2_get_device; + + /* Get node(s) produced (PRODUCES) */ + machine->obj.get_driver =3D raspi2_get_driver; + + /* free the object */ + machine->obj.destructor =3D raspi2_destructor; + qos_init_sdhci_mm(&machine->sdhci, ...); + return &machine->obj; } =20 - static void *my_get_driver(void *object, const char *interface) { - My_driver *dev =3D object; - if (!g_strcmp0(interface, "my_interface")) { - return &dev->prod; + static void raspi2_register_nodes(void) + { + /* arm/raspi2 --contains--> generic-sdhci */ + qos_node_create_machine("arm/raspi2", + qos_create_machine_arm_raspi2); + qos_node_contains("arm/raspi2", "generic-sdhci", NULL); + } + + libqos_init(raspi2_register_nodes); + +``x86_64/pc`` machine, simplified from +``tests/qtest/libqos/x86_64_pc-machine.c``:: + + #include "qgraph.h" + + struct i440FX_pcihost { + QOSGraphObject obj; + QPCIBusPC pci; + }; + + struct QX86PCMachine { + QOSGraphObject obj; + QGuestAllocator alloc; + i440FX_pcihost bridge; + }; + + /* i440FX_pcihost */ + + static QOSGraphObject *i440FX_host_get_device(void *obj, + const char *device) + { + i440FX_pcihost *host =3D obj; + if (!g_strcmp0(device, "pci-bus-pc")) { + return &host->pci.obj; + } + fprintf(stderr, "%s not present in i440FX-pcihost\n", device); + g_assert_not_reached(); + } + + /* x86_64/pc machine */ + + static void *pc_get_driver(void *object, const char *interface) + { + QX86PCMachine *machine =3D object; + if (!g_strcmp0(interface, "memory")) { + return &machine->alloc; } - abort(); + + fprintf(stderr, "%s not present in x86_64/pc\n", interface); + g_assert_not_reached(); } =20 - static void *my_get_device(void *object, const char *device) { - My_driver *dev =3D object; - if (!g_strcmp0(device, "my_driver_contained")) { - return &dev->cont; + static QOSGraphObject *pc_get_device(void *obj, const char *device) + { + QX86PCMachine *machine =3D obj; + if (!g_strcmp0(device, "i440FX-pcihost")) { + return &machine->bridge.obj; } - abort(); + + fprintf(stderr, "%s not present in x86_64/pc\n", device); + g_assert_not_reached(); } =20 - static void *my_driver_constructor(void *node_consumed, - QOSGraphObject *alloc) + static void *qos_create_machine_pc(QTestState *qts) { - My_driver dev =3D g_new(My_driver, 1); + QX86PCMachine *machine =3D g_new0(QX86PCMachine, 1); =20 - // get the node pointed by the produce edge - dev->obj.get_driver =3D my_get_driver; + /* Get node(s) contained inside (CONTAINS) */ + machine->obj.get_device =3D pc_get_device; =20 - // get the node pointed by the contains - dev->obj.get_device =3D my_get_device; + /* Get node(s) produced (PRODUCES) */ + machine->obj.get_driver =3D pc_get_driver; =20 - // free the object - dev->obj.destructor =3D my_destructor; + /* free the object */ + machine->obj.destructor =3D pc_destructor; + pc_alloc_init(&machine->alloc, qts, ALLOC_NO_FLAGS); =20 - do_something_with_node_consumed(node_consumed); + /* Get node(s) contained inside (CONTAINS) */ + machine->bridge.obj.get_device =3D i440FX_host_get_device; =20 - // set all fields of contained device - init_contained_device(&dev->cont); - return &dev->obj; + return &machine->obj; } =20 - static void register_my_driver(void) + static void pc_machine_register_nodes(void) { - qos_node_create_driver("my_driver", my_driver_constructor); - - // contained drivers don't need a constructor, - // they will be init by the parent. - qos_node_create_driver("my_driver_contained", NULL); - - // For the sake of this example, assume machine x86_64/pc - // contains "other_node". - // This relation, along with the machine and "other_node" - // creation, should be defined in the x86_64_pc-machine.c file. - // "my_driver" will then consume "other_node" - qos_node_contains("my_driver", "my_driver_contained"); - qos_node_produces("my_driver", "my_interface"); - qos_node_consumes("my_driver", "other_node"); + /* x86_64/pc --contains--> 1440FX-pcihost --contains--> + * pci-bus-pc [--produces--> pci-bus (in pci.h)] */ + qos_node_create_machine("x86_64/pc", qos_create_machine_pc); + qos_node_contains("x86_64/pc", "i440FX-pcihost", NULL); + + /* contained drivers don't need a constructor, + * they will be init by the parent */ + qos_node_create_driver("i440FX-pcihost", NULL); + qos_node_contains("i440FX-pcihost", "pci-bus-pc", NULL); } =20 -In the above example, all possible types of relations are created: -node "my_driver" consumes, contains and produces other nodes. -More specifically:: + libqos_init(pc_machine_register_nodes); =20 - x86_64/pc -->contains--> other_node <--consumes-- my_driver - | - my_driver_contained <--contains--+ - | - my_interface <--produces--+ +``sdhci`` taken from ``tests/qtest/libqos/sdhci.c``:: =20 -or inverting the consumes edge in consumed_by:: + /* Interface node, offers the sdhci API */ + struct QSDHCI { + uint16_t (*readw)(QSDHCI *s, uint32_t reg); + uint64_t (*readq)(QSDHCI *s, uint32_t reg); + void (*writeq)(QSDHCI *s, uint32_t reg, uint64_t val); + /* other fields */ + }; =20 - x86_64/pc -->contains--> other_node --consumed_by--> my_driver - | - my_driver_contained <--contains--+ + /* Memory Mapped implementation of QSDHCI */ + struct QSDHCI_MemoryMapped { + QOSGraphObject obj; + QSDHCI sdhci; + /* other driver-specific fields */ + }; + + /* PCI implementation of QSDHCI */ + struct QSDHCI_PCI { + QOSGraphObject obj; + QSDHCI sdhci; + /* other driver-specific fields */ + }; + + /* Memory mapped implementation of QSDHCI */ + + static void *sdhci_mm_get_driver(void *obj, const char *interface) + { + QSDHCI_MemoryMapped *smm =3D obj; + if (!g_strcmp0(interface, "sdhci")) { + return &smm->sdhci; + } + fprintf(stderr, "%s not present in generic-sdhci\n", interface); + g_assert_not_reached(); + } + + void qos_init_sdhci_mm(QSDHCI_MemoryMapped *sdhci, QTestState *qts, + uint32_t addr, QSDHCIProperties *common) + { + /* Get node contained inside (CONTAINS) */ + sdhci->obj.get_driver =3D sdhci_mm_get_driver; + + /* SDHCI interface API */ + sdhci->sdhci.readw =3D sdhci_mm_readw; + sdhci->sdhci.readq =3D sdhci_mm_readq; + sdhci->sdhci.writeq =3D sdhci_mm_writeq; + sdhci->qts =3D qts; + } + + /* PCI implementation of QSDHCI */ + + static void *sdhci_pci_get_driver(void *object, + const char *interface) + { + QSDHCI_PCI *spci =3D object; + if (!g_strcmp0(interface, "sdhci")) { + return &spci->sdhci; + } + + fprintf(stderr, "%s not present in sdhci-pci\n", interface); + g_assert_not_reached(); + } + + static void *sdhci_pci_create(void *pci_bus, + QGuestAllocator *alloc, + void *addr) + { + QSDHCI_PCI *spci =3D g_new0(QSDHCI_PCI, 1); + QPCIBus *bus =3D pci_bus; + uint64_t barsize; + + qpci_device_init(&spci->dev, bus, addr); + + /* SDHCI interface API */ + spci->sdhci.readw =3D sdhci_pci_readw; + spci->sdhci.readq =3D sdhci_pci_readq; + spci->sdhci.writeq =3D sdhci_pci_writeq; + + /* Get node(s) produced (PRODUCES) */ + spci->obj.get_driver =3D sdhci_pci_get_driver; + + spci->obj.start_hw =3D sdhci_pci_start_hw; + spci->obj.destructor =3D sdhci_destructor; + return &spci->obj; + } + + static void qsdhci_register_nodes(void) + { + QOSGraphEdgeOptions opts =3D { + .extra_device_opts =3D "addr=3D04.0", + }; + + /* generic-sdhci */ + /* generic-sdhci --produces--> sdhci */ + qos_node_create_driver("generic-sdhci", NULL); + qos_node_produces("generic-sdhci", "sdhci"); + + /* sdhci-pci */ + /* sdhci-pci --produces--> sdhci + * sdhci-pci --consumes--> pci-bus */ + qos_node_create_driver("sdhci-pci", sdhci_pci_create); + qos_node_produces("sdhci-pci", "sdhci"); + qos_node_consumes("sdhci-pci", "pci-bus", &opts); + } + + libqos_init(qsdhci_register_nodes); + +In the above example, all possible types of relations are created:: + + x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc | - my_interface <--produces--+ + sdhci-pci --consumes--> pci-bus <--produces--+ + | + +--produces--+ + | + v + sdhci + ^ + | + +--produces-- + + | + arm/raspi2 --contains--> generic-sdhci + +or inverting the consumes edge in consumed_by:: =20 -Creating new test + x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc + | + sdhci-pci <--consumed by-- pci-bus <--produces--+ + | + +--produces--+ + | + v + sdhci + ^ + | + +--produces-- + + | + arm/raspi2 --contains--> generic-sdhci + +Adding a new test """"""""""""""""" =20 -.. code:: +Given the above setup, adding a new test is very simple. +``sdhci-test``, taken from ``tests/qtest/sdhci-test.c``:: =20 - #include "qgraph.h" + static void check_capab_sdma(QSDHCI *s, bool supported) + { + uint64_t capab, capab_sdma; =20 - static void my_test_function(void *obj, void *data) + capab =3D s->readq(s, SDHC_CAPAB); + capab_sdma =3D FIELD_EX64(capab, SDHC_CAPAB, SDMA); + g_assert_cmpuint(capab_sdma, =3D=3D, supported); + } + + static void test_registers(void *obj, void *data, + QGuestAllocator *alloc) { - Node_produced *interface_to_test =3D obj; - // test interface_to_test + QSDHCI *s =3D obj; + + /* example test */ + check_capab_sdma(s, s->props.capab.sdma); } =20 - static void register_my_test(void) + static void register_sdhci_test(void) { - qos_add_test("my_interface", "my_test", my_test_function); + /* sdhci-test --consumes--> sdhci */ + qos_add_test("registers", "sdhci", test_registers, NULL); } =20 - libqos_init(register_my_test); + libqos_init(register_sdhci_test); =20 -Here a new test is created, consuming "my_interface" node -and creating a valid path from a machine to a test. +Here a new test is created, consuming ``sdhci`` interface node +and creating a valid path from both machines to a test. Final graph will be like this:: =20 - x86_64/pc --contains--> other_node <--consumes-- my_driver - | - my_driver_contained <--contains--+ - | - my_test --consumes--> my_interface <--produces--+ + x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc + | + sdhci-pci --consumes--> pci-bus <--produces--+ + | + +--produces--+ + | + v + sdhci <--consumes-- sdhci-test + ^ + | + +--produces-- + + | + arm/raspi2 --contains--> generic-sdhci =20 or inverting the consumes edge in consumed_by:: =20 - x86_64/pc --contains--> other_node --consumed_by--> my_driver - | - my_driver_contained <--contains--+ + x86_64/pc --contains--> 1440FX-pcihost --contains--> pci-bus-pc | - my_test <--consumed_by-- my_interface <--produces--+ + sdhci-pci <--consumed by-- pci-bus <--produces--+ + | + +--produces--+ + | + v + sdhci --consumed by--> sdhci-test + ^ + | + +--produces-- + + | + arm/raspi2 --contains--> generic-sdhci =20 Assuming there the binary is ``QTEST_QEMU_BINARY=3D./qemu-system-x86_64`` a valid test path will be: -``/x86_64/pc/other_node/my_driver/my_interface/my_test``. +``/x86_64/pc/1440FX-pcihost/pci-bus-pc/pci-bus/sdhci-pc/sdhci/sdhci-test`` + +and for the binary ``QTEST_QEMU_BINARY=3D./qemu-system-arm``: + +``/arm/raspi2/generic-sdhci/sdhci/sdhci-test`` =20 Additional examples are also in ``test-qgraph.c`` =20 @@ -215,19 +520,19 @@ There are three types of command line arguments: ``-device ``. It is automatically done by the framework. - ``after node`` : added as additional argument to the node name. This argument is added optionally when creating edges, - by setting the parameter @after_cmd_line and - @extra_edge_opts in #QOSGraphEdgeOptions. + by setting the parameter ``after_cmd_line`` and + ``extra_edge_opts`` in ``QOSGraphEdgeOptions``. The framework automatically adds - a comma before @extra_edge_opts, + a comma before ``extra_edge_opts``, because it is going to add attributes after the destination node pointed by the edge containing these options, and automatically - adds a space before @after_cmd_line, because it + adds a space before ``after_cmd_line``, because it adds an additional device, not an attribute. - ``before node`` : added as additional argument to the node name. This argument is added optionally when creating edges, - by setting the parameter @before_cmd_line in - #QOSGraphEdgeOptions. This attribute + by setting the parameter ``before_cmd_line`` in + ``QOSGraphEdgeOptions``. This attribute is going to add attributes before the destination node pointed by the edge containing these options. It is helpful to commands that are not node-representable, @@ -243,17 +548,19 @@ devices to be added in QEMU. Example:: =20 QOSGraphEdgeOptions opts =3D { - .arg =3D NULL, - .size_arg =3D 0, - .after_cmd_line =3D "-device other", - .before_cmd_line =3D "-netdev something", - .extra_edge_opts =3D "addr=3D04.0", + .before_cmd_line =3D "-drive id=3Ddrv0,if=3Dnone,file=3Dnull-co://= ," + "file.read-zeroes=3Don,format=3Draw", + .after_cmd_line =3D "-device scsi-hd,bus=3Dvs0.0,drive=3Ddrv0", + + opts.extra_device_opts =3D "id=3Dvs0"; }; - QOSGraphNodeS *node =3D qos_node_create_driver("my_node", constructor); - qos_node_consumes_args("my_node", "interface", &opts); + + qos_node_create_driver("virtio-scsi-device", + virtio_scsi_device_create); + qos_node_consumes("virtio-scsi-device", "virtio-bus", &opts); =20 Will produce the following command line: -``-netdev something -device my_node,addr=3D04.0 -device other`` +``-drive id=3Ddrv0,if=3Dnone,file=3Dnull-co://, -device virtio-scsi-device= ,id=3Dvs0 -device scsi-hd,bus=3Dvs0.0,drive=3Ddrv0`` =20 Qgraph API reference ^^^^^^^^^^^^^^^^^^^^ --=20 2.29.2