@lilith I’m a Rust consultant who works in high-performance data storage systems. I’d be happy to try to take this on. If you want to chat directly about it, please send me a message or email.
However, for the sake of completeness, I’d like to point out that rewriting mozjpeg in Rust might not be that useful.
- I think that mozjpeg (and the libraries it’s based on) have become a de facto specification. This is an example of Hyrum’s Law, which says:
With a sufficient number of users of an API,
it does not matter what you promise in the contract:
all observable behaviors of your system
will be depended on by somebody.
If mozjpeg’s code – not just its intentions – are the specification to which we need to adhere, then our porting efforts will be error-prone. Matching bug-for-bug compatibility is hard.
The mozjpeg codebase goes back to 1994, and has many different authors and styles involved.
Furthermore, the mozjpeg family of software is robust. For example, Chromium uses libjpeg-turbo, which is an ancestor of mozjpeg.
Finally, Mozilla created mozjpeg expressly to be backwards-compatible with deployed systems. It would be a big effort to replicate that. (Although, the Mozilla Research team may be interested in porting it to pure Rust, for the sake of Firefox.)
So, if possible, we should try to use mozjpeg as-is.
- Which leads me to how to use mozjpeg.
If you’re doing JPEG processing, then it is probably fair to say that your code will be CPU-intensive. As a result, even with Rust’s async support, you will end up using it from within a thread pool. This is because a dedicated thread pool will allow you to take advantage of CPU cache locality (especially L1d and L1i, as well as L2/L3) to increase throughput, and also to reduce latency.
If you agree that you’ll be using a threadpool, then perhaps we can look at the problem from a different angle.
I recommend creating a standalone mozjpeg program that accepts commands over IPC.
To pause execution after a timeslice has elapsed, you can have a timer fire in your async loop that sends SIGSTOP to the mozjpeg process. Later, you can send SIGCONT to resume JPEG processing. Or, if the child mozjpeg process is acting erratically, possibly due to bad input, you can end the process with SIGTERM or SIGKILL. In which case you can safely abort processing, then start a new mozjpeg process to handle the next request.
In conclusion, I recommend creating a standalone mozjpeg program that you can use from a threadpool via IPC, and thereby treat the situation as a noncooperative multitasking problem.