Skip to content

Commit 2536a9d

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 2536a9d

File tree

2 files changed

+148
-16
lines changed

2 files changed

+148
-16
lines changed

hp_list/Makefile

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

15+
# The RUNTIME_STAT allow to show the runtime operation state,
16+
# such as "rtry" is the number of retries in the __list_find function.
17+
analyze: CFLAGS +=-D RUNTIME_STAT
18+
analyze: $(BIN)
19+
1520
indent:
1621
clang-format -i *.[ch]
1722

hp_list/main.c

Lines changed: 143 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,124 @@
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+
struct runtime_stat rts = {0};
39+
40+
enum {
41+
TRACE_NOTHING = 0,
42+
TRACE_TRIES,
43+
TRACE_WAIT_FREE_CONS,
44+
TRACE_TRAVERSAL,
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(&rts.fail, 1); \
56+
__ret; \
57+
})
58+
#define ATOMIC_LOAD(obj) \
59+
({ \
60+
atomic_fetch_add(&rts.load, 1); \
61+
atomic_load(obj); \
62+
})
63+
#define ATOMIC_STORE_EXPLICIT(obj, desired, order) \
64+
do { \
65+
atomic_fetch_add(&rts.store, 1); \
66+
atomic_store_explicit(obj, desired, order); \
67+
} while (0)
68+
#define ATOMIC_FETCH_ADD(obj, arg, ops) \
69+
({ \
70+
if (TRACE_##ops) \
71+
atomic_fetch_add(obj, arg); \
72+
})
73+
74+
static void do_analysis(void)
75+
{
76+
printf(
77+
"\"rtry\" is the number of retries in the __list_find function.\n");
78+
printf(
79+
"\"cons\" is the number of wait-free contains in the __list_find "
80+
"function that curr pointer pointed.\n");
81+
printf(
82+
"\"trav\" is the number of list element traversal in the "
83+
"__list_find function.\n");
84+
printf("\"fail\" is the number of CAS() failures.\n");
85+
printf(
86+
"\"del\" is the number of list_delete operation failed and "
87+
"restart again.\n");
88+
printf(
89+
"\"ins\" is the number of list_insert operation failed and "
90+
"restart again.\n");
91+
printf("\"deletes\" is the number of linked list elements deleted.\n");
92+
printf("\"inserts\" is the number of linked list elements created.\n");
93+
printf(
94+
"\"load\" is the number of atomic_load operation in list_delete, "
95+
"list_insert and __list_find.\n");
96+
printf(
97+
"\"store\" is the number of atomic_store operation in list_delete, "
98+
"list_insert and __list_find.\n");
99+
printf("\n%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n", "rtry",
100+
"cons", "trav", "fail", "del", "ins", "load", "store", "deletes",
101+
"inserts");
102+
for (int i = 0; i < 109; i++)
103+
printf("-");
104+
printf("\n%10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld\n",
105+
atomic_load(&rts.rtry), atomic_load(&rts.cons),
106+
atomic_load(&rts.trav), atomic_load(&rts.fail),
107+
atomic_load(&rts.del), atomic_load(&rts.ins), atomic_load(&rts.load),
108+
atomic_load(&rts.store), atomic_load(&deletes),
109+
atomic_load(&inserts));
110+
}
111+
112+
#define RUNTIME_STAT_INIT() atexit(do_analysis)
113+
114+
#else
115+
116+
#define CAS(obj, expected, desired) \
117+
({ atomic_compare_exchange_strong(obj, expected, desired); })
118+
#define ATOMIC_LOAD(obj) ({ atomic_load(obj); })
119+
#define ATOMIC_STORE_EXPLICIT(obj, desired, order) \
120+
do { \
121+
atomic_store_explicit(obj, desired, order); \
122+
} while (0)
123+
#define ATOMIC_FETCH_ADD(obj, arg, ops) ({})
124+
125+
static void do_analysis(void)
126+
{
127+
fprintf(stderr, "inserts = %zu, deletes = %zu\n", atomic_load(&inserts),
128+
atomic_load(&deletes));
129+
}
130+
131+
#define RUNTIME_STAT_INIT() atexit(do_analysis)
132+
133+
#endif /* RUNTIME_STAT */
134+
17135
#define HP_MAX_THREADS 128
18136
#define HP_MAX_HPS 5 /* This is named 'K' in the HP paper */
19137
#define CLPAD (128 / sizeof(uintptr_t))
@@ -162,8 +280,6 @@ void list_hp_retire(list_hp_t *hp, uintptr_t ptr)
162280
#define N_THREADS (128 / 2)
163281
#define MAX_THREADS 128
164282

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

169285
#define is_marked(p) (bool) ((uintptr_t)(p) &0x01)
@@ -225,21 +341,29 @@ static bool __list_find(list_t *list,
225341

226342
try_again:
227343
prev = &list->head;
228-
curr = (list_node_t *) atomic_load(prev);
344+
curr = (list_node_t *) ATOMIC_LOAD(prev);
229345
(void) list_hp_protect_ptr(list->hp, HP_CURR, (uintptr_t) curr);
230-
if (atomic_load(prev) != get_unmarked(curr))
346+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
347+
ATOMIC_FETCH_ADD(&rts.rtry, 1, TRIES);
231348
goto try_again;
349+
}
232350
while (true) {
233-
next = (list_node_t *) atomic_load(&get_unmarked_node(curr)->next);
351+
if (is_marked(curr))
352+
ATOMIC_FETCH_ADD(&rts.cons, 1, WAIT_FREE_CONS);
353+
next = (list_node_t *) ATOMIC_LOAD(&get_unmarked_node(curr)->next);
234354
(void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(next));
235355
/* On a CAS failure, the search function, "__list_find," will simply
236356
* have to go backwards in the list until an unmarked element is found
237357
* from which the search in increasing key order can be started.
238358
*/
239-
if (atomic_load(&get_unmarked_node(curr)->next) != (uintptr_t) next)
359+
if (ATOMIC_LOAD(&get_unmarked_node(curr)->next) != (uintptr_t) next) {
360+
ATOMIC_FETCH_ADD(&rts.rtry, 1, TRIES);
240361
goto try_again;
241-
if (atomic_load(prev) != get_unmarked(curr))
362+
}
363+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
364+
ATOMIC_FETCH_ADD(&rts.rtry, 1, TRIES);
242365
goto try_again;
366+
}
243367
if (get_unmarked_node(next) == next) {
244368
if (!(get_unmarked_node(curr)->key < *key)) {
245369
*par_curr = curr;
@@ -252,12 +376,15 @@ static bool __list_find(list_t *list,
252376
get_unmarked(curr));
253377
} else {
254378
uintptr_t tmp = get_unmarked(curr);
255-
if (!atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next)))
379+
if (!CAS(prev, &tmp, get_unmarked(next))) {
380+
ATOMIC_FETCH_ADD(&rts.rtry, 1, TRIES);
256381
goto try_again;
382+
}
257383
list_hp_retire(list->hp, get_unmarked(curr));
258384
}
259385
curr = next;
260386
(void) list_hp_protect_release(list->hp, HP_CURR, get_unmarked(next));
387+
ATOMIC_FETCH_ADD(&rts.trav, 1, TRAVERSAL);
261388
}
262389
}
263390

@@ -274,13 +401,14 @@ bool list_insert(list_t *list, list_key_t key)
274401
list_hp_clear(list->hp);
275402
return false;
276403
}
277-
atomic_store_explicit(&node->next, (uintptr_t) curr,
404+
ATOMIC_STORE_EXPLICIT(&node->next, (uintptr_t) curr,
278405
memory_order_relaxed);
279406
uintptr_t tmp = get_unmarked(curr);
280-
if (atomic_compare_exchange_strong(prev, &tmp, (uintptr_t) node)) {
407+
if (CAS(prev, &tmp, (uintptr_t) node)) {
281408
list_hp_clear(list->hp);
282409
return true;
283410
}
411+
ATOMIC_FETCH_ADD(&rts.ins, 1, INS);
284412
}
285413
}
286414

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

297425
uintptr_t tmp = get_unmarked(next);
298426

299-
if (!atomic_compare_exchange_strong(&curr->next, &tmp,
300-
get_marked(next)))
427+
if (!CAS(&curr->next, &tmp, get_marked(next))) {
428+
ATOMIC_FETCH_ADD(&rts.del, 1, DEL);
301429
continue;
430+
}
302431

303432
tmp = get_unmarked(curr);
304-
if (atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next))) {
433+
if (CAS(prev, &tmp, get_unmarked(next))) {
305434
list_hp_clear(list->hp);
306435
list_hp_retire(list->hp, get_unmarked(curr));
307436
} else {
@@ -364,6 +493,7 @@ static void *delete_thread(void *arg)
364493

365494
int main(void)
366495
{
496+
RUNTIME_STAT_INIT();
367497
list_t *list = list_new();
368498

369499
pthread_t thr[N_THREADS];
@@ -382,8 +512,5 @@ int main(void)
382512

383513
list_destroy(list);
384514

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

0 commit comments

Comments
 (0)