Skip to content

Commit e22ed46

Browse files
committed
Add more operation analysis, including deletes and inserts variables.
And Using the preprocessor to decide the analysis being set or not. The following are the new varialbes to record the opreations: rtry is the number of retries in the __list_find function. cons is the number of wait-free contains in the __list_find function that curr pointer pointed. trav is the number of list element traversal in the __list_find function. fail is the number of CAS() failures. del is the number of list_delete operation failed and restart again. ins is the number of list_insert operation failed and restart again. load is the number of atomic_load operation in list_delete, list_insert and __list_find. store is the number of atomic_store operation in list_delete, list_insert and __list_find.
1 parent ce237c8 commit e22ed46

File tree

2 files changed

+150
-16
lines changed

2 files changed

+150
-16
lines changed

hp_list/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ $(BIN): main.c
1212
all: CFLAGS += -O2
1313
all: $(BIN)
1414

15+
# The RUNTIME_STAT allow to show the runtime operation states
16+
# in the list_insert, list_delete and __list_find function by
17+
# recording each operation called.
18+
# The operation including atomic load and store, CAS failure,
19+
# search function retry from list head, insert and delete the
20+
# element failed and restart again, the element and wait-free
21+
# contain traversal.
22+
# such as "rtry" is the number of retries in the __list_find function.
23+
analyze: CFLAGS +=-D RUNTIME_STAT
24+
analyze: $(BIN)
25+
1526
indent:
1627
clang-format -i *.[ch]
1728

hp_list/main.c

Lines changed: 139 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,120 @@
1414
#include <string.h>
1515
#include <threads.h>
1616

17+
static atomic_uint_fast64_t deletes = 0, inserts = 0;
18+
19+
#ifdef RUNTIME_STAT
20+
/*
21+
* "rtry" the number of retries in the __list_find function.
22+
* "cons" the number of wait-free contains in the __list_find function that curr
23+
* pointer pointed.
24+
* "trav" the number of list element traversal in the __list_find function.
25+
* "fail" the number of CAS() failures.
26+
* "del" the number of list_delete operation failed and restart again.
27+
* "ins" the number of list_insert operation failed and restart again.
28+
* "load" is the number of atomic_load operation in list_delete, list_insert
29+
* and __list_find.
30+
* "store" is the number of atomic_store operation in list_delete, list_insert
31+
* and __list_find.
32+
*/
33+
struct runtime_stat {
34+
atomic_uint_fast64_t rtry, cons, trav, fail;
35+
atomic_uint_fast64_t del, ins;
36+
atomic_uint_fast64_t load, store;
37+
};
38+
static struct runtime_stat stats = {0};
39+
40+
enum {
41+
TRACE_nothing = 0,
42+
TRACE_rtry,
43+
TRACE_cons,
44+
TRACE_trav,
45+
TRACE_del,
46+
TRACE_ins,
47+
TRACE_inserts,
48+
TRACE_deletes
49+
};
50+
51+
#define CAS(obj, expected, desired) \
52+
({ \
53+
bool __ret = atomic_compare_exchange_strong(obj, expected, desired); \
54+
if (!__ret) \
55+
atomic_fetch_add(&stats.fail, 1); \
56+
__ret; \
57+
})
58+
#define ATOMIC_LOAD(obj) \
59+
({ \
60+
atomic_fetch_add(&stats.load, 1); \
61+
atomic_load(obj); \
62+
})
63+
#define ATOMIC_STORE_EXPLICIT(obj, desired, order) \
64+
do { \
65+
atomic_fetch_add(&stats.store, 1); \
66+
atomic_store_explicit(obj, desired, order); \
67+
} while (0)
68+
#define TRACE(ops) \
69+
({ \
70+
if (TRACE_##ops) \
71+
atomic_fetch_add(&stats.ops, 1); \
72+
})
73+
74+
static void do_analysis(void)
75+
{
76+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
77+
printf(
78+
"\"rtry\" is the number of retries in the __list_find function.\n");
79+
printf(
80+
"\"cons\" is the number of wait-free contains in the __list_find "
81+
"function that curr pointer pointed.\n");
82+
printf(
83+
"\"trav\" is the number of list element traversal in the "
84+
"__list_find function.\n");
85+
printf("\"fail\" is the number of CAS() failures.\n");
86+
printf(
87+
"\"del\" is the number of list_delete operation failed and "
88+
"restart again.\n");
89+
printf(
90+
"\"ins\" is the number of list_insert operation failed and "
91+
"restart again.\n");
92+
printf("\"deletes\" is the number of linked list elements deleted.\n");
93+
printf("\"inserts\" is the number of linked list elements created.\n");
94+
printf(
95+
"\"load\" is the number of atomic_load operation in list_delete, "
96+
"list_insert and __list_find.\n");
97+
printf(
98+
"\"store\" is the number of atomic_store operation in list_delete, "
99+
"list_insert and __list_find.\n");
100+
printf("\n%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n", "rtry",
101+
"cons", "trav", "fail", "del", "ins", "load", "store", "deletes",
102+
"inserts");
103+
for (int i = 0; i < 109; i++)
104+
printf("-");
105+
printf("\n%10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld\n",
106+
stats.rtry, stats.cons, stats.trav, stats.fail, stats.del, stats.ins,
107+
stats.load, stats.store, deletes, inserts);
108+
}
109+
110+
#else
111+
112+
#define CAS(obj, expected, desired) \
113+
({ atomic_compare_exchange_strong(obj, expected, desired); })
114+
#define ATOMIC_LOAD(obj) ({ atomic_load(obj); })
115+
#define ATOMIC_STORE_EXPLICIT(obj, desired, order) \
116+
do { \
117+
atomic_store_explicit(obj, desired, order); \
118+
} while (0)
119+
#define TRACE(ops) ({})
120+
121+
static void do_analysis(void)
122+
{
123+
__atomic_thread_fence(__ATOMIC_SEQ_CST);
124+
fprintf(stderr, "inserts = %zu, deletes = %zu\n", inserts, deletes);
125+
}
126+
127+
#endif /* RUNTIME_STAT */
128+
129+
#define RUNTIME_STAT_INIT() atexit(do_analysis)
130+
17131
#define HP_MAX_THREADS 128
18132
#define HP_MAX_HPS 5 /* This is named 'K' in the HP paper */
19133
#define CLPAD (128 / sizeof(uintptr_t))
@@ -162,8 +276,6 @@ void list_hp_retire(list_hp_t *hp, uintptr_t ptr)
162276
#define N_THREADS (128 / 2)
163277
#define MAX_THREADS 128
164278

165-
static atomic_uint_fast32_t deletes = 0, inserts = 0;
166-
167279
enum { HP_NEXT = 0, HP_CURR = 1, HP_PREV };
168280

169281
#define is_marked(p) (bool) ((uintptr_t)(p) &0x01)
@@ -225,21 +337,29 @@ static bool __list_find(list_t *list,
225337

226338
try_again:
227339
prev = &list->head;
228-
curr = (list_node_t *) atomic_load(prev);
340+
curr = (list_node_t *) ATOMIC_LOAD(prev);
229341
(void) list_hp_protect_ptr(list->hp, HP_CURR, (uintptr_t) curr);
230-
if (atomic_load(prev) != get_unmarked(curr))
342+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
343+
TRACE(rtry);
231344
goto try_again;
345+
}
232346
while (true) {
233-
next = (list_node_t *) atomic_load(&get_unmarked_node(curr)->next);
347+
if (is_marked(curr))
348+
TRACE(cons);
349+
next = (list_node_t *) ATOMIC_LOAD(&get_unmarked_node(curr)->next);
234350
(void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(next));
235351
/* On a CAS failure, the search function, "__list_find," will simply
236352
* have to go backwards in the list until an unmarked element is found
237353
* from which the search in increasing key order can be started.
238354
*/
239-
if (atomic_load(&get_unmarked_node(curr)->next) != (uintptr_t) next)
355+
if (ATOMIC_LOAD(&get_unmarked_node(curr)->next) != (uintptr_t) next) {
356+
TRACE(rtry);
240357
goto try_again;
241-
if (atomic_load(prev) != get_unmarked(curr))
358+
}
359+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
360+
TRACE(rtry);
242361
goto try_again;
362+
}
243363
if (get_unmarked_node(next) == next) {
244364
if (!(get_unmarked_node(curr)->key < *key)) {
245365
*par_curr = curr;
@@ -252,12 +372,15 @@ static bool __list_find(list_t *list,
252372
get_unmarked(curr));
253373
} else {
254374
uintptr_t tmp = get_unmarked(curr);
255-
if (!atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next)))
375+
if (!CAS(prev, &tmp, get_unmarked(next))) {
376+
TRACE(rtry);
256377
goto try_again;
378+
}
257379
list_hp_retire(list->hp, get_unmarked(curr));
258380
}
259381
curr = next;
260382
(void) list_hp_protect_release(list->hp, HP_CURR, get_unmarked(next));
383+
TRACE(trav);
261384
}
262385
}
263386

@@ -274,13 +397,14 @@ bool list_insert(list_t *list, list_key_t key)
274397
list_hp_clear(list->hp);
275398
return false;
276399
}
277-
atomic_store_explicit(&node->next, (uintptr_t) curr,
400+
ATOMIC_STORE_EXPLICIT(&node->next, (uintptr_t) curr,
278401
memory_order_relaxed);
279402
uintptr_t tmp = get_unmarked(curr);
280-
if (atomic_compare_exchange_strong(prev, &tmp, (uintptr_t) node)) {
403+
if (CAS(prev, &tmp, (uintptr_t) node)) {
281404
list_hp_clear(list->hp);
282405
return true;
283406
}
407+
TRACE(ins);
284408
}
285409
}
286410

@@ -296,12 +420,13 @@ bool list_delete(list_t *list, list_key_t key)
296420

297421
uintptr_t tmp = get_unmarked(next);
298422

299-
if (!atomic_compare_exchange_strong(&curr->next, &tmp,
300-
get_marked(next)))
423+
if (!CAS(&curr->next, &tmp, get_marked(next))) {
424+
TRACE(del);
301425
continue;
426+
}
302427

303428
tmp = get_unmarked(curr);
304-
if (atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next))) {
429+
if (CAS(prev, &tmp, get_unmarked(next))) {
305430
list_hp_clear(list->hp);
306431
list_hp_retire(list->hp, get_unmarked(curr));
307432
} else {
@@ -364,6 +489,7 @@ static void *delete_thread(void *arg)
364489

365490
int main(void)
366491
{
492+
RUNTIME_STAT_INIT();
367493
list_t *list = list_new();
368494

369495
pthread_t thr[N_THREADS];
@@ -382,8 +508,5 @@ int main(void)
382508

383509
list_destroy(list);
384510

385-
fprintf(stderr, "inserts = %zu, deletes = %zu\n", atomic_load(&inserts),
386-
atomic_load(&deletes));
387-
388511
return 0;
389512
}

0 commit comments

Comments
 (0)