| 100 | } |
| 101 | |
| 102 | void cbm_scale_tick(cbm_scale_probe_t *probe, long done) { |
| 103 | if (!probe || probe->total < SCALE_MIN_ITEMS) { |
| 104 | return; |
| 105 | } |
| 106 | int cp = atomic_load_explicit(&probe->next_cp, memory_order_relaxed); |
| 107 | if (cp >= CBM_SCALE_CHECKPOINTS) { |
| 108 | return; |
| 109 | } |
| 110 | /* cp 0..3 -> total/8, total/4, total/2, total */ |
| 111 | long threshold = probe->total >> (CBM_SCALE_CHECKPOINTS - 1 - cp); |
| 112 | if (done < threshold) { |
| 113 | return; |
| 114 | } |
| 115 | /* Exactly one thread records each checkpoint; a loser simply moves on and |
| 116 | * will re-evaluate against the next threshold on its following tick. */ |
| 117 | if (!atomic_compare_exchange_strong_explicit(&probe->next_cp, &cp, cp + 1, memory_order_relaxed, |
| 118 | memory_order_relaxed)) { |
| 119 | return; |
| 120 | } |
| 121 | probe->cp_us[cp] = scale_elapsed_us(&probe->start); |
| 122 | probe->cp_items[cp] = done; |
| 123 | } |
| 124 | |
| 125 | double cbm_scale_fit_k(long first_n, long first_us, long last_n, long last_us) { |
| 126 | if (first_n <= 0 || first_us <= 0 || last_us <= 0 || last_n <= first_n) { |
no test coverage detected