libqos/qgraph: format qgraph comments for sphinx documentation
[qemu/ar7.git] / docs / devel / qgraph.rst
blob62a45cbcbf1eb8998184f4d7e7abc382831da8aa
1 .. _qgraph:
3 ========================================
4 Qtest Driver Framework
5 ========================================
7 This Qgraph API provides all basic functions to create a graph
8 and instantiate nodes representing machines, drivers and tests
9 representing their relations with ``CONSUMES``, ``PRODUCES``, and
10 ``CONTAINS`` edges.
12 The idea is to have a framework where each test asks for a specific
13 driver, and the framework takes care of allocating the proper devices
14 required and passing the correct command line arguments to QEMU.
16 Nodes
17 ^^^^^^
19 A node can be of four types:
21 - **QNODE_MACHINE**:   for example ``arm/raspi2``
22 - **QNODE_DRIVER**:    for example ``generic-sdhci``
23 - **QNODE_INTERFACE**: for example ``sdhci`` (interface for all ``-sdhci``
24   drivers).
25   An interface is not explicitly created, it will be automatically
26   instantiated when a node consumes or produces it.
27 - **QNODE_TEST**:      for example ``sdhci-test``, consumes an interface and
28   tests the functions provided.
30 Notes for the nodes:
32 - QNODE_MACHINE: each machine struct must have a ``QGuestAllocator`` and
33   implement ``get_driver()`` to return the allocator mapped to the interface
34   "memory". The function can also return ``NULL`` if the allocator
35   is not set.
36 - QNODE_DRIVER:  driver names must be unique, and machines and nodes
37   planned to be "consumed" by other nodes must match QEMU
38   drivers name, otherwise they won't be discovered
40 Edges
41 ^^^^^^
43 An edge relation between two nodes (drivers or machines) `X` and `Y` can be:
45 - ``X CONSUMES Y``: `Y` can be plugged into `X`
46 - ``X PRODUCES Y``: `X` provides the interface `Y`
47 - ``X CONTAINS Y``: `Y` is part of `X` component
49 Execution steps
50 ^^^^^^^^^^^^^^^
52 The basic framework steps are the following:
54 - All nodes and edges are created in their respective
55   machine/driver/test files
56 - The framework starts QEMU and asks for a list of available devices
57   and machines (note that only machines and "consumed" nodes are mapped
58   1:1 with QEMU devices)
59 - The framework walks the graph starting from the available machines and
60   performs a Depth First Search for tests
61 - Once a test is found, the path is walked again and all drivers are
62   allocated accordingly and the final interface is passed to the test
63 - The test is executed
64 - Unused objects are cleaned and the path discovery is continued
66 Depending on the QEMU binary used, only some drivers/machines will be
67 available and only test that are reached by them will be executed.
69 Creating a new driver and its interface
70 """""""""""""""""""""""""""""""""""""""""
72 .. code::
74     #include "qgraph.h"
76     struct My_driver {
77         QOSGraphObject obj;
78         Node_produced prod;
79         Node_contained cont;
80     }
82     static void my_destructor(QOSGraphObject *obj)
83     {
84         g_free(obj);
85     }
87     static void *my_get_driver(void *object, const char *interface) {
88         My_driver *dev = object;
89         if (!g_strcmp0(interface, "my_interface")) {
90             return &dev->prod;
91         }
92         abort();
93     }
95     static void *my_get_device(void *object, const char *device) {
96         My_driver *dev = object;
97         if (!g_strcmp0(device, "my_driver_contained")) {
98             return &dev->cont;
99         }
100         abort();
101     }
103     static void *my_driver_constructor(void *node_consumed,
104                                         QOSGraphObject *alloc)
105     {
106         My_driver dev = g_new(My_driver, 1);
108         // get the node pointed by the produce edge
109         dev->obj.get_driver = my_get_driver;
111         // get the node pointed by the contains
112         dev->obj.get_device = my_get_device;
114         // free the object
115         dev->obj.destructor = my_destructor;
117         do_something_with_node_consumed(node_consumed);
119         // set all fields of contained device
120         init_contained_device(&dev->cont);
121         return &dev->obj;
122     }
124     static void register_my_driver(void)
125     {
126         qos_node_create_driver("my_driver", my_driver_constructor);
128         // contained drivers don't need a constructor,
129         // they will be init by the parent.
130         qos_node_create_driver("my_driver_contained", NULL);
132         // For the sake of this example, assume machine x86_64/pc
133         // contains "other_node".
134         // This relation, along with the machine and "other_node"
135         // creation, should be defined in the x86_64_pc-machine.c file.
136         // "my_driver" will then consume "other_node"
137         qos_node_contains("my_driver", "my_driver_contained");
138         qos_node_produces("my_driver", "my_interface");
139         qos_node_consumes("my_driver", "other_node");
140     }
142 In the above example, all possible types of relations are created:
143 node "my_driver" consumes, contains and produces other nodes.
144 More specifically::
146   x86_64/pc -->contains--> other_node <--consumes-- my_driver
147                                                         |
148                        my_driver_contained <--contains--+
149                                                         |
150                               my_interface <--produces--+
152 or inverting the consumes edge in consumed_by::
154   x86_64/pc -->contains--> other_node --consumed_by--> my_driver
155                                                             |
156                            my_driver_contained <--contains--+
157                                                             |
158                                   my_interface <--produces--+
160 Creating new test
161 """""""""""""""""
163 .. code::
165     #include "qgraph.h"
167     static void my_test_function(void *obj, void *data)
168     {
169         Node_produced *interface_to_test = obj;
170         // test interface_to_test
171     }
173     static void register_my_test(void)
174     {
175         qos_add_test("my_interface", "my_test", my_test_function);
176     }
178     libqos_init(register_my_test);
180 Here a new test is created, consuming "my_interface" node
181 and creating a valid path from a machine to a test.
182 Final graph will be like this::
184   x86_64/pc --contains--> other_node <--consumes-- my_driver
185                                                          |
186                         my_driver_contained <--contains--+
187                                                          |
188          my_test --consumes--> my_interface <--produces--+
190 or inverting the consumes edge in consumed_by::
192   x86_64/pc --contains--> other_node --consumed_by--> my_driver
193                                                             |
194                            my_driver_contained <--contains--+
195                                                             |
196          my_test <--consumed_by-- my_interface <--produces--+
198 Assuming there the binary is
199 ``QTEST_QEMU_BINARY=./qemu-system-x86_64``
200 a valid test path will be:
201 ``/x86_64/pc/other_node/my_driver/my_interface/my_test``.
203 Additional examples are also in ``test-qgraph.c``
205 Command line:
206 """"""""""""""
208 Command line is built by using node names and optional arguments
209 passed by the user when building the edges.
211 There are three types of command line arguments:
213 - ``in node``      : created from the node name. For example, machines will
214   have ``-M <machine>`` to its command line, while devices
215   ``-device <device>``. It is automatically done by the framework.
216 - ``after node``   : added as additional argument to the node name.
217   This argument is added optionally when creating edges,
218   by setting the parameter @after_cmd_line and
219   @extra_edge_opts in #QOSGraphEdgeOptions.
220   The framework automatically adds
221   a comma before @extra_edge_opts,
222   because it is going to add attributes
223   after the destination node pointed by
224   the edge containing these options, and automatically
225   adds a space before @after_cmd_line, because it
226   adds an additional device, not an attribute.
227 - ``before node``  : added as additional argument to the node name.
228   This argument is added optionally when creating edges,
229   by setting the parameter @before_cmd_line in
230   #QOSGraphEdgeOptions. This attribute
231   is going to add attributes before the destination node
232   pointed by the edge containing these options. It is
233   helpful to commands that are not node-representable,
234   such as ``-fdsev`` or ``-netdev``.
236 While adding command line in edges is always used, not all nodes names are
237 used in every path walk: this is because the contained or produced ones
238 are already added by QEMU, so only nodes that "consumes" will be used to
239 build the command line. Also, nodes that will have ``{ "abstract" : true }``
240 as QMP attribute will loose their command line, since they are not proper
241 devices to be added in QEMU.
243 Example::
245     QOSGraphEdgeOptions opts = {
246         .arg = NULL,
247         .size_arg = 0,
248         .after_cmd_line = "-device other",
249         .before_cmd_line = "-netdev something",
250         .extra_edge_opts = "addr=04.0",
251     };
252     QOSGraphNodeS *node = qos_node_create_driver("my_node", constructor);
253     qos_node_consumes_args("my_node", "interface", &opts);
255 Will produce the following command line:
256 ``-netdev something -device my_node,addr=04.0 -device other``
258 Qgraph API reference
259 ^^^^^^^^^^^^^^^^^^^^
261 .. kernel-doc:: tests/qtest/libqos/qgraph.h