1 #include "tree_builder.hh"
2 
3 #include "../cpp-integration/message.hpp"
4 
5 #include "utils/perf_helper.hh"
6 #include "utils/debug.hh"
7 #include "execution.hh"
8 
9 #include "tree/node_tree.hh"
10 #include "name_map.hh"
11 
12 #include <thread>
13 
14 namespace cpprofiler
15 {
16 
operator <<(std::ostream & os,const NodeUID & uid)17 static std::ostream &operator<<(std::ostream &os, const NodeUID &uid)
18 {
19     return os << "{" << uid.nid << ", " << uid.rid << ", " << uid.tid << "}";
20 }
21 
operator <<(std::ostream & os,const NodeStatus & status)22 static std::ostream &operator<<(std::ostream &os, const NodeStatus &status)
23 {
24     switch (status)
25     {
26     case SOLVED:
27         os << "SOLVED";
28         break;
29     case FAILED:
30         os << "FAILED";
31         break;
32     case BRANCH:
33         os << "BRANCH";
34         break;
35     case SKIPPED:
36         os << "SKIPPED";
37         break;
38     }
39     return os;
40 }
41 
42 /// works correctly for node messages only atm
operator <<(std::ostream & os,const Message & msg)43 static std::ostream &operator<<(std::ostream &os, const Message &msg)
44 {
45     os << "nid: " << msg.nodeUID() << ", pid: " << msg.parentUID();
46     os << ", alt: " << msg.alt() << ", kids: " << msg.kids();
47     os << ", " << msg.status();
48     // if (msg.has_label()) os << ", label: " << msg.label();
49     // if (msg.has_nogood()) os << ", nogood: " << msg.nogood();
50     // if (msg.has_info()) os << ", info: " << msg.info();
51     return os;
52 }
53 
TreeBuilder(Execution & ex)54 TreeBuilder::TreeBuilder(Execution &ex) : m_execution(ex)
55 {
56     std::cerr << "  TreeBuilder()\n";
57     startBuilding();
58 }
59 
startBuilding()60 void TreeBuilder::startBuilding()
61 {
62     perfHelper.begin("tree building");
63     print("Builder: start building");
64 }
65 
finishBuilding()66 void TreeBuilder::finishBuilding()
67 {
68     perfHelper.end();
69     print("Builder: done building");
70     emit buildingDone();
71 }
72 
handleNode(Message * node)73 void TreeBuilder::handleNode(Message *node)
74 {
75 
76     std::unique_ptr<Message> node_msg{node};
77     // print("node: {}", *node);
78 
79     const auto n_uid = node->nodeUID();
80     const auto p_uid = node->parentUID();
81 
82     auto &tree = m_execution.tree();
83 
84     tree::NodeID pid = tree::NodeID::NoNode;
85 
86     if (p_uid.nid != -1)
87     {
88         /// should solver data be moved to node tree?
89         pid = m_execution.solver_data().getNodeId({p_uid.nid, p_uid.rid, p_uid.tid});
90     }
91 
92     const auto kids = node->kids();
93     const auto alt = node->alt();
94     const auto status = static_cast<tree::NodeStatus>(node->status());
95     const auto &label = node->has_label() ? node->label() : tree::emptyLabel;
96 
97     NodeID nid;
98 
99     {
100         utils::MutexLocker tree_lock(&tree.treeMutex(), "builder");
101 
102         if (pid == NodeID::NoNode)
103         {
104 
105             if (m_execution.doesRestarts())
106             {
107                 tree.addExtraChild(NodeID{0});
108                 nid = tree.promoteNode(NodeID{0}, restart_count++, kids, status, label);
109             }
110             else
111             {
112                 nid = tree.createRoot(kids);
113             }
114         }
115         else
116         {
117             nid = tree.promoteNode(pid, alt, kids, status, label);
118         }
119     }
120 
121     m_execution.solver_data().setNodeId({n_uid.nid, n_uid.rid, n_uid.tid}, nid);
122 
123     if (node->has_nogood())
124     {
125         const auto nm = m_execution.nameMap();
126 
127         if (nm)
128         {
129             /// Construct a renamed nogood using the name map
130             const auto renamed = m_execution.nameMap()->replaceNames(node->nogood());
131             m_execution.solver_data().setNogood(nid, node->nogood(), renamed);
132         }
133         else
134         {
135             m_execution.solver_data().setNogood(nid, node->nogood());
136         }
137     }
138 
139     if (node->has_info() && !node->info().empty())
140     {
141         m_execution.solver_data().processInfo(nid, node->info());
142     }
143 }
144 
145 } // namespace cpprofiler