2828
2929#include < filesystem>
3030#include < set>
31+ #include < map>
3132
3233#ifdef HAVE_FMT_STD_H
3334#include < fmt/std.h>
@@ -44,6 +45,11 @@ template <> struct fmt::formatter<cs::Configuration> : ostream_formatter {};
4445
4546namespace {
4647
48+ struct EventEntries {
49+ std::list<cs::Entry> compile;
50+ std::list<cs::Entry> link;
51+ };
52+
4753 std::list<fs::path> to_abspath (const std::list<fs::path> &paths, const fs::path &root) {
4854 std::list<fs::path> results;
4955 for (const auto &path : paths) {
@@ -194,15 +200,49 @@ namespace {
194200 });
195201 }
196202
197- rust::Result<size_t > transform (
198- cs::semantic::Build &build,
203+ bool transform_event (
204+ const cs::semantic::Build &build,
205+ const rpc::Event &event,
206+ std::map<size_t , EventEntries> &pid_entries,
207+ const bool with_link
208+ ) {
209+ const auto get_entries = [](const auto &semantic) -> std::list<cs::Entry> {
210+ const auto candidate = dynamic_cast <const cs::semantic::CompilerCall *>(semantic.get ());
211+ return (candidate != nullptr ) ? candidate->into_entries () : std::list<cs::Entry>();
212+ };
213+
214+ const size_t pid = event.started ().pid ();
215+ bool is_written = false ;
216+
217+ auto entries_compile = build.recognize (event, cs::semantic::BuildTarget::COMPILER).map <std::list<cs::Entry>>(get_entries).unwrap_or ({});
218+ if (!entries_compile.empty ()) {
219+ is_written = true ;
220+ std::move (entries_compile.begin (), entries_compile.end (), std::back_inserter (pid_entries[pid].compile ));
221+ }
222+ if (with_link) {
223+ auto entries_link = build.recognize (event, cs::semantic::BuildTarget::LINKER).map <std::list<cs::Entry>>(get_entries).unwrap_or ({});
224+ if (!entries_link.empty ()) {
225+ is_written = true ;
226+ std::move (entries_link.begin (), entries_link.end (), std::back_inserter (pid_entries[pid].link ));
227+ }
228+ }
229+
230+ return is_written;
231+ }
232+
233+ size_t transform (
234+ const cs::semantic::Build &build,
199235 const db::EventsDatabaseReader::Ptr& events,
200236 std::list<cs::Entry> &output_compile,
201237 std::list<cs::Entry> &output_link,
202238 const bool with_link
203239 ) {
204- std::set<size_t > all_ppid;
205- std::set<size_t > writed_command_pids;
240+ std::set<size_t > writed_event_pids;
241+ std::map<size_t , std::set<size_t >> pid_children;
242+ std::set<size_t > pids_without_parent;
243+ std::set<size_t > pids_with_parent;
244+
245+ std::map<size_t , EventEntries> pid_entries;
206246
207247 for (const rpc::Event &event : *events) {
208248 const size_t pid = event.started ().pid ();
@@ -211,38 +251,43 @@ namespace {
211251 continue ;
212252 }
213253
214- if (all_ppid.find (pid) != all_ppid.end ()) {
215- return rust::Err (std::runtime_error (" Processes in events database are not sorted!" ));
254+ pid_children[ppid].insert (pid);
255+ pids_without_parent.erase (pid);
256+ pids_with_parent.insert (pid);
257+ if (pids_with_parent.find (ppid) == pids_with_parent.end ()) {
258+ pids_without_parent.insert (ppid);
216259 }
217- all_ppid.insert (ppid);
218260
219- if (writed_command_pids.find (ppid) != writed_command_pids.end ()) {
220- writed_command_pids.insert (pid);
221- continue ;
261+ if (writed_event_pids.find (ppid) != writed_event_pids.end ()) {
262+ writed_event_pids.insert (pid);
263+ }
264+ else if (transform_event (build, event, pid_entries, with_link)) {
265+ writed_event_pids.insert (pid);
222266 }
267+ }
223268
224- const auto get_entries = [](const auto &semantic) -> std::list<cs::Entry> {
225- const auto candidate = dynamic_cast <const cs::semantic::CompilerCall *>(semantic.get ());
226- return (candidate != nullptr ) ? candidate->into_entries () : std::list<cs::Entry>();
227- };
269+ for (const auto &p : pids_without_parent) {
270+ std::vector<size_t > pids;
271+ std::copy (pid_children[p].rbegin (), pid_children[p].rend (), std::back_inserter (pids));
228272
229- const auto entries_compile = build.recognize (event, cs::semantic::BuildTarget::COMPILER)
230- .map <std::list<cs::Entry>>(get_entries).unwrap_or ({});
231- if (!entries_compile.empty ()) {
232- writed_command_pids.insert (pid);
233- std::copy (entries_compile.begin (), entries_compile.end (), std::back_inserter (output_compile));
234- }
273+ while (!pids.empty ()) {
274+ const auto cur_pid = pids.back ();
275+ pids.pop_back ();
235276
236- if (with_link) {
237- const auto entries_link = build.recognize (event, cs::semantic::BuildTarget::LINKER)
238- .map <std::list<cs::Entry>>(get_entries).unwrap_or ({});
239- if (!entries_link.empty ()) {
240- writed_command_pids.insert (pid);
241- std::copy (entries_link.begin (), entries_link.end (), std::back_inserter (output_link));
277+ auto entries_iter = pid_entries.find (cur_pid);
278+ // tree before meaningful event
279+ if (entries_iter == pid_entries.end ()) {
280+ std::copy (pid_children[cur_pid].rbegin (), pid_children[cur_pid].rend (), std::back_inserter (pids));
281+ }
282+ // meaningful event, children should not be written
283+ else {
284+ std::move (entries_iter->second .compile .begin (), entries_iter->second .compile .end (), std::back_inserter (output_compile));
285+ std::move (entries_iter->second .link .begin (), entries_iter->second .link .end (), std::back_inserter (output_link));
242286 }
243287 }
244288 }
245- return rust::Ok (output_compile.size () + output_link.size ());
289+
290+ return output_compile.size () + output_link.size ();
246291 }
247292
248293 rust::Result<size_t > complete_entries_from_json (
@@ -286,7 +331,7 @@ namespace cs {
286331 std::list<cs::Entry> entries_link;
287332
288333 return db::EventsDatabaseReader::from (arguments_.input )
289- .and_then <size_t >([this , &entries_compile, &entries_link](const auto &commands) {
334+ .map <size_t >([this , &entries_compile, &entries_link](const auto &commands) {
290335 cs::semantic::Build build (configuration_.compilation );
291336 return transform (build, commands, entries_compile, entries_link, arguments_.with_link );
292337 })
0 commit comments