Skip to content
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

ECS: Use fxhash in TypeIdMap. #1119

Merged
merged 1 commit into from
Jan 8, 2021
Merged

ECS: Use fxhash in TypeIdMap. #1119

merged 1 commit into from
Jan 8, 2021

Conversation

AngelicosPhosphoros
Copy link
Contributor

Relying on TypeId being some hash internally isn't future-proof because there is no guarantee about internal layout or structure of TypeId. I benchmarked TypeId noop hasher vs fxhash and found that there is very little difference.
Also fxhash is likely to be better supported because it is widely used in rustc itself.

@AngelicosPhosphoros
Copy link
Contributor Author

AngelicosPhosphoros commented Dec 21, 2020

benchmarks I made is here: #1097 (comment)

@memoryruins memoryruins added the A-ECS Entities, components, systems, and events label Dec 22, 2020
Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth doing some whole system performance analysis of how much impact this has by using a Hash implementation that's quite slow (i.e. using Ahmdal's law).

@@ -20,6 +20,7 @@ trace = []
bevy_tasks = { path = "../bevy_tasks", version = "0.4.0" }
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
bevy_ecs_macros = { path = "macros", version = "0.4.0" }
fxhash = "0.2"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to use fx_hash? In bevy_util we are already set up for using ahash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See reasoning #1119 (comment)

Also fxhash used by other dependencies so it needs to be compiled anyway.

/// which hashbrown needs), there is no need to hash it again. Instead, this uses the much
/// faster no-op hash.
pub(crate) type TypeIdMap<V> = HashMap<TypeId, V, BuildHasherDefault<TypeIdHasher>>;
pub(crate) type TypeIdMap<V> = HashMap<TypeId, V, fxhash::FxBuildHasher>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we leave a comment here mentioning why we aren't just using RandomState, and perhaps mentioning TypeIdHasher.

Copy link
Contributor Author

@AngelicosPhosphoros AngelicosPhosphoros Dec 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps mentioning TypeIdHasher

I don't think that there is a reason to mention deleted code in comments. It would just distract people unneccessary.

@AngelicosPhosphoros
Copy link
Contributor Author

AngelicosPhosphoros commented Dec 24, 2020

@DJMcNab I run benches in bevy/benches folder. I didn't run overhead_iter benches because criterion crashes every time when it try to compare it results. I just deleted overhead_iter folder from criterion report between runs.

I don't know is Ahash better or FxHash, it seems that both have little effect (ahash performs little better in single threaded benches while fxhash in multithreaded).

I think, differences here is just noise.

Comparison between old TypeIdHash and fxhash.

overhead_par_iter/threads/1
                        time:   [57.211 us 57.743 us 58.199 us]
                        change: [+10.066% +13.569% +17.144%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) low severe
  1 (1.00%) high mild
overhead_par_iter/threads/2
                        time:   [46.969 us 47.279 us 47.693 us]
                        change: [-6.3837% -4.5948% -2.9574%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  2 (2.00%) high mild
  7 (7.00%) high severe
overhead_par_iter/threads/4
                        time:   [75.005 us 75.859 us 76.788 us]
                        change: [-9.0023% -7.4223% -5.9056%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 9 outliers among 100 measurements (9.00%)
  5 (5.00%) high mild
  4 (4.00%) high severe
overhead_par_iter/threads/8
                        time:   [114.50 us 115.08 us 115.66 us]
                        change: [-2.9213% -2.0124% -1.1130%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) low mild
  1 (1.00%) high mild
overhead_par_iter/threads/16
                        time:   [129.65 us 130.50 us 131.32 us]
                        change: [-3.5935% -2.6017% -1.6707%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  2 (2.00%) low mild
  3 (3.00%) high mild
  2 (2.00%) high severe
overhead_par_iter/threads/32
                        time:   [132.06 us 132.92 us 133.75 us]
                        change: [+2.4222% +3.5232% +4.6567%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 3 outliers among 100 measurements (3.00%)
  3 (3.00%) low mild

Benchmarking for_each_iter: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 21.9s, or reduce sample count to 20.
for_each_iter           time:   [202.40 ms 205.21 ms 208.08 ms]
                        change: [+4.7140% +6.3529% +7.8758%] (p = 0.00 < 0.05)
                        Performance has regressed.

Benchmarking for_each_par_iter/threads/1: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 12.5s, or reduce sample count to 40.
for_each_par_iter/threads/1
                        time:   [123.95 ms 127.56 ms 131.07 ms]
                        change: [-2.5091% +1.3850% +5.3799%] (p = 0.52 > 0.05)
                        No change in performance detected.
Benchmarking for_each_par_iter/threads/2: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 8.2s, or reduce sample count to 60.
for_each_par_iter/threads/2
                        time:   [80.468 ms 81.328 ms 82.209 ms]
                        change: [-1.9011% -0.4065% +1.0493%] (p = 0.59 > 0.05)
                        No change in performance detected.
for_each_par_iter/threads/4
                        time:   [45.755 ms 45.962 ms 46.172 ms]
                        change: [-1.9993% -1.2790% -0.5803%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild
for_each_par_iter/threads/8
                        time:   [26.459 ms 26.517 ms 26.580 ms]
                        change: [+0.0541% +0.3071% +0.5806%] (p = 0.02 < 0.05)
                        Change within noise threshold.
Found 13 outliers among 100 measurements (13.00%)
  6 (6.00%) high mild
  7 (7.00%) high severe
for_each_par_iter/threads/16
                        time:   [14.488 ms 14.547 ms 14.615 ms]
                        change: [-1.3662% -0.6621% +0.0314%] (p = 0.07 > 0.05)
                        No change in performance detected.
Found 12 outliers among 100 measurements (12.00%)
  4 (4.00%) high mild
  8 (8.00%) high severe
for_each_par_iter/threads/32
                        time:   [14.503 ms 14.562 ms 14.629 ms]
                        change: [-1.1154% -0.4451% +0.2543%] (p = 0.20 > 0.05)
                        No change in performance detected.
Found 11 outliers among 100 measurements (11.00%)
  2 (2.00%) high mild
  9 (9.00%) high severe

Benchmarking many_maps_iter: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 19.2s, or reduce sample count to 20.
many_maps_iter          time:   [209.52 ms 211.89 ms 214.11 ms]
                        change: [+8.8041% +10.085% +11.185%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 23 outliers among 100 measurements (23.00%)
  7 (7.00%) low severe
  16 (16.00%) low mild

Benchmarking many_maps_par_iter/threads/1: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 12.5s, or reduce sample count to 40.
many_maps_par_iter/threads/1
                        time:   [119.95 ms 123.60 ms 127.19 ms]
                        change: [-3.5444% +0.4422% +4.6221%] (p = 0.83 > 0.05)
                        No change in performance detected.
Benchmarking many_maps_par_iter/threads/2: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 7.9s, or reduce sample count to 60.
many_maps_par_iter/threads/2
                        time:   [75.942 ms 76.777 ms 77.652 ms]
                        change: [-1.3678% +0.0338% +1.5773%] (p = 0.96 > 0.05)
                        No change in performance detected.
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild
many_maps_par_iter/threads/4
                        time:   [44.258 ms 44.475 ms 44.690 ms]
                        change: [-4.3059% -3.6239% -2.9538%] (p = 0.00 < 0.05)
                        Performance has improved.
many_maps_par_iter/threads/8
                        time:   [26.312 ms 26.328 ms 26.344 ms]
                        change: [-0.1002% +0.0824% +0.2376%] (p = 0.35 > 0.05)
                        No change in performance detected.
many_maps_par_iter/threads/16
                        time:   [14.333 ms 14.384 ms 14.444 ms]
                        change: [-1.0313% -0.4649% +0.1509%] (p = 0.11 > 0.05)
                        No change in performance detected.
Found 12 outliers among 100 measurements (12.00%)
  12 (12.00%) high severe
many_maps_par_iter/threads/32
                        time:   [14.369 ms 14.416 ms 14.473 ms]
                        change: [-1.1490% -0.6373% -0.0965%] (p = 0.02 < 0.05)
                        Change within noise threshold.
Found 11 outliers among 100 measurements (11.00%)
  1 (1.00%) high mild
  10 (10.00%) high severe

This is comparison between FxHash and Ahash:

overhead_par_iter/threads/1
                        time:   [44.627 us 46.120 us 47.971 us]
                        change: [-18.842% -15.800% -12.699%] (p = 0.00 < 0.05)
                        Performance has improved.
overhead_par_iter/threads/2
                        time:   [50.244 us 50.758 us 51.373 us]
                        change: [+7.2185% +8.7289% +10.223%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) high mild
  1 (1.00%) high severe
overhead_par_iter/threads/4
                        time:   [78.458 us 79.563 us 80.913 us]
                        change: [+2.3604% +3.8632% +5.4689%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 10 outliers among 100 measurements (10.00%)
  5 (5.00%) high mild
  5 (5.00%) high severe
overhead_par_iter/threads/8
                        time:   [113.95 us 114.66 us 115.42 us]
                        change: [-0.3414% +0.6894% +1.8211%] (p = 0.24 > 0.05)
                        No change in performance detected.
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
  1 (1.00%) high severe
overhead_par_iter/threads/16
                        time:   [134.43 us 135.69 us 136.90 us]
                        change: [+2.7929% +4.0322% +5.2249%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 4 outliers among 100 measurements (4.00%)
  4 (4.00%) low mild
overhead_par_iter/threads/32
                        time:   [122.10 us 123.08 us 124.18 us]
                        change: [-2.6848% -1.0317% +0.8473%] (p = 0.26 > 0.05)
                        No change in performance detected.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

Benchmarking for_each_iter: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 19.3s, or reduce sample count to 20.
for_each_iter           time:   [192.11 ms 192.24 ms 192.37 ms]
                        change: [-7.6053% -6.3220% -5.0135%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  5 (5.00%) high mild

Benchmarking for_each_par_iter/threads/1: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 13.7s, or reduce sample count to 30.
for_each_par_iter/threads/1
                        time:   [133.01 ms 136.79 ms 140.51 ms]
                        change: [+3.2951% +7.2355% +11.481%] (p = 0.00 < 0.05)
                        Performance has regressed.
Benchmarking for_each_par_iter/threads/2: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 7.7s, or reduce sample count to 60.
for_each_par_iter/threads/2
                        time:   [76.865 ms 77.749 ms 78.668 ms]
                        change: [-5.8072% -4.4006% -2.9411%] (p = 0.00 < 0.05)
                        Performance has improved.
for_each_par_iter/threads/4
                        time:   [46.355 ms 46.575 ms 46.796 ms]
                        change: [+0.7086% +1.3337% +2.0073%] (p = 0.00 < 0.05)
                        Change within noise threshold.
for_each_par_iter/threads/8
                        time:   [26.540 ms 26.587 ms 26.640 ms]
                        change: [-0.0314% +0.2642% +0.5706%] (p = 0.08 > 0.05)
                        No change in performance detected.
Found 15 outliers among 100 measurements (15.00%)
  1 (1.00%) high mild
  14 (14.00%) high severe
for_each_par_iter/threads/16
                        time:   [14.481 ms 14.542 ms 14.611 ms]
                        change: [-0.6615% -0.0372% +0.5964%] (p = 0.91 > 0.05)
                        No change in performance detected.
Found 10 outliers among 100 measurements (10.00%)
  2 (2.00%) high mild
  8 (8.00%) high severe
for_each_par_iter/threads/32
                        time:   [14.502 ms 14.560 ms 14.626 ms]
                        change: [-0.6248% -0.0113% +0.5952%] (p = 0.97 > 0.05)
                        No change in performance detected.
Found 12 outliers among 100 measurements (12.00%)
  2 (2.00%) high mild
  10 (10.00%) high severe

Benchmarking many_maps_iter: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 19.2s, or reduce sample count to 20.
many_maps_iter          time:   [191.55 ms 191.69 ms 191.84 ms]
                        change: [-10.480% -9.5310% -8.5131%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

Benchmarking many_maps_par_iter/threads/1: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 12.5s, or reduce sample count to 40.
many_maps_par_iter/threads/1
                        time:   [119.66 ms 123.41 ms 127.18 ms]
                        change: [-4.3402% -0.1568% +4.1849%] (p = 0.95 > 0.05)
                        No change in performance detected.
Benchmarking many_maps_par_iter/threads/2: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 8.3s, or reduce sample count to 60.
many_maps_par_iter/threads/2
                        time:   [80.550 ms 81.585 ms 82.650 ms]
                        change: [+4.5088% +6.2628% +8.0304%] (p = 0.00 < 0.05)
                        Performance has regressed.
many_maps_par_iter/threads/4
                        time:   [46.373 ms 46.610 ms 46.850 ms]
                        change: [+4.0527% +4.7994% +5.5538%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
many_maps_par_iter/threads/8
                        time:   [26.300 ms 26.339 ms 26.384 ms]
                        change: [-0.1109% +0.0392% +0.2235%] (p = 0.67 > 0.05)
                        No change in performance detected.
Found 14 outliers among 100 measurements (14.00%)
  1 (1.00%) high mild
  13 (13.00%) high severe
many_maps_par_iter/threads/16
                        time:   [14.626 ms 14.744 ms 14.874 ms]
                        change: [+1.5994% +2.5041% +3.5754%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 12 outliers among 100 measurements (12.00%)
  4 (4.00%) high mild
  8 (8.00%) high severe
many_maps_par_iter/threads/32
                        time:   [14.514 ms 14.578 ms 14.647 ms]
                        change: [+0.5442% +1.1175% +1.6940%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 10 outliers among 100 measurements (10.00%)
  6 (6.00%) high mild
  4 (4.00%) high severe

@cart
Copy link
Member

cart commented Dec 24, 2020

Last time I compared fxhash to ahash in the context of Bevy ECS, aHash came out on top. We use aHash everywhere in Bevy (see bevy_utils), largely as a result of those numbers ... which were never published publicly 😄

Unless we have a very good reason, I'd prefer to stay consistent everywhere / use what already works for us. If we can prove that fxhash is a measurable / significant perf improvement, I'm down to make the switch. But otherwise id rather just stick with what currently works.

When it comes to benchmarks, id prefer it if we used less synthetic benchmarks because optimizers are weird. Lets use ecs_bench_suite to check for perf changes.

See this discussion on the upstream hecs repo for the rationale behind the change and some significant perf improvements we measured (both in upstream hecs and bevy ecs)

@AngelicosPhosphoros
Copy link
Contributor Author

AngelicosPhosphoros commented Dec 26, 2020

@cart @DJMcNab
OK, I run this benchmarks and got this values:
old hash -> fxhash

simple_insert/bevy      time:   [568.27 us 569.88 us 571.48 us]
                        change: [-2.9450% -1.7396% -0.5369%] (p = 0.01 < 0.05)
                        Change within noise threshold.
Found 6 outliers among 100 measurements (6.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  2 (2.00%) high severe

simple_iter/bevy        time:   [16.566 us 16.580 us 16.593 us]
                        change: [-2.3496% -1.7000% -1.1276%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  1 (1.00%) high severe

fragmented_iter/bevy    time:   [574.79 ns 575.87 ns 576.94 ns]
                        change: [-8.4033% -7.2360% -6.4673%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

schedule/bevy           time:   [49.921 us 50.316 us 50.716 us]
                        change: [-1.4201% +0.5993% +2.4903%] (p = 0.55 > 0.05)
                        No change in performance detected.
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe

heavy_compute/bevy      time:   [581.71 us 583.93 us 586.26 us]
                        change: [-0.7975% +0.0048% +0.7285%] (p = 0.98 > 0.05)
                        No change in performance detected.
Found 5 outliers among 100 measurements (5.00%)
  4 (4.00%) high mild
  1 (1.00%) high severe

add_remove_component/bevy
                        time:   [6.3472 ms 6.3587 ms 6.3703 ms]
                        change: [-2.0538% -1.8168% -1.5582%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild

And old hash -> ahash

simple_insert/bevy      time:   [809.23 us 811.29 us 813.46 us]
                        change: [+38.625% +40.056% +41.473%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild

simple_iter/bevy        time:   [16.158 us 16.191 us 16.223 us]
                        change: [-4.8092% -4.1692% -3.6036%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

fragmented_iter/bevy    time:   [593.41 ns 596.20 ns 601.55 ns]
                        change: [-5.1417% -3.9081% -3.0008%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 7 outliers among 100 measurements (7.00%)
  4 (4.00%) high mild
  3 (3.00%) high severe

schedule/bevy           time:   [48.396 us 48.772 us 49.195 us]
                        change: [-4.9563% -3.0155% -1.3041%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 5 outliers among 100 measurements (5.00%)
  2 (2.00%) high mild
  3 (3.00%) high severe

heavy_compute/bevy      time:   [558.59 us 562.10 us 565.82 us]
                        change: [-4.1068% -3.1525% -2.2253%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) high mild
  2 (2.00%) high severe

add_remove_component/bevy
                        time:   [6.7759 ms 6.7845 ms 6.7931 ms]
                        change: [+4.5338% +4.7580% +4.9712%] (p = 0.00 < 0.05)
                        Performance has regressed.
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) low mild
  2 (2.00%) high mild

fxhash -> ahash

simple_insert/bevy      time:   [708.67 us 715.52 us 723.38 us]
                        change: [+27.258% +28.890% +30.446%] (p = 0.00 < 0.05)
                        Performance has regressed.

simple_iter/bevy        time:   [16.409 us 16.442 us 16.477 us]
                        change: [-0.9573% -0.7839% -0.5964%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) low mild

fragmented_iter/bevy    time:   [595.74 ns 596.40 ns 597.14 ns]
                        change: [+4.4259% +4.7573% +5.1486%] (p = 0.00 < 0.05)
                        Performance has regressed.

schedule/bevy           time:   [50.882 us 51.352 us 51.839 us]
                        change: [-0.8439% +0.7428% +2.4456%] (p = 0.39 > 0.05)
                        No change in performance detected.
Found 4 outliers among 100 measurements (4.00%)
  2 (2.00%) high mild
  2 (2.00%) high severe

heavy_compute/bevy      time:   [589.58 us 606.95 us 627.37 us]
                        change: [+0.4925% +2.7667% +5.3625%] (p = 0.03 < 0.05)
                        Change within noise threshold.
Found 12 outliers among 100 measurements (12.00%)
  12 (12.00%) high severe

add_remove_component/bevy
                        time:   [6.7019 ms 6.7127 ms 6.7236 ms]
                        change: [+5.3205% +5.5680% +5.8364%] (p = 0.00 < 0.05)
                        Performance has regressed.

I looks like that fxhash has comparable speed as noop hasher and ahash clearly slower than fxhash and noop. Probable reason of this that ahash optimized for data chunked by 128 bits (its code uses u128 heavily). fxhash, in contrast, optimized to use usize width (src) so works better for 8 bytes values which TypeIds are. Also Hash Dos protection (which is useless for TypeIds I believe) can be costly.

Relying on TypeId being some hash internally isn't future-proof because there is no guarantee about internal layout or structure of TypeId. I benchmarked TypeId noop hasher vs fxhash and found that there is very little difference.
Also fxhash is likely to be better supported because it is widely used in rustc itself.
[Benchmarks of hashers](#1097)
[Engine wide benchmarks](#1119 (comment))
Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already import fxhash anyway via wgpu, so I'm happy using fxhash, considering how much faster it is than ahash.

$ cargo tree -p byteorder
byteorder v1.3.4

Edit: Well that's not right, obviously
Can't fix it as on mobile

@AngelicosPhosphoros
Copy link
Contributor Author

├── wgpu-core v0.6.5
    │       │   ├── arrayvec v0.5.2
    │       │   ├── bitflags v1.2.1
    │       │   ├── copyless v0.1.5
    │       │   ├── fxhash v0.2.1 (*)

What is not right?

@DJMcNab
Copy link
Member

DJMcNab commented Dec 26, 2020

The exact message which I sent, because that was about the byteorder crate instead of the fxhash crate.

Because I knew the byteorder crate was the only dependency of fxhash, I checked that first.

@cart
Copy link
Member

cart commented Dec 30, 2020

Awesome. Those numbers are pretty convincing. In a few days when I'm back at the computer I've benched on before, I'll run some benches on my side just to convince myself thoroughly. But if everything lines up this looks like a clear win (small perf boosts in some cases, reduced code complexity, and maybe the potential to remove ahash from the build tree)

@cart
Copy link
Member

cart commented Jan 8, 2021

Alrighty I finally got around to testing this. Using fxhash for this case specifically is pretty clearly a win:
image

However switching bevy_utils to fxhash is a pretty major downgrade. I think ahash is much better at hashing very small values (ex: u32 / u64), which is way more common.

image

So I'm inclined to merge this, but keep AHash as the "default bevy hasher".

@cart cart merged commit 9bce871 into bevyengine:master Jan 8, 2021
rparrett pushed a commit to rparrett/bevy that referenced this pull request Jan 27, 2021
Relying on TypeId being some hash internally isn't future-proof because there is no guarantee about internal layout or structure of TypeId. I benchmarked TypeId noop hasher vs fxhash and found that there is very little difference.
Also fxhash is likely to be better supported because it is widely used in rustc itself.
[Benchmarks of hashers](bevyengine#1097)
[Engine wide benchmarks](bevyengine#1119 (comment))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants