173 ExecutePass(
const ExecutionPolicy& policy_ = ExecutionPolicy::kSeq)
176 if constexpr (std::is_base_of<TetMesh, AppMesh>::value) {
179 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
180 std::vector<Tuple> ret;
181 if (m.collapse_edge(t, ret))
187 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
188 std::vector<Tuple> ret;
189 if (m.swap_edge(t, ret))
195 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
196 std::vector<Tuple> ret;
197 if (m.swap_edge_44(t, ret))
203 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
204 std::vector<Tuple> ret;
205 if (m.swap_edge_56(t, ret))
211 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
212 std::vector<Tuple> ret;
213 if (m.split_edge(t, ret))
219 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
220 std::vector<Tuple> ret;
221 if (m.swap_face(t, ret))
227 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
228 if (m.smooth_vertex(t))
229 return std::vector<Tuple>{};
234 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
235 std::vector<Tuple> ret;
236 if (m.split_face(t, ret))
241 {
"tet_split", [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
242 std::vector<Tuple> ret;
243 if (m.split_tet(t, ret))
249 if constexpr (std::is_base_of<TriMesh, AppMesh>::value) {
252 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
253 std::vector<Tuple> ret;
254 if (m.collapse_edge(t, ret))
260 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
261 std::vector<Tuple> ret;
262 if (m.swap_edge(t, ret))
268 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
269 std::vector<Tuple> ret;
270 if (m.split_edge(t, ret))
276 [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
277 if (m.smooth_vertex(t))
278 return std::vector<Tuple>{};
282 {
"face_split", [](AppMesh& m,
const Tuple& t) -> std::optional<std::vector<Tuple>> {
283 std::vector<Tuple> ret;
284 if (m.split_face(t, ret))
324 bool operator()(AppMesh& m,
const std::vector<std::pair<Op, Tuple>>& operation_tuples)
334 using OpId = uint32_t;
335 using Elem = std::tuple<double, OpId, Tuple, size_t>;
344 std::vector<const Op*> op_name;
345 std::vector<std::function<std::optional<std::vector<Tuple>>(AppMesh&,
const Tuple&)>*>
347 std::map<Op, OpId> op_id;
351 op_id.emplace(kv.first, OpId(op_name.size()));
352 op_name.push_back(&kv.first);
353 op_fn.push_back(&kv.second);
358 const auto id_of = [&op_id](
const Op& name) {
359 const auto it = op_id.find(name);
360 if (it == op_id.end()) {
361 log_and_throw_error(
"No operation registered under the name '{}'.", name);
366 std::atomic<bool> stop(
false);
374 const bool track_live_success =
376 std::atomic<size_t> live_success(0);
378 std::vector<LocalQueue> queues(num_threads);
379 SharedQueue final_queue;
386 std::atomic<size_t> lock_failures(0);
387 std::atomic<size_t> overflowed(0);
388 std::vector<double> task_seconds(queues.size(), 0.);
390 auto run_single_queue = [&](
auto& Q,
int task_id) {
396 std::atomic_int& success_total;
397 std::atomic_int& fail_total;
398 std::atomic<size_t>& lock_failure_total;
399 std::atomic<size_t>& overflow_total;
402 size_t lock_failure = 0;
406 success_total.fetch_add(success, std::memory_order_relaxed);
407 fail_total.fetch_add(fail, std::memory_order_relaxed);
408 lock_failure_total.fetch_add(lock_failure, std::memory_order_relaxed);
409 overflow_total.fetch_add(overflow, std::memory_order_relaxed);
411 } counts{cnt_success, cnt_fail, lock_failures, overflowed};
421 std::vector<Elem> second_chance;
427 size_t since_refill = 0;
428 const auto refill = [&] {
429 for (
auto& e : second_chance) {
430 Q.emplace(std::move(e));
432 second_chance.clear();
440 if (!Q.try_pop(ele_in_queue)) {
441 if (second_chance.empty()) {
449 std::this_thread::yield();
453 auto& [weight, op, tup, retry] = ele_in_queue;
454 if (!tup.is_valid(m)) {
458 std::vector<Elem> renewed_elements;
465 counts.lock_failure++;
468 second_chance.push_back(ele_in_queue);
472 final_queue.emplace(ele_in_queue);
476 if (tup.is_valid(m)) {
477 const Op& op_str = *op_name[op];
480 std::tuple<double, Op, Tuple>(weight, op_str, tup))) {
481 operation_cleanup(m);
484 auto newtup = (*op_fn[op])(m, tup);
485 std::vector<std::pair<Op, Tuple>> renewed_tuples;
489 if (track_live_success) {
490 live_success.fetch_add(1, std::memory_order_relaxed);
496 for (
const auto& [o, e] : renewed_tuples) {
499 renewed_elements.emplace_back(val, id_of(o), e, 0);
503 operation_cleanup(m);
505 for (
auto& e : renewed_elements) {
509 if (stop.load(std::memory_order_acquire)) {
512 if (track_live_success && live_success.load(std::memory_order_relaxed) >
522 if (policy == ExecutionPolicy::kSeq) {
523 for (
const auto& [op, e] : operation_tuples) {
524 if (!e.is_valid(m)) {
527 final_queue.emplace(
priority(m, op, e), id_of(op), e, 0);
529 run_single_queue(final_queue, 0);
531 for (
const auto& [op, e] : operation_tuples) {
532 if (!e.is_valid(m)) {
535 queues[get_partition_id(m, e)].emplace(
priority(m, op, e), id_of(op), e, 0);
538 using clock = std::chrono::steady_clock;
539 const auto t_parallel = clock::now();
541 for (
int task_id = 0; task_id < queues.size(); task_id++) {
542 tg.run([&run_single_queue, &queues, &task_seconds, task_id] {
543 const auto t0 = clock::now();
544 run_single_queue(queues[task_id], task_id);
546 task_seconds[task_id] =
547 std::chrono::duration<double>(clock::now() - t0).count();
552 std::chrono::duration<double>(clock::now() - t_parallel).count();
555 logger().debug(
"Parallel Complete, remains element {}", final_queue.size());
557 const auto t_tail = clock::now();
558 run_single_queue(final_queue, 0);
559 m_stats.serial_tail_seconds =
560 std::chrono::duration<double>(clock::now() - t_tail).count();
563 m_stats.
lock_failures = lock_failures.load(std::memory_order_relaxed);
564 m_stats.
overflowed = overflowed.load(std::memory_order_relaxed);
565 if (!task_seconds.empty()) {
566 const auto mm = std::minmax_element(task_seconds.begin(), task_seconds.end());
567 m_stats.idlest_task_seconds = *mm.first;
572 "executed: {} | success / fail: {} / {}",
573 (
int)cnt_success + (
int)cnt_fail,