File: [bitcoin/src/interfaces/node.cpp] Function: [listWalletDir()] Function: [getWallets()]
Reserving vectors where we already know the size to save on reallocation costs.
File: [bitcoin/src/interfaces/node.cpp] Function: [listWalletDir()] Function: [getWallets()]
Reserving vectors where we already know the size to save on reallocation costs.
File: [bitcoin/src/interfaces/node.cpp]
Function: [listWalletDir()]
Function: [getWallets()]
Reserving vectors where we already know the size to save on reallocation costs.
Do you have any benchmarks that show this is actually faster?
Do you have any benchmarks that show this is actually faster?
I wouldn't expect much performance gain, these are small vectors. I think reserving is mostly a gain when there's a large number of pushes.
How did you come to optimizing these specific functions? Did they show up in a profiling result?
This code isn't performance critical. IMO simple code is preferred.
As long as size is bigger than 1, it is mostly useful(which is most likely the case). For example:
******************[Incase of NO-reserve]******************: size = 1; initial cap = 1. No Re-Allocations needed. Total Cost: 0 Re-Allocation
size = 2; initial cap = 1. so needs 1 Re-Allocation, in this case so becomes (prev_cap * 2): size = 2; initial cap = 2. Total Cost: 1 Re-Allocation
size = 3; initial cap = 1. needs to Re-Allocate in this case so becomes (prev_cap * 2): size = 3; initial cap = 2. needs 1 more Re-Allocation so becomes (prev_cap * 2): size = 3; initial cap = 4. Total Cost: 2 Re-Allocations
size = 10; initial cap = 1. needs Re-Allocation, so becomes (prev_cap * 2): size = 10; initial cap = 2. needs more Re-Allocation so becomes (prev_cap * 2): size = 10; initial cap = 4. needs more Re-Alocation so becomes (prev_cap * 2): size = 10; initial cap = 8. needs more Re-Alocation so becomes (prev_cap * 2): size = 10; initial cap = 16. Total Cost: 4 Re-Allocations
******************[Incase of Reserve]******************: size = 1; initial cap = 1. Reserves once for cap = 1, so no reallocation needed upto size = 1. Total Cost: 1 Re-Allocation
size = 2; initial cap = 2. Reserves once for cap = 2, so no reallocation needed upto size = 2. Total Cost: 1 Re-Allocation
size = 3; initial cap = 3 (or up to 4, compiler specifc). Reserved once for upto(atleast) cap = 3, so no reallocation needed upto size = 3. Total Cost: 1 Re-Allocations
size = 10; initial cap = 10 (or up to 16, compiler specifc). Reserved once for upto(atleast) cap = 10, so no reallocation needed upto size = 10. Total Cost: 1 Re-Allocations
In-addition to memory-allocation-cost there are more over-heads for each re-allocation like these things for example:
Makes a new vector of double size each time. (creation time spent).
Copies each element of the old vector in the new (bigger) sized one. (expensive).
Then destroys the old one.
Moreover, this also guarantees that the iterator will remain valid, because early throw/error incase not enough memory for the task. This can potentially save data corruptions.
Which can all be avoided in this case as we know the size before.
This is pretty standard practice, infact in this file alone I see this applied in function[getNodesStats(NodesStats& stats)] line 98:
stats.reserve(stats_temp.size());
for (auto& node_stats_temp : stats_temp) {
stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats());
}
Agreed it's not critically important, but it is better code practice to reserve if you know the size.
Current code is worst since it calls each function twice.
Sorry, I'm going to close this, there is no agreement to make this change.