Skip to content

Commit c8f984e

Browse files
committed
Add more operation analysis, combine with deletes and inserts variables.
And Using the preprocessor to decide the analysis being set or not. Rename the variable which is the number of linked list element created from "inserts" to "creates". The origin one may mixed up with the list_insert operation. 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 c8f984e

File tree

2 files changed

+123
-19
lines changed

2 files changed

+123
-19
lines changed

hp_list/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ $(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

1823
clean:
19-
rm -f $(BIN)
24+
rm -f list

hp_list/main.c

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

17+
#ifdef RUNTIME_STAT
18+
/*
19+
* "rtry" the number of retries in the __list_find function.
20+
* "cons" the number of wait-free contains in the __list_find function that curr
21+
* pointer pointed.
22+
* "trav" the number of list element traversal in the __list_find function.
23+
* "fail" the number of CAS() failures.
24+
* "del" the number of list_delete operation failed and restart again.
25+
* "ins" the number of list_insert operation failed and restart again.
26+
* "load" is the number of atomic_load operation in list_delete, list_insert
27+
* and __list_find.
28+
* "store" is the number of atomic_store operation in list_delete, list_insert
29+
* and __list_find.
30+
*/
31+
static atomic_uint_fast64_t rtry = 0, cons = 0, trav = 0, fail = 0;
32+
static atomic_uint_fast64_t del = 0, ins = 0;
33+
static atomic_uint_fast64_t load = 0, store = 0;
34+
static atomic_uint_fast64_t deletes = 0, creates = 0;
35+
36+
#define CAS(obj, expected, desired) \
37+
({ \
38+
bool __ret = atomic_compare_exchange_strong(obj, expected, desired); \
39+
if (!__ret) \
40+
atomic_fetch_add(&fail, 1); \
41+
__ret; \
42+
})
43+
#define ATOMIC_LOAD(obj) \
44+
({ \
45+
atomic_fetch_add(&load, 1); \
46+
atomic_load(obj); \
47+
})
48+
#define ATOMIC_STORE_EXPLICIT(obj, desired, order) \
49+
do { \
50+
atomic_fetch_add(&store, 1); \
51+
atomic_store_explicit(obj, desired, order); \
52+
} while (0)
53+
#define ATOMIC_FETCH_ADD(obj, arg, ops) ({ atomic_fetch_add(obj, 1); })
54+
55+
void do_analysis(void)
56+
{
57+
printf(
58+
"\"rtry\" is the number of retries in the __list_find function.\n");
59+
printf(
60+
"\"cons\" is the number of wait-free contains in the __list_find "
61+
"function that curr pointer pointed.\n");
62+
printf(
63+
"\"trav\" is the number of list element traversal in the "
64+
"__list_find function.\n");
65+
printf("\"fail\" is the number of CAS() failures.\n");
66+
printf(
67+
"\"del\" is the number of list_delete operation failed and "
68+
"restart again.\n");
69+
printf(
70+
"\"ins\" is the number of list_insert operation failed and "
71+
"restart again.\n");
72+
printf("\"deletes\" is the number of linked list elements deleted.\n");
73+
printf("\"creates\" is the number of linked list elements created.\n");
74+
printf(
75+
"\"load\" is the number of atomic_load operation in list_delete, "
76+
"list_insert and __list_find.\n");
77+
printf(
78+
"\"store\" is the number of atomic_store operation in list_delete, "
79+
"list_insert and __list_find.\n");
80+
printf("\n%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s\n", "rtry",
81+
"cons", "trav", "fail", "del", "ins", "load", "store", "deletes",
82+
"creates");
83+
for (int i = 0; i < 109; i++)
84+
printf("-");
85+
printf("\n%10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld %10ld\n",
86+
rtry, cons, trav, fail, del, ins, load, store, deletes, creates);
87+
}
88+
89+
#else
90+
91+
#define CAS(obj, expected, desired) \
92+
({ atomic_compare_exchange_strong(obj, expected, desired); })
93+
#define ATOMIC_LOAD(obj) ({ atomic_load(obj); })
94+
#define ATOMIC_STORE_EXPLICIT(obj, desired, order) \
95+
do { \
96+
atomic_store_explicit(obj, desired, order); \
97+
} while (0)
98+
#define ATOMIC_FETCH_ADD(obj, arg, ops) \
99+
do { \
100+
} while (0)
101+
#endif
102+
17103
#define HP_MAX_THREADS 128
18104
#define HP_MAX_HPS 5 /* This is named 'K' in the HP paper */
19105
#define CLPAD (128 / sizeof(uintptr_t))
@@ -162,8 +248,6 @@ void list_hp_retire(list_hp_t *hp, uintptr_t ptr)
162248
#define N_THREADS (128 / 2)
163249
#define MAX_THREADS 128
164250

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

169253
#define is_marked(p) (bool) ((uintptr_t)(p) &0x01)
@@ -195,7 +279,7 @@ list_node_t *list_node_new(list_key_t key)
195279
list_node_t *node = aligned_alloc(128, sizeof(*node));
196280
assert(node);
197281
*node = (list_node_t){.magic = LIST_MAGIC, .key = key};
198-
(void) atomic_fetch_add(&inserts, 1);
282+
ATOMIC_FETCH_ADD(&creates, 1, TRACE_CREATES);
199283
return node;
200284
}
201285

@@ -205,7 +289,7 @@ void list_node_destroy(list_node_t *node)
205289
return;
206290
assert(node->magic == LIST_MAGIC);
207291
free(node);
208-
(void) atomic_fetch_add(&deletes, 1);
292+
ATOMIC_FETCH_ADD(&deletes, 1, TRACE_DELETES);
209293
}
210294

211295
static void __list_node_delete(void *arg)
@@ -225,21 +309,31 @@ static bool __list_find(list_t *list,
225309

226310
try_again:
227311
prev = &list->head;
228-
curr = (list_node_t *) atomic_load(prev);
312+
curr = (list_node_t *) ATOMIC_LOAD(prev);
229313
(void) list_hp_protect_ptr(list->hp, HP_CURR, (uintptr_t) curr);
230-
if (atomic_load(prev) != get_unmarked(curr))
314+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
315+
ATOMIC_FETCH_ADD(&rtry, 1, TRACE_TRIES);
231316
goto try_again;
317+
}
232318
while (true) {
233-
next = (list_node_t *) atomic_load(&get_unmarked_node(curr)->next);
319+
#ifdef RUNTIME_STAT
320+
if (is_marked(curr))
321+
ATOMIC_FETCH_ADD(&cons, 1, TRACE_WAIT_FREE_CONS);
322+
#endif
323+
next = (list_node_t *) ATOMIC_LOAD(&get_unmarked_node(curr)->next);
234324
(void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(next));
235325
/* On a CAS failure, the search function, "__list_find," will simply
236326
* have to go backwards in the list until an unmarked element is found
237327
* from which the search in increasing key order can be started.
238328
*/
239-
if (atomic_load(&get_unmarked_node(curr)->next) != (uintptr_t) next)
329+
if (ATOMIC_LOAD(&get_unmarked_node(curr)->next) != (uintptr_t) next) {
330+
ATOMIC_FETCH_ADD(&rtry, 1, TRACE_TRIES);
240331
goto try_again;
241-
if (atomic_load(prev) != get_unmarked(curr))
332+
}
333+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
334+
ATOMIC_FETCH_ADD(&rtry, 1, TRACE_TRIES);
242335
goto try_again;
336+
}
243337
if (get_unmarked_node(next) == next) {
244338
if (!(get_unmarked_node(curr)->key < *key)) {
245339
*par_curr = curr;
@@ -252,12 +346,15 @@ static bool __list_find(list_t *list,
252346
get_unmarked(curr));
253347
} else {
254348
uintptr_t tmp = get_unmarked(curr);
255-
if (!atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next)))
349+
if (!CAS(prev, &tmp, get_unmarked(next))) {
350+
ATOMIC_FETCH_ADD(&rtry, 1, TRACE_TRIES);
256351
goto try_again;
352+
}
257353
list_hp_retire(list->hp, get_unmarked(curr));
258354
}
259355
curr = next;
260356
(void) list_hp_protect_release(list->hp, HP_CURR, get_unmarked(next));
357+
ATOMIC_FETCH_ADD(&trav, 1, TRACE_TRAVERSAL);
261358
}
262359
}
263360

@@ -274,13 +371,14 @@ bool list_insert(list_t *list, list_key_t key)
274371
list_hp_clear(list->hp);
275372
return false;
276373
}
277-
atomic_store_explicit(&node->next, (uintptr_t) curr,
374+
ATOMIC_STORE_EXPLICIT(&node->next, (uintptr_t) curr,
278375
memory_order_relaxed);
279376
uintptr_t tmp = get_unmarked(curr);
280-
if (atomic_compare_exchange_strong(prev, &tmp, (uintptr_t) node)) {
377+
if (CAS(prev, &tmp, (uintptr_t) node)) {
281378
list_hp_clear(list->hp);
282379
return true;
283380
}
381+
ATOMIC_FETCH_ADD(&ins, 1, TRACE_INS);
284382
}
285383
}
286384

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

297395
uintptr_t tmp = get_unmarked(next);
298396

299-
if (!atomic_compare_exchange_strong(&curr->next, &tmp,
300-
get_marked(next)))
397+
if (!CAS(&curr->next, &tmp, get_marked(next))) {
398+
ATOMIC_FETCH_ADD(&del, 1, TRACE_DEL);
301399
continue;
400+
}
302401

303402
tmp = get_unmarked(curr);
304-
if (atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next))) {
403+
if (CAS(prev, &tmp, get_unmarked(next))) {
305404
list_hp_clear(list->hp);
306405
list_hp_retire(list->hp, get_unmarked(curr));
307406
} else {
@@ -382,8 +481,8 @@ int main(void)
382481

383482
list_destroy(list);
384483

385-
fprintf(stderr, "inserts = %zu, deletes = %zu\n", atomic_load(&inserts),
386-
atomic_load(&deletes));
387-
484+
#ifdef RUNTIME_STAT
485+
do_analysis();
486+
#endif
388487
return 0;
389488
}

0 commit comments

Comments
 (0)