Data-Histogram-Shared
view release on metacpan or search on metacpan
for (int spin = 0; ; spin++) {
uint32_t expected = 0;
if (__atomic_compare_exchange_n(lock, &expected, mypid,
1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
return;
if (__builtin_expect(spin < HIST_RWLOCK_SPIN_LIMIT, 1)) {
hist_rwlock_spin_pause();
continue;
}
hist_park_writer(h);
uint32_t cur = __atomic_load_n(lock, __ATOMIC_RELAXED);
if (cur != 0) {
long rc = syscall(SYS_futex, lock, FUTEX_WAIT, cur,
&hist_lock_timeout, NULL, 0);
if (rc == -1 && errno == ETIMEDOUT) {
hist_unpark_writer(h);
hist_recover_after_timeout(h);
spin = 0;
continue;
}
}
hist_unpark_writer(h);
spin = 0;
}
}
static inline void hist_rwlock_wrunlock(HistHandle *h) {
HistHeader *hdr = h->hdr;
__atomic_store_n(&hdr->rwlock, 0, __ATOMIC_RELEASE);
if (__atomic_load_n(&hdr->rwlock_waiters, __ATOMIC_RELAXED) > 0)
syscall(SYS_futex, &hdr->rwlock, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
}
/* ================================================================
* Layout math + create / open / destroy
*
* Layout: Header -> reader_slots[1024] -> counts[counts_len] (int64_t)
* ================================================================ */
/* Single source of truth for the mmap region layout offsets. */
typedef struct { uint64_t reader_slots, counts; } HistLayout;
static inline HistLayout hist_layout(void) {
HistLayout L;
L.reader_slots = sizeof(HistHeader);
L.counts = L.reader_slots + (uint64_t)HIST_READER_SLOTS * sizeof(HistReaderSlot);
L.counts = (L.counts + 7) & ~(uint64_t)7; /* 8-byte align the counts array (int64_t words) */
return L;
}
static inline uint64_t hist_total_size(int64_t counts_len) {
HistLayout L = hist_layout();
return L.counts + (uint64_t)counts_len * sizeof(int64_t); /* counts_len int64_t cells */
}
static inline int64_t *hist_counts(HistHandle *h) {
return (int64_t *)((char *)h->base + h->hdr->counts_off);
}
/* ================================================================
* HdrHistogram geometry -- canonical formulas (see HdrHistogram_c).
* All derived fields are computed once here and stored in the header.
* ================================================================ */
typedef struct {
int64_t lowest;
int64_t highest;
int32_t sig_figs;
int32_t unit_magnitude;
int32_t sub_bucket_count_magnitude;
int32_t sub_bucket_half_count_magnitude;
int32_t sub_bucket_count;
int32_t sub_bucket_half_count;
int64_t sub_bucket_mask;
int32_t bucket_count;
int64_t counts_len;
} HistGeometry;
/* Validate args + compute the full geometry. Single source of truth: the XS
* layer does NOT duplicate these range checks. */
static int hist_validate_create_args(int64_t lowest, int64_t highest, int32_t sig_figs,
HistGeometry *g, char *errbuf) {
if (errbuf) errbuf[0] = '\0';
if (lowest < 1) { HIST_ERR("lowest must be >= 1"); return 0; }
if (highest < 2 * lowest) { HIST_ERR("highest must be >= 2 * lowest"); return 0; }
if (sig_figs < HIST_MIN_SIG || sig_figs > HIST_MAX_SIG) {
HIST_ERR("sig_figs must be between %d and %d", HIST_MIN_SIG, HIST_MAX_SIG); return 0;
}
int32_t unit_magnitude = (int32_t)floor(log2((double)lowest));
int32_t sbc_magnitude = (int32_t)ceil(log2(2.0 * pow(10.0, (double)sig_figs)));
if (sbc_magnitude < 1) sbc_magnitude = 1;
int32_t shc_magnitude = sbc_magnitude - 1;
if (unit_magnitude + shc_magnitude > 61) {
HIST_ERR("lowest too large for sig_figs (unit_magnitude %d + sub_bucket_half_count_magnitude %d exceeds 61)", unit_magnitude, shc_magnitude);
return 0;
}
int32_t sub_bucket_count = (int32_t)(1 << sbc_magnitude);
int32_t sub_bucket_half_count = sub_bucket_count / 2;
int64_t sub_bucket_mask = ((int64_t)sub_bucket_count - 1) << unit_magnitude;
/* bucket_count: smallest count of buckets covering 'highest' */
int64_t smallest_untrackable = (int64_t)sub_bucket_count << unit_magnitude;
int32_t bucket_count = 1;
while (smallest_untrackable <= highest) {
if (smallest_untrackable > (INT64_MAX / 2)) { bucket_count++; break; }
smallest_untrackable <<= 1;
bucket_count++;
}
int64_t counts_len = (int64_t)(bucket_count + 1) * sub_bucket_half_count;
g->lowest = lowest;
g->highest = highest;
g->sig_figs = sig_figs;
g->unit_magnitude = unit_magnitude;
g->sub_bucket_count_magnitude = sbc_magnitude;
g->sub_bucket_half_count_magnitude = shc_magnitude;
g->sub_bucket_count = sub_bucket_count;
g->sub_bucket_half_count = sub_bucket_half_count;
g->sub_bucket_mask = sub_bucket_mask;
g->bucket_count = bucket_count;
( run in 2.872 seconds using v1.01-cache-2.11-cpan-c966e8aa7e8 )