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.);
409 std::atomic_int& success_total;
410 std::atomic_int& fail_total;
411 std::atomic<size_t>& lock_failure_total;
412 std::atomic<size_t>& overflow_total;
415 size_t lock_failure = 0;
419 success_total.fetch_add(success, std::memory_order_relaxed);
420 fail_total.fetch_add(fail, std::memory_order_relaxed);
421 lock_failure_total.fetch_add(lock_failure, std::memory_order_relaxed);
422 overflow_total.fetch_add(overflow, std::memory_order_relaxed);
426 auto run_single_queue = [&](
auto& Q,
int task_id) {
427 CountFlusher counts{cnt_success, cnt_fail, lock_failures, overflowed};
437 std::vector<Elem> second_chance;
443 size_t since_refill = 0;
444 const auto refill = [&] {
445 for (
auto& e : second_chance) {
446 Q.emplace(std::move(e));
448 second_chance.clear();
456 if (!Q.try_pop(ele_in_queue)) {
457 if (second_chance.empty()) {
465 std::this_thread::yield();
469 auto& [weight, op, tup, retry] = ele_in_queue;
470 if (!tup.is_valid(m)) {
474 std::vector<Elem> renewed_elements;
481 counts.lock_failure++;
484 second_chance.push_back(ele_in_queue);
488 final_queue.emplace(ele_in_queue);
492 if (tup.is_valid(m)) {
493 const Op& op_str = *op_name[op];
496 std::tuple<double, Op, Tuple>(weight, op_str, tup))) {
497 operation_cleanup(m);
500 auto newtup = (*op_fn[op])(m, tup);
501 std::vector<std::pair<Op, Tuple>> renewed_tuples;
505 if (track_live_success) {
506 live_success.fetch_add(1, std::memory_order_relaxed);
512 for (
const auto& [o, e] : renewed_tuples) {
515 renewed_elements.emplace_back(val, id_of(o), e, 0);
519 operation_cleanup(m);
521 for (
auto& e : renewed_elements) {
525 if (stop.load(std::memory_order_acquire)) {
528 if (track_live_success && live_success.load(std::memory_order_relaxed) >
538 if (policy == ExecutionPolicy::kSeq) {
539 for (
const auto& [op, e] : operation_tuples) {
540 if (!e.is_valid(m)) {
543 final_queue.emplace(
priority(m, op, e), id_of(op), e, 0);
545 run_single_queue(final_queue, 0);
547 for (
const auto& [op, e] : operation_tuples) {
548 if (!e.is_valid(m)) {
551 queues[get_partition_id(m, e)].emplace(
priority(m, op, e), id_of(op), e, 0);
554 using clock = std::chrono::steady_clock;
555 const auto t_parallel = clock::now();
557 for (
int task_id = 0; task_id < queues.size(); task_id++) {
558 tg.run([&run_single_queue, &queues, &task_seconds, task_id] {
559 const auto t0 = clock::now();
560 run_single_queue(queues[task_id], task_id);
562 task_seconds[task_id] =
563 std::chrono::duration<double>(clock::now() - t0).count();
568 std::chrono::duration<double>(clock::now() - t_parallel).count();
571 logger().debug(
"Parallel Complete, remains element {}", final_queue.size());
573 const auto t_tail = clock::now();
574 run_single_queue(final_queue, 0);
575 m_stats.serial_tail_seconds =
576 std::chrono::duration<double>(clock::now() - t_tail).count();
579 m_stats.
lock_failures = lock_failures.load(std::memory_order_relaxed);
580 m_stats.
overflowed = overflowed.load(std::memory_order_relaxed);
581 if (!task_seconds.empty()) {
582 const auto mm = std::minmax_element(task_seconds.begin(), task_seconds.end());
583 m_stats.idlest_task_seconds = *mm.first;
588 "executed: {} | success / fail: {} / {}",
589 (
int)cnt_success + (
int)cnt_fail,