-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[optimization] avoid extra memory copy while build hash table #5301
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |||||
|
|
||||||
| #include "codegen/doris_ir.h" | ||||||
| #include "common/logging.h" | ||||||
| #include "common/object_pool.h" | ||||||
| #include "util/hash_util.hpp" | ||||||
|
|
||||||
| namespace doris { | ||||||
|
|
@@ -142,7 +143,7 @@ class HashTable { | |||||
|
|
||||||
| // Returns the number of bytes allocated to the hash table | ||||||
| int64_t byte_size() const { | ||||||
| return _node_byte_size * _nodes_capacity + sizeof(Bucket) * _buckets.size(); | ||||||
| return _node_byte_size * _total_capacity + sizeof(Bucket) * _buckets.size(); | ||||||
| } | ||||||
|
|
||||||
| // Returns the results of the exprs at 'expr_idx' evaluated over the last row | ||||||
|
|
@@ -172,7 +173,7 @@ class HashTable { | |||||
| // stl-like iterator interface. | ||||||
| class Iterator { | ||||||
| public: | ||||||
| Iterator() : _table(NULL), _bucket_idx(-1), _node_idx(-1) {} | ||||||
| Iterator() : _table(NULL), _bucket_idx(-1), _node(nullptr) {} | ||||||
|
|
||||||
| // Iterates to the next element. In the case where the iterator was | ||||||
| // from a Find, this will lazily evaluate that bucket, only returning | ||||||
|
|
@@ -182,54 +183,52 @@ class HashTable { | |||||
|
|
||||||
| // Returns the current row or NULL if at end. | ||||||
| TupleRow* get_row() { | ||||||
| if (_node_idx == -1) { | ||||||
| if (_node == nullptr) { | ||||||
| return NULL; | ||||||
| } | ||||||
| return _table->get_node(_node_idx)->data(); | ||||||
| return _node->data(); | ||||||
| } | ||||||
|
|
||||||
| // Returns Hash | ||||||
| uint32_t get_hash() { return _table->get_node(_node_idx)->_hash; } | ||||||
| uint32_t get_hash() { return _node->_hash; } | ||||||
|
|
||||||
| // Returns if the iterator is at the end | ||||||
| bool has_next() { return _node_idx != -1; } | ||||||
| bool has_next() { return _node != nullptr; } | ||||||
|
|
||||||
| // Returns true if this iterator is at the end, i.e. get_row() cannot be called. | ||||||
| bool at_end() { return _node_idx == -1; } | ||||||
| bool at_end() { return _node == nullptr; } | ||||||
|
|
||||||
| // Sets as matched the node currently pointed by the iterator. The iterator | ||||||
| // cannot be AtEnd(). | ||||||
| void set_matched() { | ||||||
| DCHECK(!at_end()); | ||||||
| Node* node = _table->get_node(_node_idx); | ||||||
| node->matched = true; | ||||||
| _node->matched = true; | ||||||
| } | ||||||
|
|
||||||
| bool matched() { | ||||||
| DCHECK(!at_end()); | ||||||
| Node* node = _table->get_node(_node_idx); | ||||||
| return node->matched; | ||||||
| return _node->matched; | ||||||
| } | ||||||
|
|
||||||
| bool operator==(const Iterator& rhs) { | ||||||
| return _bucket_idx == rhs._bucket_idx && _node_idx == rhs._node_idx; | ||||||
| return _bucket_idx == rhs._bucket_idx && _node == rhs._node; | ||||||
| } | ||||||
|
|
||||||
| bool operator!=(const Iterator& rhs) { | ||||||
| return _bucket_idx != rhs._bucket_idx || _node_idx != rhs._node_idx; | ||||||
| return _bucket_idx != rhs._bucket_idx || _node != rhs._node; | ||||||
| } | ||||||
|
|
||||||
| private: | ||||||
| friend class HashTable; | ||||||
|
|
||||||
| Iterator(HashTable* table, int bucket_idx, int64_t node, uint32_t hash) | ||||||
| : _table(table), _bucket_idx(bucket_idx), _node_idx(node), _scan_hash(hash) {} | ||||||
| Iterator(HashTable* table, int bucket_idx, Node* node, uint32_t hash) | ||||||
| : _table(table), _bucket_idx(bucket_idx), _node(node), _scan_hash(hash) {} | ||||||
|
|
||||||
| HashTable* _table; | ||||||
| // Current bucket idx | ||||||
| int64_t _bucket_idx; | ||||||
| // Current node idx (within current bucket) | ||||||
| int64_t _node_idx; | ||||||
| // Current node (within current bucket) | ||||||
| Node* _node; | ||||||
| // cached hash value for the row passed to find()() | ||||||
| uint32_t _scan_hash; | ||||||
| }; | ||||||
|
|
@@ -241,11 +240,11 @@ class HashTable { | |||||
| // Header portion of a Node. The node data (TupleRow) is right after the | ||||||
| // node memory to maximize cache hits. | ||||||
| struct Node { | ||||||
| int64_t _next_idx; // chain to next node for collisions | ||||||
| uint32_t _hash; // Cache of the hash for _data | ||||||
| Node* _next; // chain to next node for collisions | ||||||
| uint32_t _hash; // Cache of the hash for _data | ||||||
| bool matched; | ||||||
|
|
||||||
| Node() : _next_idx(-1), _hash(-1), matched(false) {} | ||||||
| Node() : _next(nullptr), _hash(-1), matched(false) {} | ||||||
|
|
||||||
| TupleRow* data() { | ||||||
| uint8_t* mem = reinterpret_cast<uint8_t*>(this); | ||||||
|
|
@@ -255,22 +254,14 @@ class HashTable { | |||||
| }; | ||||||
|
|
||||||
| struct Bucket { | ||||||
| int64_t _node_idx; | ||||||
|
|
||||||
| Bucket() { _node_idx = -1; } | ||||||
| Bucket() { _node = nullptr; } | ||||||
| Node* _node; | ||||||
| }; | ||||||
|
|
||||||
| // Returns the next non-empty bucket and updates idx to be the index of that bucket. | ||||||
| // If there are no more buckets, returns NULL and sets idx to -1 | ||||||
| Bucket* next_bucket(int64_t* bucket_idx); | ||||||
|
|
||||||
| // Returns node at idx. Tracking structures do not use pointers since they will | ||||||
| // change as the HashTable grows. | ||||||
| Node* get_node(int64_t idx) { | ||||||
| DCHECK_NE(idx, -1); | ||||||
| return reinterpret_cast<Node*>(_nodes + _node_byte_size * idx); | ||||||
| } | ||||||
|
|
||||||
| // Resize the hash table to 'num_buckets' | ||||||
| void resize_buckets(int64_t num_buckets); | ||||||
|
|
||||||
|
|
@@ -279,12 +270,11 @@ class HashTable { | |||||
|
|
||||||
| // Chains the node at 'node_idx' to 'bucket'. Nodes in a bucket are chained | ||||||
| // as a linked list; this places the new node at the beginning of the list. | ||||||
| void add_to_bucket(Bucket* bucket, int64_t node_idx, Node* node); | ||||||
| void add_to_bucket(Bucket* bucket, Node* node); | ||||||
|
|
||||||
| // Moves a node from one bucket to another. 'previous_node' refers to the | ||||||
| // node (if any) that's chained before this node in from_bucket's linked list. | ||||||
| void move_node(Bucket* from_bucket, Bucket* to_bucket, int64_t node_idx, Node* node, | ||||||
| Node* previous_node); | ||||||
| void move_node(Bucket* from_bucket, Bucket* to_bucket, Node* node, Node* previous_node); | ||||||
|
|
||||||
| // Evaluate the exprs over row and cache the results in '_expr_values_buffer'. | ||||||
| // Returns whether any expr evaluated to NULL | ||||||
|
|
@@ -354,14 +344,16 @@ class HashTable { | |||||
| const int _node_byte_size; | ||||||
| // Number of non-empty buckets. Used to determine when to grow and rehash | ||||||
| int64_t _num_filled_buckets; | ||||||
| // Memory to store node data. This is not allocated from a pool to take advantage | ||||||
| // of realloc. | ||||||
| // TODO: integrate with mem pools | ||||||
| uint8_t* _nodes; | ||||||
| // Buffer to store node data. | ||||||
| uint8_t* _current_nodes; | ||||||
| // number of nodes stored (i.e. size of hash table) | ||||||
| int64_t _num_nodes; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Easier to understand |
||||||
| // max number of nodes that can be stored in '_nodes' before realloc | ||||||
| int64_t _nodes_capacity; | ||||||
| // current nodes buffer capacity | ||||||
| int64_t _current_capacity; | ||||||
| // current used | ||||||
| int64_t _current_used; | ||||||
| // total capacity | ||||||
| int64_t _total_capacity; | ||||||
wangbo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| bool _exceeded_limit; // true if any of _mem_trackers[].limit_exceeded() | ||||||
|
|
||||||
|
|
@@ -395,6 +387,8 @@ class HashTable { | |||||
| // Use bytes instead of bools to be compatible with llvm. This address must | ||||||
| // not change once allocated. | ||||||
| uint8_t* _expr_value_null_bits; | ||||||
| // node buffer list | ||||||
| std::vector<uint8_t*> _alloc_list; | ||||||
| }; | ||||||
|
|
||||||
| } // namespace doris | ||||||
|
|
||||||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.