Skip to content

Commit 4728635

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 4728635

File tree

2 files changed

+149
-16
lines changed

2 files changed

+149
-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: 138 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,119 @@
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+
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+
stats.rtry, stats.cons, stats.trav, stats.fail, stats.del, stats.ins,
106+
stats.load, stats.store, deletes, inserts);
107+
}
108+
109+
#else
110+
111+
#define CAS(obj, expected, desired) \
112+
({ atomic_compare_exchange_strong(obj, expected, desired); })
113+
#define ATOMIC_LOAD(obj) ({ atomic_load(obj); })
114+
#define ATOMIC_STORE_EXPLICIT(obj, desired, order) \
115+
do { \
116+
atomic_store_explicit(obj, desired, order); \
117+
} while (0)
118+
#define TRACE(ops) ({})
119+
120+
static void do_analysis(void)
121+
{
122+
fprintf(stderr, "inserts = %zu, deletes = %zu\n", atomic_load(&inserts),
123+
atomic_load(&deletes));
124+
}
125+
126+
#endif /* RUNTIME_STAT */
127+
128+
#define RUNTIME_STAT_INIT() atexit(do_analysis)
129+
17130
#define HP_MAX_THREADS 128
18131
#define HP_MAX_HPS 5 /* This is named 'K' in the HP paper */
19132
#define CLPAD (128 / sizeof(uintptr_t))
@@ -162,8 +275,6 @@ void list_hp_retire(list_hp_t *hp, uintptr_t ptr)
162275
#define N_THREADS (128 / 2)
163276
#define MAX_THREADS 128
164277

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

169280
#define is_marked(p) (bool) ((uintptr_t)(p) &0x01)
@@ -225,21 +336,29 @@ static bool __list_find(list_t *list,
225336

226337
try_again:
227338
prev = &list->head;
228-
curr = (list_node_t *) atomic_load(prev);
339+
curr = (list_node_t *) ATOMIC_LOAD(prev);
229340
(void) list_hp_protect_ptr(list->hp, HP_CURR, (uintptr_t) curr);
230-
if (atomic_load(prev) != get_unmarked(curr))
341+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
342+
TRACE(rtry);
231343
goto try_again;
344+
}
232345
while (true) {
233-
next = (list_node_t *) atomic_load(&get_unmarked_node(curr)->next);
346+
if (is_marked(curr))
347+
TRACE(cons);
348+
next = (list_node_t *) ATOMIC_LOAD(&get_unmarked_node(curr)->next);
234349
(void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(next));
235350
/* On a CAS failure, the search function, "__list_find," will simply
236351
* have to go backwards in the list until an unmarked element is found
237352
* from which the search in increasing key order can be started.
238353
*/
239-
if (atomic_load(&get_unmarked_node(curr)->next) != (uintptr_t) next)
354+
if (ATOMIC_LOAD(&get_unmarked_node(curr)->next) != (uintptr_t) next) {
355+
TRACE(rtry);
240356
goto try_again;
241-
if (atomic_load(prev) != get_unmarked(curr))
357+
}
358+
if (ATOMIC_LOAD(prev) != get_unmarked(curr)) {
359+
TRACE(rtry);
242360
goto try_again;
361+
}
243362
if (get_unmarked_node(next) == next) {
244363
if (!(get_unmarked_node(curr)->key < *key)) {
245364
*par_curr = curr;
@@ -252,12 +371,15 @@ static bool __list_find(list_t *list,
252371
get_unmarked(curr));
253372
} else {
254373
uintptr_t tmp = get_unmarked(curr);
255-
if (!atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next)))
374+
if (!CAS(prev, &tmp, get_unmarked(next))) {
375+
TRACE(rtry);
256376
goto try_again;
377+
}
257378
list_hp_retire(list->hp, get_unmarked(curr));
258379
}
259380
curr = next;
260381
(void) list_hp_protect_release(list->hp, HP_CURR, get_unmarked(next));
382+
TRACE(trav);
261383
}
262384
}
263385

@@ -274,13 +396,14 @@ bool list_insert(list_t *list, list_key_t key)
274396
list_hp_clear(list->hp);
275397
return false;
276398
}
277-
atomic_store_explicit(&node->next, (uintptr_t) curr,
399+
ATOMIC_STORE_EXPLICIT(&node->next, (uintptr_t) curr,
278400
memory_order_relaxed);
279401
uintptr_t tmp = get_unmarked(curr);
280-
if (atomic_compare_exchange_strong(prev, &tmp, (uintptr_t) node)) {
402+
if (CAS(prev, &tmp, (uintptr_t) node)) {
281403
list_hp_clear(list->hp);
282404
return true;
283405
}
406+
TRACE(ins);
284407
}
285408
}
286409

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

297420
uintptr_t tmp = get_unmarked(next);
298421

299-
if (!atomic_compare_exchange_strong(&curr->next, &tmp,
300-
get_marked(next)))
422+
if (!CAS(&curr->next, &tmp, get_marked(next))) {
423+
TRACE(del);
301424
continue;
425+
}
302426

303427
tmp = get_unmarked(curr);
304-
if (atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next))) {
428+
if (CAS(prev, &tmp, get_unmarked(next))) {
305429
list_hp_clear(list->hp);
306430
list_hp_retire(list->hp, get_unmarked(curr));
307431
} else {
@@ -364,6 +488,7 @@ static void *delete_thread(void *arg)
364488

365489
int main(void)
366490
{
491+
RUNTIME_STAT_INIT();
367492
list_t *list = list_new();
368493

369494
pthread_t thr[N_THREADS];
@@ -382,8 +507,5 @@ int main(void)
382507

383508
list_destroy(list);
384509

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

0 commit comments

Comments
 (0)