-
Notifications
You must be signed in to change notification settings - Fork 611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Meta] Performance bottlenecks #257
Comments
Has any progress been made on this? I'm trying to get a sense of how it may compare performance wise to ImageMagick |
Sorry if this is the wrong issue to report/ask about this, but is it really ok for the default #[test]
fn allocate_gray_image_1g_raw() {
let mut img = GrayImage::from_raw(32768, 32768, Vec::with_capacity(32768 * 32768));
}
#[test]
fn allocate_gray_image_1g() {
let mut img = GrayImage::new(32768, 32768);
}
|
Vec::with_capacity won't give you a Vec with actual values in it, it will just have the capacity to hold that amount of values. To create a properly initialized Vec you need to do this: |
Apologies :) I thought it must have been something like that... I'll explore more to see what would be the idiomatic rust way to allocate memory once instead of runtime resizing. Thanks for commenting! |
I stumbled on servo on this issue it's quite old servo/servo#8271 Am not sure if the test is done correctly but the difference is huge.
|
The scanlines have been removed, that interface doesn’t make much sense as some image formats are using tiles (like jpeg for example) so the naturally don’t come in scanlines. Regarding the performance, looks like a factor of 2-4, I expected worse for unoptimized code. |
jpeg-turbo uses hand-written assembly and SIMD to make the mathematical operations fast, that's a bit difficult to compete with on stable rust at this time. |
Yes for unoptimized code it's not too bad but I was researching this library to be used as image server it would need to be as fast as possible but it seems not really mature for it yet. |
For jpeg (and other formats doing similar colour conversions and transforms) we really need some way of using SIMD on stable rust to get close to the C implementations. E.g according to valgrind, this function in jpeg was where 20% of the time spent (possibly more as it uses multiple threads). With SIMD Vectors one could do the calculations on multiple components or multiple pixels in parallel. |
Since SIMD has landed in Rust stable, what's the status of this issue? |
I compared Go's JPEG encoder with Rust's JPEG encoder and Go's is quite a bit faster: Go:
Rust (
I manually tuned the quality setting so that the file size is approximately equal (around 409 kB). This is at 75 in Go and 66 in Rust. The visual quality seems pretty much identical with my test photo. Go's JPEG encoder does not use any SIMD instructions (unless the compiler uses them automatically, which I don't think it does): https://golang.org/src/image/jpeg/writer.go Note that Go's encoder does not write proper headers (which means no density values), which is a problem, but I don't think that causes the difference in performance. Go codepackage main
import (
"fmt"
"image/jpeg"
"image/png"
"log"
"os"
"time"
)
func main() {
f, err := os.Open("example.png")
check(err)
i, err := png.Decode(f)
check(err)
_ = f.Close()
for {
f, err := os.Create("go-temp.jpg")
check(err)
start := time.Now()
err = jpeg.Encode(f, i, &jpeg.Options{Quality: 75})
check(err)
err = f.Close()
check(err)
fmt.Println(time.Since(start))
err = os.Rename("go-temp.jpg", "go.jpg")
check(err)
}
}
func check(err error) {
if err != nil {
log.Fatalln(err)
}
} Rust codeuse image::ImageDecoder;
use std::io::Write;
use std::time::Instant;
fn main() {
let decoder = image::png::PngDecoder::new(std::fs::File::open("example.png").unwrap()).unwrap();
let mut img: Vec<u8> = vec![0; decoder.total_bytes() as usize];
let (width, height) = decoder.dimensions();
let color_type = decoder.color_type();
decoder.read_image(img.as_mut()).unwrap();
loop {
let start = Instant::now();
{
let w = std::fs::File::create("rust-temp.jpg").unwrap();
let mut bw = std::io::BufWriter::new(w);
let mut encoder = image::jpeg::JPEGEncoder::new_with_quality(&mut bw, 66);
encoder.encode(&img, width, height, color_type).unwrap();
bw.flush().unwrap();
}
println!("{} ms", start.elapsed().as_millis());
std::fs::rename("rust-temp.jpg", "rust.jpg").unwrap();
}
} |
I'm using image crate to generate thumbnails, and yes, it is a bit on the slow side. I don't know anything, but one point I noticed while looking through libvips (which may be fast, but crashes quite easily) is that it will use "shrink-on-load" features to create thumbnails from jpeg images. https://github.com/libvips/libvips/wiki/HOWTO----Image-shrinking Hope that helps (or you already knew this and this was no help at all). |
There's been many performance optimizations since this issue was created. Please create dedicated issues if there's specific bottlenecks you notice that aren't being tracked already |
Since it gets mentioned relatively often, this bug should collect all known performance issues.
The text was updated successfully, but these errors were encountered: