-
Notifications
You must be signed in to change notification settings - Fork 0
Transfer Monitoring
To demonstrate and benchmark performance of the xHCI stack, a proprietary subsystem has been implemented in HelenOS. The primary function of this subsystem is to communicate with a custom QEMU USB device over arbitrary endpoints and provide statistical information related to the communication. This way, it can be used to verify the correctness of message transmission, experiment with synchronization and to measure performance indicators.
In addition, since the subsystem is built on top of the USB device driver framework and has no xHCI-specific requirements, it can be also used to compare parameters of the xHCI stack with its predecessors.
The subsystem is composed of three parts:
- QEMU fork with a proprietary diagnostic device (usb-tmon)
- This implementation of QEMU contains a virtual USB device, which carries the diagnostic device class descriptor.
- USB Diagnostic Device Driver (usbdiag)
- The usbdiag driver matches with the QEMU diagnostic device and facilitates all communication with it. It also exposes a remote interface for all HelenOS aplications.
- User Frontend Program (tmon)
- The tmon program is the primary user frontend in shell. It can use the interface exposed by usbdiag to perform various tests with diagnostic devices and return human-readable results.
The usb-tmon
virtual device is a diagnostic class USB device created in order to easily test the functionality
of the xHCI stack. It contains two sets of endpoints, each of which contains six endpoints (one for each
transfer direction for each type of transfer - i.e. interrupt, bulk and isochronous). The first set of endpoints
(0x1 - 0x6) only monitors the size of the data it receives or sends but does not perform any check for validity
when it receives data nor does it actually send any data back (it only tells QEMU to use its buffer as it is as
the result). The second set of endpoints (0x7 - 0xC) fills the packets it sends to the host with a repeated predefined
value (0xDEADBEEF
) and checks the packets it receives that it contains the same repeated value.
The information gathered and displayed depends on the type of transfer the device receives:
- Interrupt
- On every IN or OUT data request, the device outputs to QEMU's standard output the time (in microseconds) since the last transfer request of the same type.
- Bulk
- On every bulk transfer request, the device checks the time since the last request of the same type, if the time is over a second, the device outputs to QEMU's standard output the amount of bytes transferred in that time period.
- Isochronous
- Currently only outputs to QEMU's standard output a message notifying the user that a transfer of this type has been received.
The implementation of this device is located in the file hw/usb/dev-tmon.c
in the helenos-xhci-team/qemu
fork
of the official QEMU repository. It contains several key structures and functions:
- USBTmonState
- Structure that reperesents the current state of a `usb-tmon` device.
- desc_tmon, desc_device_tmon, desc_iface_tmon
- These three structures form the descriptor of the device and contain information about the device's class, protocol, endpoints etc.
- usb_tmon_class_init
- Called when QEMU starts, so it is used as a constructor function for the virtual device and all relevant data.
- usb_tmon_realize
- Called when an instance of the `usb-tmon` device gets created and is used to initialize a specific instance of `USBTmonState`.
- usb_tmon_handle_attach
- Called when an instance of the `usb-tmon` device get attached to the guest OS.
- usb_tmon_handle_control
- Called when the device receives a control request, in its current implementation simply forwards the request to QEMU via `usb_desc_handle_control`.
- usb_tmon_handle_data
- Called when the device receives an interrupt, a bulk or an isochronous data request, determines the receiving endpoint, stores information about handled data and if needed, sends or validates a USB packet.
- usb_tmon_{int|bulk|isoc}_{in|out}
- Called on specific kinds of transfers and track sent/received data.
These are the structures and functions one needs to modify in order to modify the behavior of the device.
Additionally, the source code contains helper functions (e.g. time measurement with get_now_sec
and get_now_usec
)
and QEMU debuggin/informational functions and structures (e.g. desc_strings
, vmstate_usb_tmon
, usb_tmon_info
and usb_tmon_register_types
). These should seldom require modification.
For the purposes of modifying or debugging usb-tmon
's source code, the header include/hw/usb.h
contains
most of the structure definitions and function declarations that might be needed.
In a running instance of QEMU, one can press the C-A-2
key combination to switch to the monitor in which they
can type device_add usb-tmon
to attach a new usb-tmon
device (it is possible to redirect the monitor to QEMU's
standard IO by adding -monitor stdio
to its startup command). To have QEMU start with usb-tmon
attached, they
may add -device usb-tmon
to their QEMU startup command.
TODO @petrmanek
This section explains what you can find in the uspace/app/tmon
directory.
- main.c
- Main entry point, command selection and usage string.
- commands.h
- Executable commands.
- list.c
- Implementation of the `list` command.
- tf.h, tf.c
- Testing framework, common code for all `test-*` commands.
- resolve.h, resolve.c
- Resolving DDF device from string using devman's IPC interface.
- burst_tests.c
- Implementation of burst tests.
tmon: benchmark USB diagnostic device
Usage: tmon command [device] [options]
list - Print a list of connected diagnostic devices.
test-intr-in - Read from interrupt endpoint as fast as possible.
test-intr-out - Write to interrupt endpoint as fast as possible.
test-bulk-in - Read from bulk endpoint as fast as possible.
test-bulk-out - Write to bulk endpoint as fast as possible.
test-isoch-in - Read from isochronous endpoint as fast as possible.
test-isoch-out - Write to isochronous endpoint as fast as possible.
-n --cycles
Set the number of read/write cycles.
-s --size
Set the data size transferred in a single cycle.
If no device is specified, the first device is used provided that it is the only one connected. Otherwise, the command fails.