nanoid icon indicating copy to clipboard operation
nanoid copied to clipboard

experiment to improve perf

Open ruslandoga opened this issue 1 year ago • 0 comments

This PR tries using binary lookups to improve performance. For now I've only updated just one clause in the non-secure generator.

Before
$ MIX_ENV=bench mix run bench/generate.exs
Operating System: macOS
CPU Information: Apple M1
Number of Available Cores: 8
Available memory: 8 GB
Elixir 1.15.7
Erlang 26.1.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 7 s

Benchmarking generate ...

Name               ips        average  deviation         median         99th %
generate      104.87 K        9.54 μs    ±80.33%        9.38 μs       12.21 μs

Profiling generate with eprof...

Profile results of #PID<0.174.0>
#                                               CALLS     % TIME µS/CALL
Total                                            1184 100.0  135    0.11
:rand.seed58/1                                      3  0.00    0    0.00
:rand.exsss_seed/1                                  1  0.00    0    0.00
:rand.mk_alg/1                                      1  0.00    0    0.00
:rand.seed_s/2                                      1  0.00    0    0.00
:rand.seed_s/1                                      1  0.00    0    0.00
:rand.seed/1                                        1  0.00    0    0.00
:erlang.system_time/0                               1  0.00    0    0.00
:erlang.unique_integer/0                            1  0.00    0    0.00
String.graphemes/1                                  1  0.00    0    0.00
:unicode_util.gc_extend/3                           1  0.00    0    0.00
:unicode_util.gc_1/1                                1  0.00    0    0.00
:unicode_util.cp/1                                  1  0.00    0    0.00
Nanoid.NonSecure.generate/1                         1  0.00    0    0.00
Nanoid.NonSecure.generate/0                         1  0.00    0    0.00
Enum.reduce/3                                       1  0.00    0    0.00
Enum.map/2                                          1  0.00    0    0.00
Enum.join/2                                         1  0.00    0    0.00
Enum.join/1                                         1  0.00    0    0.00
Range.new/2                                         1  0.00    0    0.00
Nanoid.Configuration.default_size/0                 1  0.00    0    0.00
Nanoid.Configuration.default_alphabet/0             1  0.00    0    0.00
anonymous fn/0 in :elixir_compiler_1.__FILE__/1     1  0.00    0    0.00
:rand.exsss_uniform/2                              21  0.74    1    0.05
:rand.seed_get/0                                   21  0.74    1    0.05
:rand.uniform_s/2                                  21  0.74    1    0.05
:rand.default_seed/0                                1  0.74    1    1.00
:erlang.phash2/1                                    1  0.74    1    1.00
:erlang.iolist_to_binary/1                          1  0.74    1    1.00
Nanoid.NonSecure.generator/2                        2  0.74    1    0.50
Enum.entry_to_string/1                             21  0.74    1    0.05
:erlang.apply/2                                     1  1.48    2    2.00
anonymous fn/3 in Nanoid.NonSecure.generator/2     21  1.48    2    0.10
Enum.reduce_range/5                                11  1.48    2    0.18
:rand.seed_put/1                                   22  2.22    3    0.14
Enum.random_integer/2                              21  2.22    3    0.14
:rand.splitmix64_next/1                             3  2.96    4    1.33
:erlang.put/2                                      22  2.96    4    0.18
Enum."-map/2-lists^map/1-1-"/2                     22  2.96    4    0.18
:rand.uniform/1                                    21  3.70    5    0.24
Enum.random/1                                      21  3.70    5    0.24
String.do_graphemes/1                              65  8.89   12    0.18
:unicode_util.gc/1                                 65 23.70   32    0.49
Enum.drop_list/2                                  776 36.30   49    0.06
After
$ MIX_ENV=bench mix run bench/generate.exs
Compiling 1 file (.ex)
Operating System: macOS
CPU Information: Apple M1
Number of Available Cores: 8
Available memory: 8 GB
Elixir 1.15.7
Erlang 26.1.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 7 s

Benchmarking generate ...

Name               ips        average  deviation         median         99th %
generate      651.25 K        1.54 μs  ±1603.41%        1.42 μs        1.75 μs

Profiling generate with eprof...

Profile results of #PID<0.187.0>
#                                               CALLS     % TIME µS/CALL
Total                                             193 100.0   48    0.25
:rand.seed58/1                                      3  0.00    0    0.00
:rand.exsss_seed/1                                  1  0.00    0    0.00
:rand.mk_alg/1                                      1  0.00    0    0.00
:rand.seed_s/2                                      1  0.00    0    0.00
:rand.default_seed/0                                1  0.00    0    0.00
:rand.seed_s/1                                      1  0.00    0    0.00
:rand.seed/1                                        1  0.00    0    0.00
:erlang.system_time/0                               1  0.00    0    0.00
:erlang.unique_integer/0                            1  0.00    0    0.00
Nanoid.NonSecure.generator/2                        1  0.00    0    0.00
Nanoid.NonSecure.generate/1                         1  0.00    0    0.00
Nanoid.NonSecure.generate/0                         1  0.00    0    0.00
Nanoid.Configuration.default_size/0                 1  0.00    0    0.00
Nanoid.Configuration.default_alphabet/0             1  0.00    0    0.00
anonymous fn/0 in :elixir_compiler_1.__FILE__/1     1  0.00    0    0.00
:rand.exsss_uniform/2                              21  2.08    1    0.05
:rand.seed_get/0                                   21  2.08    1    0.05
:rand.uniform_s/2                                  21  2.08    1    0.05
:erlang.phash2/1                                    1  2.08    1    1.00
:binary.at/2                                       21  2.08    1    0.05
:rand.seed_put/1                                   22  4.17    2    0.09
:erlang.apply/2                                     1  4.17    2    2.00
:rand.splitmix64_next/1                             3 10.42    5    1.67
:rand.uniform/1                                    21 10.42    5    0.24
:erlang.put/2                                      22 18.75    9    0.41
Nanoid.NonSecure._generate/2                       22 41.67   20    0.91

If there is interest in this approach I can update the other functions and add workarounds for the unicode limitation.

ruslandoga avatar Nov 22 '23 09:11 ruslandoga