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
Move map management to BpfBytecode
#2988
Conversation
5118ac7
to
03e9287
Compare
03e9287
to
f5e423e
Compare
For some reason, there are random failures of the |
Unfortunately, I'm not able to reproduce the issue locally (even when using Nix). |
f5e423e
to
6b3a8b8
Compare
What kinds of failures were they? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good to me.
There do seem to be a lot of map lookups going on throughout the whole process, which might be slowing us down more than necessary.
e.g. in the output path (where performance counts), we have a multi-step process to obtain a BpfMap object:
- Ringbuffer ->
print->mapid
resources.maps_by_id[mapid]
->map_name
bytecode.getMap(map_name)
->BpfMap
Also resources.map_key
and resources.map_type
being two separate map lookups.
IIRC there was no stack printed (just empty output). |
6b3a8b8
to
bc82b0d
Compare
That's a good point, although I'm wondering if we can really avoid that.
This is necessary b/c mapid is stored in codegen. I don't see a way to avoid this.
Probably the most efficient would be to have mapid ->
That's a good point. We could probably aggregate them in some structure like |
bc82b0d
to
8bb915b
Compare
Thanks for the review @ajor! I implemented all of the comments, noticeable changes in the new version are:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
Just spotted few extra copies we can eliminate. I'm extra suspicious whenever I see auto x =
because it's easy to hide these expensive copies (not saying that I don't code like this myself!)
8bb915b
to
5d2de2c
Compare
Thanks, those are great catches! I try to avoid Anyways, I'd like to wait for @danobi's review before merging this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only looked at first 3 commits. might get more time this weekend to finish
5d2de2c
to
4ba6286
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
few comments, but great cleanup!
src/aot/CMakeLists.txt
Outdated
@@ -1,4 +1,4 @@ | |||
add_library(aot aot.cpp) | |||
add_library(aot aot.cpp ${CMAKE_SOURCE_DIR}/src/required_resources.cpp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is a bit unfortunate. I feel like cmakelists.txt should try not to reach up to parent or sibling dirs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like it either. But I couldn't come with any other solution, besides adding the dummy constructor (see the other thread).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should required_resources.cpp live in the aot directory, since that's where it's used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly but we wouldn't have required_resources.cpp
next to required_resources.h
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of moving the header too, but I suppose it's used in more than just AOT so that doesn't make sense.
How about creating a new CMake library target just for required_resources? Then aot can link against that - would it solve the unused symbol issues?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - separate target is probably cleanest solution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, done.
ab31c85
to
78c3369
Compare
78c3369
to
a5f67f5
Compare
bpf_object is libbpf's structure for representing a collection of BPF programs, maps, etc. Typically, it's parsed from a single ELF file. Since we now emit BTF information on maps into the produced ELF, we can let libbpf parse it for us so that don't have to store it elsewhere (currently in IMap/Map/FakeMap/MapManager). This is another step towards libbpf-based loading and attachment of programs. Eventually, we'd like to get into the state when BpfBytecode only contains bpf_object and everything is managed by libbpf.
The basic map information (map type, max entries, key and value size) is now stored inside the generated ELF in the BTF form. Thanks to that, libbpf is able to parse that information and store it inside bpf_object. We can retrieve the information and use it to create BPF maps from BpfBytecode (instead of from RequiredResources). This has several advantages: 1. We only need to store minimal map information (name and fd). This is done in BpfBytecode (where it logically belongs) using a new BpfMap class, instead of MapManager. We will eventually be able to drop MapManager. 2. Once we let libbpf auto-create maps for us, we will need minimal code adjustments (we'll just remove the manual map creation). The new BpfMap class logically replaces the previous Imap/Map classes. Since map information is used in many places, we do not remove MapManager and Map/Imap at once (the commit would be just too large). To allow removing it incrementally, we (1) copy the map fds from BpfBytecode maps to MapManager maps and (2) store names for builtin maps in MapManager. Once all usages of MapManager maps are gone, we will drop this code. The only map manipulation code that is migrated at once is filling of the printf data map. This is because it is done in the same method as the data map is created (RequiredResources::prepareFormatStringDataMap) and therefore it cannot be kept while moving the map creation code.
All manipulations of internal maps now use maps from BpfBytecode instead of MapManager. This also allows to move the MapManager::Type enum for internal maps to a new MapType enum located in bpfmap.h. This also removes some code from RequiredResources and MapManager which was using (now missing) MapManager::Type. Codegen tests for internal maps (stacks) now use BpfBytecode maps rather than MapManager maps.
Currently, map info (key type, value type, hist, and lhist args) is stored in 4 separate std::maps in RequiredResources. In future, we plan to add more info and will possibly need to access multiple items from a single place (typically key and value type). Therefore, it is much more efficient to aggregate everything in a single map (indexed by map name) so that we always need to do just one lookup.
Async map actions (print, clear, zero) now use maps from BpfBytecode instead of MapManager. This comes with two significant problems: - we do use map ids to identify maps in codegen anymore but we still need them for async actions, - some information used by async actions (e.g. key/value types) is not in BpfBytecode maps (instances of BpfMap). Since we want to keep the generated BPF programs decoupled from runtime as much as possible, we store the above information in RequiredResources since those are accessible by async actions. Part of the information is already there and this commit adds map id to MapInfo. In addition, we create a new mapping id->BpfMap in BpfBytecode to allow for efficient lookup of maps by their id. This is then used from async actions. Thanks to the chosen approach, instances of BpfMap can be fully populated by parsing the BPF program ELF and all other information is retrieved from RequiredResources. This also removes the last usages of MapManager and *Map classes so they will be removed in the following commit.
Now that map management has been completely moved to BpfBytecode, using BpfMap objects, we can remove the legacy MapManager and all of the related classes: IMap, Map, FakeMap. One problem that popped up is that now, required_resources.cpp only contains methods used by AOT. To avoid linker errors, we create a new target required_resources which is now linked from libaot only. Once we add methods required by libruntime to reqired_resources.cpp, we'll simply link against that target.
a5f67f5
to
c18f9d8
Compare
Rebased. Going to merge this to avoid more conflicts with open PRs. |
The current map management using
MapManager
/IMap
/Map
/FakeMap
is quite difficult to read in the code as map settings are scattered across multiple files. This PR attempts to unify everything inBpfBytecode
, where it logically belongs.Maps are stored by their name (map ids are not used anymore) and represented using a new
BpfMap
class. The class containsstruct bpf_map
which is libbpf map representation containing basic map information (map type, max entries, key and value size) which libbpf is able to parse from BTF stored in the generated ELF. In addition,BpfMap
stores map fd. Once we let libbpf auto-create maps for us in future, we will be able to drop manual map creation and fd will also be stored instruct bpf_map
. Logically, the newBpfMap
class replaces the previousImap
/Map
classes.The PR migrates all map usages to the new map management. The migration had to deal with two kinds of maps:
print
,clear
, andzero
) which came with two problems: (1) async actions need map ids which were dropped and (2) some information needed (e.g. key/value type) is not stored inBpfMap
. Since I wanted to keep the generated BPF programs decoupled from runtime as much as possible, I decided to store the above information inRequiredResources
which are accessible by async actions. Part of the information was already there and the PR adds map name<->id mappings (for maps used inside async actions).Finally,
MapManager
,IMap
,Map
, andFakeMap
are dropped.See individual commit messages for more details.
Note: this is the last part of #2911. It's quite big but unfortunately, I wasn't able to split it into smaller parts as it wouldn't make much sense to me. If you still prefer to post it per-commit, let me know.
Checklist
man/adoc/bpftrace.adoc
and if needed indocs/reference_guide.md
CHANGELOG.md