From aa23f247d8e09856be5baea620b31bbddadaf550 Mon Sep 17 00:00:00 2001 From: Maria Kozlovtseva <43620101+mamaria-k@users.noreply.github.com> Date: Fri, 9 Jun 2023 19:15:54 +0300 Subject: [PATCH] Fix case with unsorted events (#9) * Fix case with unsorted events --- source/citnames/source/Citnames.cc | 101 +++++++++++++----- test/cases/citnames/output/unsorted_events.sh | 20 ++++ 2 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 test/cases/citnames/output/unsorted_events.sh diff --git a/source/citnames/source/Citnames.cc b/source/citnames/source/Citnames.cc index 8a289d3d..c7587fc9 100644 --- a/source/citnames/source/Citnames.cc +++ b/source/citnames/source/Citnames.cc @@ -28,6 +28,7 @@ #include #include +#include #ifdef HAVE_FMT_STD_H #include @@ -44,6 +45,11 @@ template <> struct fmt::formatter : ostream_formatter {}; namespace { + struct EventEntries { + std::list compile; + std::list link; + }; + std::list to_abspath(const std::list &paths, const fs::path &root) { std::list results; for (const auto &path : paths) { @@ -194,15 +200,49 @@ namespace { }); } - rust::Result transform( - cs::semantic::Build &build, + bool transform_event( + const cs::semantic::Build &build, + const rpc::Event &event, + std::map &pid_entries, + const bool with_link + ) { + const auto get_entries = [](const auto &semantic) -> std::list { + const auto candidate = dynamic_cast(semantic.get()); + return (candidate != nullptr) ? candidate->into_entries() : std::list(); + }; + + const size_t pid = event.started().pid(); + bool is_written = false; + + auto entries_compile = build.recognize(event, cs::semantic::BuildTarget::COMPILER).map>(get_entries).unwrap_or({}); + if (!entries_compile.empty()) { + is_written = true; + std::move(entries_compile.begin(), entries_compile.end(), std::back_inserter(pid_entries[pid].compile)); + } + if (with_link) { + auto entries_link = build.recognize(event, cs::semantic::BuildTarget::LINKER).map>(get_entries).unwrap_or({}); + if (!entries_link.empty()) { + is_written = true; + std::move(entries_link.begin(), entries_link.end(), std::back_inserter(pid_entries[pid].link)); + } + } + + return is_written; + } + + size_t transform( + const cs::semantic::Build &build, const db::EventsDatabaseReader::Ptr& events, std::list &output_compile, std::list &output_link, const bool with_link ) { - std::set all_ppid; - std::set writed_command_pids; + std::set writed_event_pids; + std::map> pid_children; + std::set pids_without_parent; + std::set pids_with_parent; + + std::map pid_entries; for (const rpc::Event &event : *events) { const size_t pid = event.started().pid(); @@ -211,38 +251,43 @@ namespace { continue; } - if (all_ppid.find(pid) != all_ppid.end()) { - return rust::Err(std::runtime_error("Processes in events database are not sorted!")); + pid_children[ppid].insert(pid); + pids_without_parent.erase(pid); + pids_with_parent.insert(pid); + if (pids_with_parent.find(ppid) == pids_with_parent.end()) { + pids_without_parent.insert(ppid); } - all_ppid.insert(ppid); - if (writed_command_pids.find(ppid) != writed_command_pids.end()) { - writed_command_pids.insert(pid); - continue; + if (writed_event_pids.find(ppid) != writed_event_pids.end()) { + writed_event_pids.insert(pid); + } + else if (transform_event(build, event, pid_entries, with_link)) { + writed_event_pids.insert(pid); } + } - const auto get_entries = [](const auto &semantic) -> std::list { - const auto candidate = dynamic_cast(semantic.get()); - return (candidate != nullptr) ? candidate->into_entries() : std::list(); - }; + for (const auto &p : pids_without_parent) { + std::vector pids; + std::copy(pid_children[p].rbegin(), pid_children[p].rend(), std::back_inserter(pids)); - const auto entries_compile = build.recognize(event, cs::semantic::BuildTarget::COMPILER) - .map>(get_entries).unwrap_or({}); - if (!entries_compile.empty()) { - writed_command_pids.insert(pid); - std::copy(entries_compile.begin(), entries_compile.end(), std::back_inserter(output_compile)); - } + while (!pids.empty()) { + const auto cur_pid = pids.back(); + pids.pop_back(); - if (with_link) { - const auto entries_link = build.recognize(event, cs::semantic::BuildTarget::LINKER) - .map>(get_entries).unwrap_or({}); - if (!entries_link.empty()) { - writed_command_pids.insert(pid); - std::copy(entries_link.begin(), entries_link.end(), std::back_inserter(output_link)); + auto entries_iter = pid_entries.find(cur_pid); + // tree before meaningful event + if (entries_iter == pid_entries.end()) { + std::copy(pid_children[cur_pid].rbegin(), pid_children[cur_pid].rend(), std::back_inserter(pids)); + } + // meaningful event, children should not be written + else { + std::move(entries_iter->second.compile.begin(), entries_iter->second.compile.end(), std::back_inserter(output_compile)); + std::move(entries_iter->second.link.begin(), entries_iter->second.link.end(), std::back_inserter(output_link)); } } } - return rust::Ok(output_compile.size() + output_link.size()); + + return output_compile.size() + output_link.size(); } rust::Result complete_entries_from_json( @@ -286,7 +331,7 @@ namespace cs { std::list entries_link; return db::EventsDatabaseReader::from(arguments_.input) - .and_then([this, &entries_compile, &entries_link](const auto &commands) { + .map([this, &entries_compile, &entries_link](const auto &commands) { cs::semantic::Build build(configuration_.compilation); return transform(build, commands, entries_compile, entries_link, arguments_.with_link); }) diff --git a/test/cases/citnames/output/unsorted_events.sh b/test/cases/citnames/output/unsorted_events.sh new file mode 100644 index 00000000..6c41fd15 --- /dev/null +++ b/test/cases/citnames/output/unsorted_events.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +# RUN: cd %T; %{shell} %s %t +# RUN: %{citnames} --verbose --input %t.commands.json --output-compile %t.compilations.json +# RUN: assert_compilation %t.compilations.json count -eq 1 + +cat << EOF > "$1.commands.json" +{"rid":"5208588700335725496","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.573991Z"} +{"rid":"5982815742339840829","started":{"execution":{"executable":"/usr/lib/gcc/x86_64-linux-gnu/11/collect2","arguments":["/usr/lib/gcc/x86_64-linux-gnu/11/collect2"],"working_dir":"example/build","environment":{}},"pid":13896,"ppid":13868},"timestamp":"2023-05-26T11:42:25.580038Z"} +{"rid":"16827070368060185859","started":{"execution":{"executable":"/usr/bin/ld","arguments":["/usr/bin/ld"],"working_dir":"example/build","environment":{}},"pid":13904,"ppid":13896},"timestamp":"2023-05-26T11:42:25.585572Z"} +{"rid":"16827070368060185859","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.638394Z"} +{"rid":"5982815742339840829","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.639796Z"} +{"rid":"11620369640675796770","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.641203Z"} +{"rid":"3208622825367537157","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.642386Z"} +{"rid":"3208622825367537157","started":{"execution":{"executable":"/usr/bin/make","arguments":["make","-f","../Makefile"],"working_dir":"example/build","environment":{}},"pid":13860,"ppid":13847},"timestamp":"2023-05-26T11:42:25.322304Z"} +{"rid":"11620369640675796770","started":{"execution":{"executable":"/usr/bin/g++","arguments":["g++","../main.cpp"],"working_dir":"example/build","environment":{}},"pid":13868,"ppid":13860},"timestamp":"2023-05-26T11:42:25.332432Z"} +{"rid":"1195915605071429231","started":{"execution":{"executable":"/usr/lib/gcc/x86_64-linux-gnu/11/cc1plus","arguments":["/usr/lib/gcc/x86_64-linux-gnu/11/cc1plus"],"working_dir":"example/build","environment":{}},"pid":13876,"ppid":13868},"timestamp":"2023-05-26T11:42:25.345192Z"} +{"rid":"1195915605071429231","terminated":{"status":"0"},"timestamp":"2023-05-26T11:42:25.563234Z"} +{"rid":"5208588700335725496","started":{"execution":{"executable":"/usr/bin/as","arguments":["as"],"working_dir":"example/build","environment":{}},"pid":13888,"ppid":13868},"timestamp":"2023-05-26T11:42:25.568801Z"} +EOF \ No newline at end of file