-
Notifications
You must be signed in to change notification settings - Fork 14
fix: cache ELF file descriptors per file, not per process #528
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
base: main
Are you sure you want to change the base?
Changes from 3 commits
95e24c7
487fc8b
9976f8e
3d17427
ae044ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -237,11 +237,31 @@ DDRes report_module(Dwfl *dwfl, ProcessAddress_t pc, const Dso &dso, | |
| return ddres_warn(DD_WHAT_MODULE); | ||
| } | ||
|
|
||
| UniqueFd fd_holder{::open(filepath.c_str(), O_RDONLY | O_CLOEXEC)}; | ||
| if (!fd_holder) { | ||
| auto cached_elf_file = dso.get_cached_elf_file(); | ||
| if (!cached_elf_file) { | ||
| LG_WRN("[Mod] Missing cached file state for module (%s)", filepath.c_str()); | ||
| return ddres_warn(DD_WHAT_MODULE); | ||
| } | ||
|
|
||
| // Open lazily; the shared cache entry keeps the fd alive as long as some DSO | ||
| // mapping still references this file. | ||
| auto &cached_fd = cached_elf_file->_fd; | ||
| if (!cached_fd) { | ||
| cached_fd = UniqueFd{::open(filepath.c_str(), O_RDONLY | O_CLOEXEC)}; | ||
| LG_DBG("[Mod] Opened and cached fd for %s", filepath.c_str()); | ||
| } | ||
| if (!cached_fd) { | ||
| LG_WRN("[Mod] Couldn't open fd to module (%s)", filepath.c_str()); | ||
| return ddres_warn(DD_WHAT_MODULE); | ||
| } | ||
| // dup with O_CLOEXEC preserved: plain dup() drops close-on-exec, which | ||
| // would leak ELF fds into exec'd children. F_DUPFD_CLOEXEC atomically | ||
| // duplicates and sets FD_CLOEXEC, matching the original open(O_CLOEXEC). | ||
| UniqueFd fd_holder{::fcntl(cached_fd.get(), F_DUPFD_CLOEXEC, 0)}; | ||
|
Collaborator
Author
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. not very useful to add this (cloexec) |
||
| if (!fd_holder) { | ||
| LG_WRN("[Mod] Couldn't dup fd to module (%s)", filepath.c_str()); | ||
| return ddres_warn(DD_WHAT_MODULE); | ||
| } | ||
| LG_DBG("[Mod] Success opening %s, ", filepath.c_str()); | ||
|
|
||
| // Load the file at a matching DSO address | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -284,6 +284,9 @@ DsoHdr::DsoFindRes DsoHdr::dso_find_adjust_same(DsoMap &map, const Dso &dso) { | |
|
|
||
| FileInfoId_t DsoHdr::get_or_insert_file_info(const Dso &dso) { | ||
| if (dso._id != k_file_info_undef) { | ||
|
Collaborator
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. All the cache handling could be done in |
||
| if (dso._id > k_file_info_error && !dso.get_cached_elf_file()) { | ||
| dso.set_cached_elf_file(get_or_create_cached_elf_file(dso._id)); | ||
| } | ||
| // already looked up this dso | ||
| return dso._id; | ||
| } | ||
|
|
@@ -294,6 +297,7 @@ FileInfoId_t DsoHdr::get_or_insert_file_info(const Dso &dso) { | |
| FileInfoId_t DsoHdr::update_id_dd_profiling(const Dso &dso) { | ||
| if (_dd_profiling_file_info != k_file_info_undef) { | ||
| dso._id = _dd_profiling_file_info; | ||
| dso.set_cached_elf_file(get_or_create_cached_elf_file(dso._id)); | ||
| return dso._id; | ||
| } | ||
|
|
||
|
|
@@ -303,6 +307,7 @@ FileInfoId_t DsoHdr::update_id_dd_profiling(const Dso &dso) { | |
| dso._id = _file_info_vector.size(); | ||
| _dd_profiling_file_info = dso._id; | ||
| _file_info_vector.emplace_back(FileInfo(dso._filename, 0, 0), dso._id); | ||
| dso.set_cached_elf_file(get_or_create_cached_elf_file(dso._id)); | ||
| return _dd_profiling_file_info; | ||
| } | ||
| _dd_profiling_file_info = update_id_from_path(dso); | ||
|
|
@@ -314,6 +319,7 @@ FileInfoId_t DsoHdr::update_id_from_path(const Dso &dso) { | |
| FileInfo file_info = find_file_info(dso); | ||
| if (!file_info._inode) { | ||
| dso._id = k_file_info_error; | ||
| dso.set_cached_elf_file(nullptr); | ||
| return dso._id; | ||
| } | ||
|
|
||
|
|
@@ -336,12 +342,14 @@ FileInfoId_t DsoHdr::update_id_from_path(const Dso &dso) { | |
| _file_info_vector[dso._id] = FileInfoValue(std::move(file_info), dso._id); | ||
| } | ||
| } | ||
| dso.set_cached_elf_file(get_or_create_cached_elf_file(dso._id)); | ||
| return dso._id; | ||
| } | ||
|
|
||
| FileInfoId_t DsoHdr::update_id_from_dso(const Dso &dso) { | ||
| if (!has_relevant_path(dso._type)) { | ||
| dso._id = k_file_info_error; // no file associated | ||
| dso.set_cached_elf_file(nullptr); | ||
| return dso._id; | ||
| } | ||
|
|
||
|
|
@@ -352,6 +360,28 @@ FileInfoId_t DsoHdr::update_id_from_dso(const Dso &dso) { | |
| return update_id_from_path(dso); | ||
| } | ||
|
|
||
| std::shared_ptr<CachedElfFile> | ||
| DsoHdr::get_or_create_cached_elf_file(FileInfoId_t file_info_id) { | ||
| auto &weak_entry = _fd_cache[file_info_id]; | ||
| auto cached_elf_file = weak_entry.lock(); | ||
| if (!cached_elf_file) { | ||
| cached_elf_file = std::make_shared<CachedElfFile>(); | ||
| cached_elf_file->_id = file_info_id; | ||
| weak_entry = cached_elf_file; | ||
| } | ||
| return cached_elf_file; | ||
| } | ||
|
|
||
| void DsoHdr::cleanup_expired_fd_cache_entries() { | ||
| for (auto it = _fd_cache.begin(); it != _fd_cache.end();) { | ||
| if (it->second.expired()) { | ||
| it = _fd_cache.erase(it); | ||
| } else { | ||
| ++it; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| bool DsoHdr::maybe_insert_erase_overlap(Dso &&dso, | ||
| PerfClock::time_point timestamp) { | ||
| auto &pid_mapping = _pid_map[dso._pid]; | ||
|
|
@@ -424,7 +454,10 @@ DsoHdr::DsoFindRes DsoHdr::dso_find_or_backpopulate(pid_t pid, | |
| return dso_find_or_backpopulate(pid_mapping, pid, addr); | ||
| } | ||
|
|
||
| void DsoHdr::pid_free(int pid) { _pid_map.erase(pid); } | ||
| void DsoHdr::pid_free(int pid) { | ||
| _pid_map.erase(pid); | ||
| cleanup_expired_fd_cache_entries(); | ||
| } | ||
|
|
||
| bool DsoHdr::pid_backpopulate(pid_t pid, int &nb_elts_added) { | ||
| return pid_backpopulate(_pid_map[pid], pid, nb_elts_added); | ||
|
|
@@ -566,6 +599,17 @@ int DsoHdr::get_nb_dso() const { | |
| return total_nb_elts; | ||
| } | ||
|
|
||
| size_t DsoHdr::get_fd_cache_size() const { | ||
| size_t nb_open_fds = 0; | ||
| for (const auto &[_, weak_cached_elf_file] : _fd_cache) { | ||
| if (auto cached_elf_file = weak_cached_elf_file.lock(); | ||
| cached_elf_file && cached_elf_file->_fd) { | ||
| ++nb_open_fds; | ||
| } | ||
| } | ||
| return nb_open_fds; | ||
| } | ||
|
|
||
| void DsoHdr::reset_backpopulate_state(int reset_threshold) { | ||
| for (auto &[_, pid_mapping] : _pid_map) { | ||
| auto &backpopulate_state = pid_mapping._backpopulate_state; | ||
|
|
@@ -632,8 +676,9 @@ int DsoHdr::clear_unvisited(const std::unordered_set<pid_t> &visited_pids) { | |
| } | ||
| } | ||
| for (const auto &pid : pids_to_clear) { | ||
| _pid_map.erase(pid); | ||
| pid_free(pid); | ||
| } | ||
|
|
||
| return pids_to_clear.size(); | ||
| } | ||
| } // namespace ddprof | ||
Uh oh!
There was an error while loading. Please reload this page.