[alsa-devel] proposed MPD16 latency workaround
Hi all,
I've played with USB MIDI driver and MPD16 a bit more. The problem is definitely triggered by submitting URBs on the configuration input endpoint - when these are killed, the latency disappears. Disabling the configuration port works, but is a bit heavy-handed, so I've implemented a workaround: initially, the URBs for the input configuration endpoint are not submitted until two conditions are met:
i) the control port is actually open (I check that using input_triggered bitmask)
ii) the driver is switched into config mode by sending a special SysEx message to the output port (which is intercepted by the driver and used to set a flag). This is to prevent programs that open all the MIDI ports in the system (JACK daemon with ALSA MIDI driver, a2jmidid etc.) from starting unwanted communication with configuration endpoints.
Any time one of these conditions is changed, the driver may either submit the URBs or kill them or do nothing - depending on the difference between expected and current "queuing state" of the URBs. This logic is only used for MPD16, for all the other devices the driver always submit their input URBs, no matter if any input is actually wanted or not.
The attached diff is relative to the Ubuntu 2.6.35 kernel, but I'm mostly interested in the review of the general approach - I have some doubts about thread-safety of calling snd_usbmidi_input_update_ep from send function and about the elegance of the SysEx approach (vs. ioctl or something else). If the approach is not too icky and doesn't have hidden flaws, I can try to create a diff relative to alsa-kernel or some other tree.
Any comments? Krzysztof
Krzysztof Foltman wrote:
I've played with USB MIDI driver and MPD16 a bit more. The problem is definitely triggered by submitting URBs on the configuration input endpoint - when these are killed, the latency disappears. Disabling the configuration port works, but is a bit heavy-handed, so I've implemented a workaround: initially, the URBs for the input configuration endpoint are not submitted until two conditions are met:
i) the control port is actually open (I check that using input_triggered bitmask)
ii) the driver is switched into config mode by sending a special SysEx message to the output port (which is intercepted by the driver and used to set a flag). This is to prevent programs that open all the MIDI ports in the system (JACK daemon with ALSA MIDI driver, a2jmidid etc.) from starting unwanted communication with configuration endpoints.
This can be considered a bug in those programs.
I'm mostly interested in the review of the general approach - I have some doubts about thread-safety of calling snd_usbmidi_input_update_ep from send function
I also have doubts, but I didn't look too much into this.
Since this device uses a completely vendor-dependent protocol, your changes result in a driver that uses practically none of the common code for the MPD16. Furthermore, your code makes it harder to maintain the driver because these parts of the code cannot be tested without the MPD16. In other words, I think that writing a separate driver would be a better idea.
I'll see if I can write it until Monday; you'll just have to test it and remove my bugs. :)
and about the elegance of the SysEx approach (vs. ioctl or something else).
If the control port is used only by some specialized control application, it doesn't matter too much which mechanism is used. If the data port is already being used by it, the SysEx approach would indeed be the simplest to use.
Regards, Clemens
On 16/09/10 10:02, Clemens Ladisch wrote:
ii) the driver is switched into config mode by sending a special SysEx message to the output port (which is intercepted by the driver and used to set a flag). This is to prevent programs that open all the MIDI ports in the system (JACK daemon with ALSA MIDI driver, a2jmidid etc.) from starting unwanted communication with configuration endpoints.
This can be considered a bug in those programs.
Yes. Well, it's the case of what's right vs. what's convenient. I think the assumption that opening a MIDI port (sequencer or raw) won't cause disastrous results (like increased latency of some other port) is a fair assumption.
Also, working around the problem in the central place (kernel driver) is, in my opinion, more convenient than fixing that otherwise-harmless behaviour in many other projects (jackd1, jackd2, a2jmidid, another JACK implementation by Torben Hohn that I don't know the name of). Especially given the minimal popularity of the MPD16.
Since this device uses a completely vendor-dependent protocol, your changes result in a driver that uses practically none of the common code for the MPD16.
Well, it _could_ be used for some other USB MIDI devices (the ones using bulk mode on input endpoints) to reduce data churn on USB ports when devices are physically connected but their MIDI ports are not used. Probably isn't worth it though: the power and bandwidth use of the unnecessary polling is probably minimal.
The MPD16 code *does* use some things in the generic driver, like most of the setup code. The only differences are: 1) I/O quirks (and many other devices have those), 2) conditional opening of endpoints (potentially reusable). I don't think the impact is very severe, comparing with the Roland stuff in the same file, for example.
I'll see if I can write it until Monday; you'll just have to test it and remove my bugs. :)
That would be great - if you have time for it. I definitely can take care of testing/debugging in that case.
If the control port is used only by some specialized control application, it doesn't matter too much which mechanism is used. If the data port is already being used by it, the SysEx approach would indeed be the simplest to use.
To clarify: in this solution, to enable control input, you need to send a fake sysex on control output. The device has no functional *data* output, as far as I can tell - there's only data input which sends events from the pads and the slider.
I thought of using alternatives like a hwdep device, a mixer control or an ioctl, but those were frighteningly hard to implement and not really much nicer for the user. And the control port talks MIDI (SysEx messages) anyway.
That specialized control application doesn't even exist at this point. So, a low-effort alternative option to consider would be to completely drop the ability to configure the device, as most of the configuration can be done from the device anyway (the inconvenient but working "hold some button, press some pads" type of interface).
If I had to choose between "enormous latency and automatic configuration... maybe some day" and "imperceptible latency, but have to set it up manually", I'd definitely choose the latter.
Krzysztof
Krzysztof Foltman wrote:
On 16/09/10 10:02, Clemens Ladisch wrote:
ii) the driver is switched into config mode by sending a special SysEx message to the output port (which is intercepted by the driver and used to set a flag). This is to prevent programs that open all the MIDI ports in the system (JACK daemon with ALSA MIDI driver, a2jmidid etc.) from starting unwanted communication with configuration endpoints.
This can be considered a bug in those programs.
Yes. Well, it's the case of what's right vs. what's convenient. I think the assumption that opening a MIDI port (sequencer or raw) won't cause disastrous results (like increased latency of some other port) is a fair assumption.
It is possible that an opened MIDI port uses resources that would be needed by other devices.
Since this device uses a completely vendor-dependent protocol, your changes result in a driver that uses practically none of the common code for the MPD16.
Well, it _could_ be used for some other USB MIDI devices (the ones using bulk mode on input endpoints) to reduce data churn on USB ports when devices are physically connected but their MIDI ports are not used. Probably isn't worth it though: the power and bandwidth use of the unnecessary polling is probably minimal.
I'd estimate that the power usage is measurable on laptops. Changing the driver to submit URBs only when a port is open is one of those changes that I want to do whenever I have time to do unimportant changes.
I'll see if I can write it until Monday; you'll just have to test it and remove my bugs. :)
That would be great - if you have time for it. I definitely can take care of testing/debugging in that case.
Well, it turned out bigger than I would have liked.
Compile-tested. Handle with care.
To clarify: in this solution, to enable control input, you need to send a fake sysex on control output.
I've changed it so that you can send anything to enable the input.
On 20/09/10 08:23, Clemens Ladisch wrote:
It is possible that an opened MIDI port uses resources that would be needed by other devices.
True.
I'd estimate that the power usage is measurable on laptops. Changing the driver to submit URBs only when a port is open is one of those changes that I want to do whenever I have time to do unimportant changes.
In that case, you can probably just use my changes as a starting point. They should be easily adaptable for at least some of the devices (I think only multiple cables per port are hard to support with current set-up). Some day, maybe :)
Well, it turned out bigger than I would have liked. Compile-tested. Handle with care.
Checked it yesterday. The data input works, however, the trying to output some sysex data with amidi prints the "bad dma" messages from the UHCI driver, and data don't end up on a device. Also, either on disconnection or rmmod it OOPSes (can't tell which of them, it came up in the dmesg output but I couldn't do proper tests yet).
I'll try to investigate it further when I have a couple of hours.
That aside, why do you need URB_NO_FSBR flag for the URBs? Because of prevalence of very short packets in the Akai MIDI protocol?
To clarify: in this solution, to enable control input, you need to send a fake sysex on control output.
I've changed it so that you can send anything to enable the input.
That might cause some problems if I (or anyone else) create the config program. They're avoidable (only run the config tool while JACK is not running), but still, it's not what I'd expect as a user.
I'll try to write a patch for all JACKs to blacklist the control device, that should take care of the JACK incompatibility.
Krzysztof
Krzysztof Foltman wrote:
Checked it yesterday. The data input works, however, the trying to output some sysex data with amidi prints the "bad dma" messages from the UHCI driver,
Never heard of that message.
Also, either on disconnection or rmmod it OOPSes (can't tell which of them, it came up in the dmesg output but I couldn't do proper tests yet).
Might be the same problem with some DMA buffer ...
That aside, why do you need URB_NO_FSBR flag for the URBs?
It's optional, so it isn't really needed. I'm using it for control input transfers because those aren't latency sensitive, and using less polling might help with the latency problem on the data input endpoint.
I'll try to write a patch for all JACKs to blacklist the control device, that should take care of the JACK incompatibility.
In theory, Jack should never open any MIDI port that isn't actually used.
Regards, Clemens
participants (2)
-
Clemens Ladisch
-
Krzysztof Foltman