In my custom physics engine, the biggest bottleneck is a method that gets all bodies from the spatial partitioning (a 2D grid), and returns a collection containing only unique pointers to body.
template<typename T, typename V> bool contains(const T& mContainer, const V& mValue)
{
return std::find(std::begin(mContainer),
std::end(mContainer), mValue) != std::end(mContainer);
}
const vector<Body*>& GridInfo::getBodiesToCheck()
{
bodiesToCheck.clear();
for(auto& query : queries)
for(auto& body : *query)
if(!contains(bodiesToCheck, body)) bodiesToCheck.push_back(body);
return bodiesToCheck;
}
Using a profiler shows that the bottleneck is in the "contains" method.
Obviously, an std::unordered_set
would be the "ideal" solution here. However, it is a lot slower than the current solution. I've also tried google::dense_hash_set
, which is faster than std::unordered_set
, but still slower than the current solution.
const unordered_set<Body*>& GridInfo::getBodiesToCheck()
{
bodiesToCheck.clear();
for(auto& query : queries)
for(auto& body : *query)
/*if(!contains(bodiesToCheck, body))*/ bodiesToCheck.insert(body);
return bodiesToCheck;
}
Why are the "correct" containers slower than a std::vector
?
Is there any way I can speed up this method further?
A std::vector can never be faster than an array, as it has (a pointer to the first element of) an array as one of its data members. But the difference in run-time speed is slim and absent in any non-trivial program. One reason for this myth to persist, are examples that compare raw arrays with mis-used std::vectors.
Even though unordered set is faster in the average case, set is almost always guaranteed to have lower worst-case complexities (for example insert). If you want to access the elements in order, that set sorts them. Different sets can be lexicographically compared using <,<=, >, and >=.
The time complexity of set operations is O(log n) while for unordered_set, it is O(1).
vector is fast and is the best choice 99% of the time. Unless, of course, if correctness is more important than performance, then use unordered_set and switch to vector only if performance problems arise from the use of unordered_set .
There are two possibilities I can think of:
contains
function to find an element in the unordered_set
, instead of using the member function find
.If the number of duplicate bodies isn't that high compared to the others, one option might be to just push all your bodies into the vector and remove the duplicates afterwards. But this will require a std::sort
followed by an erase(std::unique, end)
.
But it may be worth a try, considering that your vector seems to outplay a std::unordered_set
anyway, which doesn't have the same memory locality and trivial access like a std::vector
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With