Skip to content

Conversation

@richcarl
Copy link
Contributor

Takes care of a couple of old TODO notes: adds write caching, which speeds up sequential writes by upwards of 300%, and adds pruning of the data structure when the array shrinks, so that the unused parts can be GC:d.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 21, 2026

CT Test Results

    3 files    130 suites   1h 22m 44s ⏱️
2 615 tests 2 562 ✅ 51 💤 2 ❌
3 115 runs  3 057 ✅ 56 💤 2 ❌

For more details on these failures, see this check.

Results for commit 0daddab.

♻️ This comment has been updated with latest results.

To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass.

See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally.

Artifacts

// Erlang/OTP Github Action Bot

@richcarl
Copy link
Contributor Author

Your commiting-BEAM-file check is drunk.

@kikofernandez
Copy link
Contributor

Yes, it detected that one of your contributions contains *.beam files that should not be committed...
It does not apply to this commit, but it will prevent in the long-term external contributions that modify *.beam files
I will try to fix today/tomorrow, or please provide a quick fix. I provide below the lines that need to be updated
https://github.com/erlang/otp/blob/master/.github/workflows/main.yaml#L81-L82

@richcarl
Copy link
Contributor Author

Yes, it detected that one of your contributions contains *.beam files that should not be committed...

The diff included changes that had happened on the target branch (master), not just the ones in the contribution. I rebased and pushed a fix that I think should work for the future.

@IngelaAndin IngelaAndin added the team:PS Assigned to OTP team PS label Jan 23, 2026
@dgud dgud self-assigned this Jan 23, 2026
@IngelaAndin IngelaAndin added the waiting waiting for changes/input from author label Jan 27, 2026
@dgud
Copy link
Contributor

dgud commented Jan 28, 2026

I wait with this until the other (discussed changes) are incorporated.

dgud added 2 commits January 31, 2026 12:02
Measurements gives that a bucket size of 16 seems to be the best size
nowadays. Measurements where done on size 8, 10, 16 and 32.

The power of 2 size also enables us to use bit operations
instead of rem/div, that gave even more performance
even if the div/rem operations where optimized.

Further optimizations might be to remove the bit-size storage in the
nodes, and only keep that on the top-level array.
Remove unused tests in source code.
end,
#array{size = Size, max = M, default = Default, elements = E}.
E = find_max(Size - 1, ?SHIFT),
C = ?NEW_CACHE(Default),
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder to what extent it would be worth it to try and optimise the operations when the default is unchanged to return literals

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think I understand?

Unchanged the default is 'undefined', which should be an immediate, can't be better than that, can it?
But even if it the user set default to an literal, wouldn't that just be a pointer to literal area, what do you have in mind?

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean to have the macros like ?NEW_CACHE or others that dynamically create tuples for values to instead return a literal tuple if Default == ?DEFAULT - avoiding some of the allocations

Keep the size information in meta-data only, and forward recursively.
Reduces memory and removes one bit shift on recursions.

Fixed coverage and removed some dead code.
@dgud dgud added testing currently being tested, tag is used by OTP internal CI and removed waiting waiting for changes/input from author labels Feb 6, 2026
dgud
dgud previously approved these changes Feb 6, 2026
Comment on lines 179 to 186
-record(array, {size :: non_neg_integer(), %% number of defined entries
max :: non_neg_integer(), %% maximum number of entries
%% in current tree
fix :: boolean(), %% not automatically growing
default, %% the default value (usually 'undefined')
elements :: elements(_) %% the tuple tree
cache :: cache(), %% cached leaf tuple
cache_index :: non_neg_integer(),
elements :: elements(_), %% the tuple tree
bits :: integer() %% in bits
}).
Copy link
Contributor

@michalmuskala michalmuskala Feb 6, 2026

Choose a reason for hiding this comment

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

Would it make sense to store some fields together to save on garbage when the array is updated - the old implementation had just 4 top-level fields, this has 7, so every update operation creates at least 3 words more of garbage

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have thought about it, but most fields are needed regularly enough that you don't want to follow an extra pointer to access them. But a linear type analysis allowing in-place updates would be nice...

@bjorng bjorng removed the testing currently being tested, tag is used by OTP internal CI label Feb 7, 2026
@bjorng
Copy link
Contributor

bjorng commented Feb 7, 2026

pdict_SUITE:mixed/1 in the kernel application fails:

=== Location: [{erlang,tuple_to_list},
 {array,prune,492},
 {array,shrink_1,488},
 {array,resize,455},
 {pdict_SUITE,do_mixed,456},
 {pdict_SUITE,mixed,412},
 {test_server,ts_tc,1796},
 {test_server,run_test_case_eval1,1305}]
=== === Reason: bad argument
  in function  tuple_to_list/1
     called as tuple_to_list(7548)
     *** argument 1: not a tuple
  in call from array:prune/4 (array.erl:492)
  in call from array:shrink_1/4 (array.erl:488)
  in call from array:resize/2 (array.erl:455)
  in call from pdict_SUITE:do_mixed/5 (pdict_SUITE.erl:456)
  in call from pdict_SUITE:mixed/1 (pdict_SUITE.erl:412)
  in call from test_server:ts_tc/3 (test_server.erl:1796)
  in call from test_server:run_test_case_eval1/6 (test_server.erl:1305)

@bjorng
Copy link
Contributor

bjorng commented Feb 7, 2026

The indent2_SUITE:arr/1 and opaque_SUITE:array/1 test cases for Dialyzer now also fail.

And added more regression tests.
@IngelaAndin IngelaAndin added this to the OTP-29.0 milestone Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

team:PS Assigned to OTP team PS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants