Skip to content

Commit 8768c88

Browse files
committed
Add concurrent_set.c debugging facilities
1 parent 245f3e8 commit 8768c88

1 file changed

Lines changed: 43 additions & 9 deletions

File tree

concurrent_set.c

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#define CONCURRENT_SET_HASH_MASK (~CONCURRENT_SET_HASH_RECLAIMABLE_BIT)
1414

1515
#define CONCURRENT_SET_DEBUG 0
16+
#define CONCURRENT_SET_DEBUG_STATS 0
17+
#define CONCURRENT_SET_DEBUG_DUPLICATES 0
18+
#define CONCURRENT_SET_DEBUG_BAD_HASH_FN 0
1619

1720
enum concurrent_set_special_values {
1821
CONCURRENT_SET_EMPTY = 0,
@@ -33,7 +36,7 @@ struct concurrent_set {
3336
const struct rb_concurrent_set_funcs *funcs;
3437
struct concurrent_set_entry *entries;
3538
int key_type;
36-
#if CONCURRENT_SET_DEBUG
39+
#if CONCURRENT_SET_DEBUG_STATS
3740
rb_atomic_t find_count;
3841
rb_atomic_t find_probe_total;
3942
rb_atomic_t find_probe_max;
@@ -68,6 +71,10 @@ static VALUE
6871
concurrent_set_hash(const struct concurrent_set *set, VALUE key)
6972
{
7073
VALUE hash = set->funcs->hash(key);
74+
#if CONCURRENT_SET_DEBUG_BAD_HASH_FN
75+
hash = hash % 1024;
76+
if (hash == 0) hash = 1;
77+
#endif
7178
hash &= CONCURRENT_SET_HASH_MASK;
7279
if (hash == 0) hash = ~(VALUE)0 & CONCURRENT_SET_HASH_MASK;
7380
RUBY_ASSERT(hash != 0);
@@ -155,7 +162,7 @@ rb_concurrent_set_probe_stats(VALUE set_obj,
155162
rb_atomic_t *find_count, rb_atomic_t *find_probe_total, rb_atomic_t *find_probe_max,
156163
rb_atomic_t *insert_count, rb_atomic_t *insert_probe_total, rb_atomic_t *insert_probe_max)
157164
{
158-
#if CONCURRENT_SET_DEBUG
165+
#if CONCURRENT_SET_DEBUG_STATS
159166
struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
160167
*find_count = RUBY_ATOMIC_LOAD(set->find_count);
161168
*find_probe_total = RUBY_ATOMIC_LOAD(set->find_probe_total);
@@ -173,7 +180,7 @@ rb_concurrent_set_probe_stats(VALUE set_obj,
173180
#endif
174181
}
175182

176-
#if CONCURRENT_SET_DEBUG
183+
#if CONCURRENT_SET_DEBUG_STATS
177184
static void
178185
concurrent_set_atomic_max(rb_atomic_t *target, rb_atomic_t val)
179186
{
@@ -244,6 +251,7 @@ concurrent_set_try_resize_locked(VALUE old_set_obj, VALUE *set_obj_ptr, VALUE ne
244251
// Insert key into new_set.
245252
struct concurrent_set_probe probe;
246253
int idx = concurrent_set_probe_start(&probe, new_set, hash);
254+
int start_idx = idx;
247255

248256
while (true) {
249257
struct concurrent_set_entry *entry = &new_set->entries[idx];
@@ -262,6 +270,7 @@ concurrent_set_try_resize_locked(VALUE old_set_obj, VALUE *set_obj_ptr, VALUE ne
262270
RUBY_ASSERT(entry->key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
263271
entry->key |= CONCURRENT_SET_CONTINUATION_BIT;
264272
idx = concurrent_set_probe_next(&probe);
273+
RUBY_ASSERT(idx != start_idx);
265274
}
266275
}
267276

@@ -397,7 +406,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
397406
VALUE curr_hash = rbimpl_atomic_value_load(&entry->hash, RBIMPL_ATOMIC_ACQUIRE) & CONCURRENT_SET_HASH_MASK;
398407

399408
if (curr_hash == 0) {
400-
#if CONCURRENT_SET_DEBUG
409+
#if CONCURRENT_SET_DEBUG_STATS
401410
rbimpl_atomic_fetch_add(&set->find_count, 1, RBIMPL_ATOMIC_RELAXED);
402411
rbimpl_atomic_fetch_add(&set->find_probe_total, probe.d, RBIMPL_ATOMIC_RELAXED);
403412
concurrent_set_atomic_max(&set->find_probe_max, probe.d);
@@ -411,7 +420,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
411420

412421
if (curr_hash != hash) {
413422
if (!continuation) {
414-
#if CONCURRENT_SET_DEBUG
423+
#if CONCURRENT_SET_DEBUG_STATS
415424
rbimpl_atomic_fetch_add(&set->find_count, 1, RBIMPL_ATOMIC_RELAXED);
416425
rbimpl_atomic_fetch_add(&set->find_probe_total, probe.d, RBIMPL_ATOMIC_RELAXED);
417426
concurrent_set_atomic_max(&set->find_probe_max, probe.d);
@@ -442,7 +451,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
442451

443452
if (set->funcs->cmp(key, curr_key)) {
444453
// We've found a match.
445-
#if CONCURRENT_SET_DEBUG
454+
#if CONCURRENT_SET_DEBUG_STATS
446455
rbimpl_atomic_fetch_add(&set->find_count, 1, RBIMPL_ATOMIC_RELAXED);
447456
rbimpl_atomic_fetch_add(&set->find_probe_total, probe.d, RBIMPL_ATOMIC_RELAXED);
448457
concurrent_set_atomic_max(&set->find_probe_max, probe.d);
@@ -452,7 +461,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
452461
}
453462

454463
if (!continuation) {
455-
#if CONCURRENT_SET_DEBUG
464+
#if CONCURRENT_SET_DEBUG_STATS
456465
rbimpl_atomic_fetch_add(&set->find_count, 1, RBIMPL_ATOMIC_RELAXED);
457466
rbimpl_atomic_fetch_add(&set->find_probe_total, probe.d, RBIMPL_ATOMIC_RELAXED);
458467
concurrent_set_atomic_max(&set->find_probe_max, probe.d);
@@ -551,10 +560,35 @@ rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
551560

552561
VALUE prev_raw_key = rbimpl_atomic_value_cas(&entry->key, raw_key, key | (continuation ? CONCURRENT_SET_CONTINUATION_BIT : 0), RBIMPL_ATOMIC_RELEASE, RBIMPL_ATOMIC_ACQUIRE);
553562
if (prev_raw_key == raw_key) {
554-
#if CONCURRENT_SET_DEBUG
563+
#if CONCURRENT_SET_DEBUG_STATS
555564
rbimpl_atomic_fetch_add(&set->insert_count, 1, RBIMPL_ATOMIC_RELAXED);
556565
rbimpl_atomic_fetch_add(&set->insert_probe_total, probe.d, RBIMPL_ATOMIC_RELAXED);
557566
concurrent_set_atomic_max(&set->insert_probe_max, probe.d);
567+
#endif
568+
#if CONCURRENT_SET_DEBUG_DUPLICATES
569+
{
570+
// Probe further to verify no duplicate of our key exists
571+
struct concurrent_set_probe dup_probe = probe;
572+
int dup_idx = concurrent_set_probe_next(&dup_probe);
573+
int dup_idx_start = dup_idx;
574+
while (true) {
575+
struct concurrent_set_entry *dup_entry = &set->entries[dup_idx];
576+
VALUE dup_raw_key = rbimpl_atomic_value_load(&dup_entry->key, RBIMPL_ATOMIC_ACQUIRE);
577+
VALUE dup_key = dup_raw_key & CONCURRENT_SET_KEY_MASK;
578+
579+
if (dup_key == CONCURRENT_SET_EMPTY) break;
580+
if (dup_key == CONCURRENT_SET_MOVED) break;
581+
582+
if (dup_key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT && dup_key == key) {
583+
rb_bug("concurrent_set_find_or_insert: duplicate key %p found at index %d after inserting at index %d",
584+
(void *)key, dup_idx, idx);
585+
}
586+
int next_dup_idx = concurrent_set_probe_next(&dup_probe);
587+
if (dup_idx < dup_idx_start && next_dup_idx >= dup_idx_start) break;
588+
if (next_dup_idx == dup_idx_start) break;
589+
dup_idx = next_dup_idx;
590+
}
591+
}
558592
#endif
559593
RB_GC_GUARD(set_obj);
560594
return key;
@@ -593,7 +627,7 @@ rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
593627

594628
if (set->funcs->cmp(key, curr_key)) {
595629
// We've found a live match.
596-
#if CONCURRENT_SET_DEBUG
630+
#if CONCURRENT_SET_DEBUG_STATS
597631
rbimpl_atomic_fetch_add(&set->insert_count, 1, RBIMPL_ATOMIC_RELAXED);
598632
rbimpl_atomic_fetch_add(&set->insert_probe_total, probe.d, RBIMPL_ATOMIC_RELAXED);
599633
concurrent_set_atomic_max(&set->insert_probe_max, probe.d);

0 commit comments

Comments
 (0)