HAL
processing.cpp
Go to the documentation of this file.
2 
11 #include "hal_core/netlist/gate.h"
13 #include "hal_core/utilities/log.h"
14 
15 #include <iomanip>
16 #include <iostream>
17 #include <thread>
18 
19 namespace hal
20 {
21  namespace dataflow
22  {
23  namespace processing
24  {
25  namespace
26  {
27  ProgressPrinter m_progress_printer;
28 
29  void process_pass_configuration(const Configuration& config, Context& ctx)
30  {
31  u32 num_passes = ctx.current_passes.size();
32 
33  while (true)
34  {
35  u32 start_id;
36  u32 end_id;
37 
38  // fetch next work package
39  {
40  std::lock_guard<std::mutex> guard(ctx.progress_mutex);
41 
42  if (ctx.done)
43  {
44  break;
45  }
46 
47  // adaptive workload:
48  // every thread gets between 1 and 20 passes, depending on the number of remaining passes
49  // this improves cpu utilization and reduces number of mutex locks
50  start_id = ctx.pass_counter;
51  u32 remaining_passes = num_passes - start_id;
52 
53  u32 work = 20;
54 
55  if (remaining_passes < config.num_threads * work / 2)
56  {
57  work = std::max(1u, remaining_passes / config.num_threads);
58  }
59 
60  end_id = std::min(start_id + work, (u32)num_passes);
61 
62  ctx.pass_counter = end_id;
63  if (ctx.pass_counter >= num_passes)
64  {
65  std::lock_guard guard(ctx.result_mutex);
66  ctx.done = true;
67  }
68  }
69 
70  for (u32 current_id = start_id; current_id < end_id; ++current_id)
71  {
72  const auto& [current_state, current_pass] = ctx.current_passes[current_id];
73 
74  if (auto it = ctx.pass_outcome.find({current_state, current_pass.id}); it != ctx.pass_outcome.end())
75  {
76  {
77  // early exit, outcome is already known
78  std::lock_guard guard(ctx.result_mutex);
79  ctx.new_recurring_results.emplace_back(current_state, current_pass.id, it->second);
80  ctx.finished_passes++;
81  m_progress_printer.print_progress_to_stderr((float)ctx.finished_passes / ctx.current_passes.size(),
82  std::to_string(ctx.finished_passes) + "\\" + std::to_string(ctx.current_passes.size()) + " ("
83  + std::to_string(ctx.new_unique_groupings.size()) + " new results)");
84  }
85  m_progress_printer.print_progress_to_gui();
86  continue;
87  }
88 
89  // process work
90  auto new_state = current_pass.function(current_state);
91 
92  // aggregate result
93  std::shared_ptr<Grouping> duplicate = nullptr;
94  for (const auto& other : ctx.result.unique_groupings)
95  {
96  if (*new_state == *other)
97  {
98  duplicate = other;
99  break;
100  }
101  }
102  {
103  std::lock_guard guard(ctx.result_mutex);
104  if (duplicate == nullptr)
105  {
106  ctx.new_unique_groupings.emplace_back(current_state, current_pass.id, new_state);
107  }
108  else
109  {
110  ctx.new_recurring_results.emplace_back(current_state, current_pass.id, duplicate);
111  }
112 
113  ctx.finished_passes++;
114  m_progress_printer.print_progress_to_stderr((float)ctx.finished_passes / ctx.current_passes.size(),
115  std::to_string(ctx.finished_passes) + "\\" + std::to_string(ctx.current_passes.size()) + " ("
116  + std::to_string(ctx.new_unique_groupings.size()) + " new results)");
117  }
118  m_progress_printer.print_progress_to_gui();
119  }
120  }
121  }
122 
123  std::vector<std::pair<std::shared_ptr<Grouping>, PassConfiguration>>
124  generate_pass_combinations(Context& ctx, const Configuration& config, const std::shared_ptr<Grouping>& initial_grouping)
125  {
126  // create current layer of pass combinations;
127  std::vector<std::pair<std::shared_ptr<Grouping>, PassConfiguration>> output;
128 
129  if (initial_grouping != nullptr)
130  {
131  for (const auto& pass : pass_collection::get_passes(config, ctx.result.pass_combinations_leading_to_grouping[initial_grouping]))
132  {
133  output.emplace_back(initial_grouping, pass);
134  }
135  }
136  else
137  {
138  for (const auto& state : ctx.result.unique_groupings)
139  {
140  for (const auto& pass : pass_collection::get_passes(config, ctx.result.pass_combinations_leading_to_grouping[state]))
141  {
142  output.emplace_back(state, pass);
143  }
144  }
145  }
146 
147  return output;
148  }
149 
150  } // namespace
151 
152  Result run(const Configuration& config, const std::shared_ptr<Grouping>& initial_grouping)
153  {
154  log_info("dataflow", "starting pipeline with {} threads", config.num_threads);
155 
156  Context ctx;
157  ctx.num_iterations = 0;
158  ctx.phase = 0;
159  ctx.end_reached = false;
160 
161  for (u32 layer = 0; layer < config.pass_layers; layer++)
162  {
163  log_info("dataflow", "start processing layer {}", layer);
164  auto begin_time = std::chrono::high_resolution_clock::now();
165 
166  // get all pass combinations of layer
167  ctx.current_passes = generate_pass_combinations(ctx, config, (layer == 0) ? initial_grouping : nullptr);
168 
169  // preparations
170  ctx.done = false;
171  ctx.pass_counter = 0;
172  ctx.finished_passes = 0;
173 
174  m_progress_printer = ProgressPrinter(30);
175 
176  // spawn threads
177  std::vector<std::thread> workers;
178  for (u32 t = 0; t < config.num_threads - 1; ++t)
179  {
180  workers.emplace_back([&]() { process_pass_configuration(config, ctx); });
181  }
182 
183  process_pass_configuration(config, ctx);
184 
185  // wait for threads to finish
186  for (auto& worker : workers)
187  {
188  worker.join();
189  }
190 
191  m_progress_printer.clear();
192 
193  log_info("dataflow", " finished in {:3.2f}s, processed {} passes, filtering results...", seconds_since(begin_time), ctx.finished_passes, ctx.new_unique_groupings.size());
194 
195  auto all_new_results = ctx.new_recurring_results;
196 
197  begin_time = std::chrono::high_resolution_clock::now();
198 
199  // filter same results of different threads
200  u32 num_unique_filtered = 0;
201  std::vector<bool> do_not_consider(ctx.new_unique_groupings.size(), false);
202  for (u32 i = 0; i < ctx.new_unique_groupings.size(); ++i)
203  {
204  if (do_not_consider[i])
205  {
206  continue;
207  }
208  const auto& [start_state_i, pass_i, new_state_i] = ctx.new_unique_groupings[i];
209  for (u32 j = i + 1; j < ctx.new_unique_groupings.size(); ++j)
210  {
211  if (do_not_consider[j])
212  {
213  continue;
214  }
215  const auto& [start_state_j, pass_j, new_state_j] = ctx.new_unique_groupings[j];
216 
217  // j is a duplicate of i
218  if (*new_state_i == *new_state_j)
219  {
220  do_not_consider[j] = true;
221  all_new_results.emplace_back(start_state_j, pass_j, new_state_i);
222  }
223  }
224  ctx.result.unique_groupings.push_back(new_state_i);
225  all_new_results.push_back(ctx.new_unique_groupings[i]);
226  num_unique_filtered++;
227  }
228  log_info("dataflow", " filtered results in {:3.2f}s, got {} new unique results", seconds_since(begin_time), num_unique_filtered);
229 
230  begin_time = std::chrono::high_resolution_clock::now();
231  ctx.new_recurring_results.clear();
232  ctx.new_unique_groupings.clear();
233 
234  // fill results: compute path by appending pass id to the path of the prev round
235  for (const auto& [start_state, pass, new_state] : all_new_results)
236  {
237  ctx.pass_outcome[{start_state, pass}] = new_state;
238 
239  const auto& start_pass_combinations = ctx.result.pass_combinations_leading_to_grouping[start_state];
240  auto& new_pass_combinations = ctx.result.pass_combinations_leading_to_grouping[new_state];
241  if (start_pass_combinations.empty())
242  {
243  std::vector<pass_id> path{pass};
244  new_pass_combinations.push_back(path);
245  ctx.result.groupings[path] = new_state;
246  }
247  else
248  {
249  std::vector<std::vector<pass_id>> new_paths; // temporary memory to avoid modification while looping
250  new_paths.reserve(start_pass_combinations.size());
251  for (const auto& path : start_pass_combinations)
252  {
253  if (path.size() != layer)
254  {
255  continue;
256  }
257  std::vector<pass_id> new_path(path);
258  new_path.push_back(pass);
259  new_paths.push_back(new_path);
260  ctx.result.groupings[new_path] = new_state;
261  }
262  new_pass_combinations.insert(new_pass_combinations.end(), new_paths.begin(), new_paths.end());
263  }
264  }
265  log_info("dataflow", " total: {} unique states", ctx.result.unique_groupings.size());
266  }
267 
268  return ctx.result;
269  }
270 
271  void clear()
272  {
274  }
275  } // namespace processing
276  } // namespace dataflow
277 } // namespace hal
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the work(an example is provided in the Appendix below). "Derivative Works" shall mean any work
#define log_info(channel,...)
Definition: log.h:70
std::vector< PassConfiguration > get_passes(const Configuration &config, const std::vector< std::vector< pass_id >> &previous_passes)
processing::Result run(const processing::Configuration &config, const std::shared_ptr< Grouping > &initial_grouping)
Definition: processing.cpp:152
quint32 u32
This file contains the struct that holds all information on the netlist abstraction used for dataflow...
This file contains the class that holds all information of a dataflow analysis grouping.
std::vector< std::pair< std::shared_ptr< Grouping >, PassConfiguration > > current_passes
Definition: context.h:60
std::vector< std::tuple< std::shared_ptr< Grouping >, pass_id, std::shared_ptr< Grouping > > > new_recurring_results
Definition: context.h:63
std::map< std::pair< std::shared_ptr< Grouping >, pass_id >, std::shared_ptr< Grouping > > pass_outcome
Definition: context.h:61
std::vector< std::tuple< std::shared_ptr< Grouping >, pass_id, std::shared_ptr< Grouping > > > new_unique_groupings
Definition: context.h:62
processing::Result result
Definition: context.h:71
std::map< std::shared_ptr< Grouping >, std::vector< std::vector< pass_id > > > pass_combinations_leading_to_grouping
Definition: result.h:43
std::map< std::vector< pass_id >, std::shared_ptr< Grouping > > groupings
Definition: result.h:44
std::vector< std::shared_ptr< Grouping > > unique_groupings
Definition: result.h:42
#define seconds_since(X)
Definition: timing_utils.h:38