- Notifications
You must be signed in to change notification settings - Fork5
Benchmarks
When running SVGOs defaults against OXVG's defaults -- which are almost identical -- OXVG runs considerably faster.
Just running it once yields the following comparison, bringing a 10x improvement overall and 3.5x improvement for the actual optimization. This shows that the main bottleneck of svgo is the cold start of node/bun, reading files, and writing to stdout. If your use case is focused on optimizing many/large files then oxvg is for you! If you're more focused on running optimisation on in-memory svgs, then you'll also see positive improvements in performance if you're willing to consider the tradeoffs.
provider | total time | optimisation time |
---|---|---|
oxvg | 16.44ms | 12.08ms |
svgo (node) | 383.36ms | 89ms |
svgo (bun) | 222.16ms | 69ms |
These results are based on running the programs onblobs.svg.
How it's run
./target/release/oxvg optimise blobs.svgnode bin/svgo.js blobs.svg-o-bun bin/svgo.js blobs.svg -o -
When parsing a detailedworld map consider the following comparisons in some off-the-bat benchmarks.OXVG was benchmarked usingdivan while SVGO was benchmarked usingconsole.time
.
Remember to always take benchmarks with a grain of salt. Performance may vary depending on hardware and platform. That being said, as of 12th October 2024, not much effort has been made into optimising OXVG runtime performance, yet we see an average 3.2x improvement.
test | fastest | slowest | median | mean | samples | iters |
---|---|---|---|---|---|---|
parse | 30 µs | 96 µs | 30 µs | 32 µs | 100 | 100 |
optimise | 136 µs | 221 µs | 136 µs | 141 µs | 100 | 100 |
whole svg | 146 ms | 153 ms | 147 ms | 147 ms | 100 | 100 |
test | fastest | slowest | median | mean | samples | iters |
---|---|---|---|---|---|---|
parse | 68 µs | 892 µs | 71 µs | 81 µs | 100 | 100 |
optimise | 456 µs | 3ms 799 µs | 492 µs | 537 µs | 100 | 100 |
whole svg | 440 ms | 605 ms | 470 ms | 476 ms | 100 | 100 |
OXVG benchmark source
/// Create a file at `crates/oxvg_optimiser/benches/path.rs`/// Run the command `cargo bench -q -p oxvg_optimiser --profile bench`use divan::Bencher;fnmain(){ divan::main();}#[divan::bench]fnparse(bencher:Bencher){ bencher.bench(|| oxvg_path::Path::parse(PATH));}#[divan::bench]fnoptimise(bencher:Bencher){let path = oxvg_path::Path::parse(PATH).unwrap(); bencher.bench(|| -> oxvg_path::Path{ oxvg_path::convert::run(&path,&oxvg_path::convert::Options::default(),&oxvg_path::convert::StyleInfo::empty(),)});}#[divan::bench]fnsvg(bencher:Bencher){use xml5ever::{ driver::{parse_document,XmlParseOpts}, tendril::TendrilSink,}; bencher.with_inputs(||{let job: oxvg_optimiser::Jobs = serde_json::from_str(r#"{ "convertPathData": {} }"#).unwrap();let dom: rcdom::RcDom =parse_document(rcdom::RcDom::default(),XmlParseOpts::default()).one(LARGE_SVG);[(job, dom)]}).bench_values(|[(job, dom)]| job.run(&dom));}/// Using the United Arab Emirates path from https://www.amcharts.com/lib/3/maps/svg/worldHigh.svgconstPATH =&str ="";/// Using the world map svg from https://www.amcharts.com/lib/3/maps/svg/worldHigh.svgconstLARGE_SVG =&str ="";
SVGO benchmark source
/** * create a file at /benchmark.js * run `node ./benchmark.js` * In my case I'm using nushell, an easy way to process the results is as follows * ```nu * let result = (node ./benchmark.js | lines | parse "{key}: {value}" | update value {|| $in | into duration }) * # sort results to get fastest/slowest * $result | where key == "parse" | sort-by value * # get statistical info * $result | where key == "parse" | math median * $result | where key == "parse" | math avg * ``` * * bunjs also produces results around 2x faster than Node * ```nu * let result = (bun ./benchmark.js err>| lines | parse "[{value}] {key}" | update value {|| $in | into duration }) * ``` */import{optimize}from'./lib/svgo-node.js';import{parsePathData}from'./lib/path.js';import{fn}from'./plugins/convertPathData.js';functionmain(){for(leti=0;i<100;i+=1){parse();optimise();svg();}}functionparse(){console.time('parse');parsePathData(PATH);console.timeEnd('parse');}functionoptimise(){const{element:{ enter},}=fn({type:'root',children:[]},{applyTransforms:false,applyTransformsStroked:false},);constnode={type:'element',name:'path',attributes:{d:PATH},children:[],};console.time('optimise');enter(node);console.timeEnd('optimise');}functionsvg(){constconfig={plugins:[{name:'convertPathData',params:{applyTransforms:false,applyTransformsStroked:false,},},],};console.time('svg');optimize(LARGE_SVG,config);console.timeEnd('svg');}/// Using the United Arab Emirates path from https://www.amcharts.com/lib/3/maps/svg/worldHigh.svgconstPATH="";/// Using the world map svg from https://www.amcharts.com/lib/3/maps/svg/worldHigh.svgconstLARGE_SVG=``;
Hardware
-` noah@archlinux .o+` -------------- `ooo/ OS: Arch Linux x86_64 `+oooo: Host: G5 KC `+oooooo: Kernel: Linux 6.10.10-arch1-1 -+oooooo+: Uptime: 46 seconds `/:-:++oooo+: Packages: 1219 (pacman) `/++++/+++++++: Shell: nushell 0.98.0 `/++++++++++++++: Display (BOE08B3): 1920x1080 @ 144 Hz in 16″ `/+++ooooooooooooo/` DE: GNOME 47.0 ./ooosssso++osssssso+` WM: Mutter (X11) .oossssso-````/ossssss+` WM Theme: Adwaita -osssssso. :ssssssso. Theme: Adwaita [GTK2/3/4] :osssssss/ osssso+++. Icons: Adwaita [GTK2/3/4] /ossssssss/ +ssssooo/- Font: Atkinson Hyperlegible (13pt) [GTK2/3/4] `/ossssso+/:- -:/+osssso+- Cursor: Adwaita (24px) `+sso+:-` `.-/+oso: Terminal: zellij 0.40.1`++:. `-/+/ CPU: Intel(R) Core(TM) i5-10500H (12) @ 4.50 GHz.` `/ GPU 1: NVIDIA GeForce RTX 3060 Mobile / Max-Q GPU 2: Intel UHD Graphics @ 1.05 GHz [Integrated] Memory: 4.34 GiB / 15.32 GiB (28%) Swap: 0 B / 4.00 GiB (0%) Disk (/): 328.10 GiB / 475.94 GiB (69%) - btrfs Local IP (wlan0): 192.168.1.62/24 Battery (BAT): 95% [Discharging] Locale: en_US.UTF-8> node --versionv20.15.0> cargo --versioncargo 1.79.0 (ffa9cf99a 2024-06-03)