This is an archive of the discontinued LLVM Phabricator instance.

[lldb][NFCI] Remove n^2 loops and simplify iterator usage
ClosedPublic

Authored by fdeazeve on May 9 2023, 12:02 PM.

Details

Summary

The code inside Broadcaster makes usage of iterators using olden C++ coding
style. Hidden in this old style is a couple of N^2 loops: we iterate over a map
(sequentially), removing the first element that matches some predicate. The
search is _always_ done from the start of the map, which implies that, if the
map has N elements and if all matches happen on the second half of the map, then
we visit the first N/2 elements exactly N/2 * N/2 times.

Ideally some of the code here would benefit from std::maps own "erase_if", but
this is only available with C++20:
https://en.cppreference.com/w/cpp/container/map/erase_if

We spent quite some time trying to make these loops more elegant, but it is
surprisingly tricky to do so.

Diff Detail

Event Timeline

fdeazeve created this revision.May 9 2023, 12:02 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 9 2023, 12:02 PM
fdeazeve requested review of this revision.May 9 2023, 12:02 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 9 2023, 12:02 PM
fdeazeve updated this revision to Diff 520786.May 9 2023, 12:05 PM

Update commit message

fdeazeve edited the summary of this revision. (Show Details)May 9 2023, 12:07 PM
fdeazeve added reviewers: Restricted Project, JDevlieghere, jingham, mib, bulbazord.

Heavily inspired by @bulbazord's D150168

fdeazeve added inline comments.May 9 2023, 12:16 PM
lldb/source/Utility/Broadcaster.cpp
382

Oh, this should be == end

436

this should be == end

mib added inline comments.May 9 2023, 12:17 PM
lldb/source/Utility/Broadcaster.cpp
430–437
434–439

Would be nice to add a // TODO: use 'std::map::erase_if' when moving to c++20 comment

455–461

ditto

fdeazeve added inline comments.May 9 2023, 12:19 PM
lldb/source/Utility/Broadcaster.cpp
430–437

listener is a raw pointer, we shouldn't capture those by reference

mib added inline comments.May 9 2023, 12:20 PM
lldb/source/Utility/Broadcaster.cpp
430–437

I didn't pay attention, I thought it was a local variable. Good point!

mib accepted this revision.May 9 2023, 12:21 PM

LGTM!

This revision is now accepted and ready to land.May 9 2023, 12:21 PM
bulbazord accepted this revision.May 9 2023, 12:25 PM

I like this. :)

lldb/source/Utility/Broadcaster.cpp
392

I don't think you need to actually capture the iterator here? std::map::erase doesn't invalidate existing iterators* (so begin and end are fine) and we redefine iter at the beginning of this loop.

*:https://en.cppreference.com/w/cpp/container/map/erase

jingham accepted this revision.May 9 2023, 12:37 PM

You are inconsistent in a couple of places about whether you re-look up m_event_map.end or use the version you captured in a variable, which is a little confusing. Other than that this looks equivalent

lldb/source/Utility/Broadcaster.cpp
381

Why do you re-look-up m_event_map.end() instead of using the end variable you defined in the for initializer?

std::map::erase says it only invalidates iterators to the erased element, so you should be fine to use end here (and since you do exactly that in the previous line) it should be good here too.

436

Again here, you don't trust the "end" variable, but then in the next function you do reuse end_iter.

fdeazeve updated this revision to Diff 520796.May 9 2023, 12:55 PM
fdeazeve edited the summary of this revision. (Show Details)

Address review comments

lldb/source/Utility/Broadcaster.cpp
381

Yup, this was just a mistake on my part. Will address in the next version

392

Argh, the variable begin shouldn't exist, it should all be iter, otherwise we're not addressing the quadratic behaviour.