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  ctx.done = true;
66  }
67  }
68 
69  for (u32 current_id = start_id; current_id < end_id; ++current_id)
70  {
71  const auto& [current_state, current_pass] = ctx.current_passes[current_id];
72 
73  if (auto it = ctx.pass_outcome.find({current_state, current_pass.id}); it != ctx.pass_outcome.end())
74  {
75  // early exit, outcome is already known
76  std::lock_guard guard(ctx.result_mutex);
77  ctx.new_recurring_results.emplace_back(current_state, current_pass.id, it->second);
78  ctx.finished_passes++;
79  m_progress_printer.print_progress((float)ctx.finished_passes / ctx.current_passes.size(),
80  std::to_string(ctx.finished_passes) + "\\" + std::to_string(ctx.current_passes.size()) + " ("
81  + std::to_string(ctx.new_unique_groupings.size()) + " new results)");
82  continue;
83  }
84 
85  // process work
86  auto new_state = current_pass.function(current_state);
87 
88  // aggregate result
89  std::shared_ptr<Grouping> duplicate = nullptr;
90  for (const auto& other : ctx.result.unique_groupings)
91  {
92  if (*new_state == *other)
93  {
94  duplicate = other;
95  break;
96  }
97  }
98  {
99  std::lock_guard guard(ctx.result_mutex);
100  if (duplicate == nullptr)
101  {
102  ctx.new_unique_groupings.emplace_back(current_state, current_pass.id, new_state);
103  }
104  else
105  {
106  ctx.new_recurring_results.emplace_back(current_state, current_pass.id, duplicate);
107  }
108 
109  ctx.finished_passes++;
110  m_progress_printer.print_progress((float)ctx.finished_passes / ctx.current_passes.size(),
111  std::to_string(ctx.finished_passes) + "\\" + std::to_string(ctx.current_passes.size()) + " ("
112  + std::to_string(ctx.new_unique_groupings.size()) + " new results)");
113  }
114  }
115  }
116  }
117 
118  std::vector<std::pair<std::shared_ptr<Grouping>, PassConfiguration>>
119  generate_pass_combinations(Context& ctx, const Configuration& config, const std::shared_ptr<Grouping>& initial_grouping)
120  {
121  // create current layer of pass combinations;
122  std::vector<std::pair<std::shared_ptr<Grouping>, PassConfiguration>> output;
123 
124  if (initial_grouping != nullptr)
125  {
126  for (const auto& pass : pass_collection::get_passes(config, ctx.result.pass_combinations_leading_to_grouping[initial_grouping]))
127  {
128  output.emplace_back(initial_grouping, pass);
129  }
130  }
131  else
132  {
133  for (const auto& state : ctx.result.unique_groupings)
134  {
135  for (const auto& pass : pass_collection::get_passes(config, ctx.result.pass_combinations_leading_to_grouping[state]))
136  {
137  output.emplace_back(state, pass);
138  }
139  }
140  }
141 
142  return output;
143  }
144 
145  } // namespace
146 
147  Result run(const Configuration& config, const std::shared_ptr<Grouping>& initial_grouping)
148  {
149  log_info("dataflow", "starting pipeline with {} threads", config.num_threads);
150 
151  Context ctx;
152  ctx.num_iterations = 0;
153  ctx.phase = 0;
154  ctx.end_reached = false;
155 
156  for (u32 layer = 0; layer < config.pass_layers; layer++)
157  {
158  log_info("dataflow", "start processing layer {}", layer);
159  auto begin_time = std::chrono::high_resolution_clock::now();
160 
161  // get all pass combinations of layer
162  ctx.current_passes = generate_pass_combinations(ctx, config, (layer == 0) ? initial_grouping : nullptr);
163 
164  // preparations
165  ctx.done = false;
166  ctx.pass_counter = 0;
167  ctx.finished_passes = 0;
168 
169  m_progress_printer = ProgressPrinter(30);
170 
171  // spawn threads
172  std::vector<std::thread> workers;
173  for (u32 t = 0; t < config.num_threads - 1; ++t)
174  {
175  workers.emplace_back([&]() { process_pass_configuration(config, ctx); });
176  }
177 
178  process_pass_configuration(config, ctx);
179 
180  // wait for threads to finish
181  for (auto& worker : workers)
182  {
183  worker.join();
184  }
185 
186  m_progress_printer.clear();
187 
188  log_info("dataflow", " finished in {:3.2f}s, processed {} passes, filtering results...", seconds_since(begin_time), ctx.finished_passes, ctx.new_unique_groupings.size());
189 
190  auto all_new_results = ctx.new_recurring_results;
191 
192  begin_time = std::chrono::high_resolution_clock::now();
193 
194  // filter same results of different threads
195  u32 num_unique_filtered = 0;
196  std::vector<bool> do_not_consider(ctx.new_unique_groupings.size(), false);
197  for (u32 i = 0; i < ctx.new_unique_groupings.size(); ++i)
198  {
199  if (do_not_consider[i])
200  {
201  continue;
202  }
203  const auto& [start_state_i, pass_i, new_state_i] = ctx.new_unique_groupings[i];
204  for (u32 j = i + 1; j < ctx.new_unique_groupings.size(); ++j)
205  {
206  if (do_not_consider[j])
207  {
208  continue;
209  }
210  const auto& [start_state_j, pass_j, new_state_j] = ctx.new_unique_groupings[j];
211 
212  // j is a duplicate of i
213  if (*new_state_i == *new_state_j)
214  {
215  do_not_consider[j] = true;
216  all_new_results.emplace_back(start_state_j, pass_j, new_state_i);
217  }
218  }
219  ctx.result.unique_groupings.push_back(new_state_i);
220  all_new_results.push_back(ctx.new_unique_groupings[i]);
221  num_unique_filtered++;
222  }
223  log_info("dataflow", " filtered results in {:3.2f}s, got {} new unique results", seconds_since(begin_time), num_unique_filtered);
224 
225  begin_time = std::chrono::high_resolution_clock::now();
226  ctx.new_recurring_results.clear();
227  ctx.new_unique_groupings.clear();
228 
229  // fill results: compute path by appending pass id to the path of the prev round
230  for (const auto& [start_state, pass, new_state] : all_new_results)
231  {
232  ctx.pass_outcome[{start_state, pass}] = new_state;
233 
234  const auto& start_pass_combinations = ctx.result.pass_combinations_leading_to_grouping[start_state];
235  auto& new_pass_combinations = ctx.result.pass_combinations_leading_to_grouping[new_state];
236  if (start_pass_combinations.empty())
237  {
238  std::vector<pass_id> path{pass};
239  new_pass_combinations.push_back(path);
240  ctx.result.groupings[path] = new_state;
241  }
242  else
243  {
244  std::vector<std::vector<pass_id>> new_paths; // temporary memory to avoid modification while looping
245  new_paths.reserve(start_pass_combinations.size());
246  for (const auto& path : start_pass_combinations)
247  {
248  if (path.size() != layer)
249  {
250  continue;
251  }
252  std::vector<pass_id> new_path(path);
253  new_path.push_back(pass);
254  new_paths.push_back(new_path);
255  ctx.result.groupings[new_path] = new_state;
256  }
257  new_pass_combinations.insert(new_pass_combinations.end(), new_paths.begin(), new_paths.end());
258  }
259  }
260  log_info("dataflow", " total: {} unique states", ctx.result.unique_groupings.size());
261  }
262 
263  return ctx.result;
264  }
265 
266  void clear()
267  {
269  }
270  } // namespace processing
271  } // namespace dataflow
272 } // 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:147
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