Skip to content

Commit 209a7a0

Browse files
committed
opal/lifo: add load-linked store-conditional support
This commit adds implementations for opal_atomic_lifo_pop and opal_atomic_lifo_push that make use of the load-linked and store-conditional instruction. These instruction allow for a more efficient implementation on supported platforms. Signed-off-by: Nathan Hjelm <hjelmn@lanl.gov>
1 parent 2a7e191 commit 209a7a0

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

opal/class/opal_lifo.h

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* All rights reserved.
1313
* Copyright (c) 2007 Voltaire All rights reserved.
1414
* Copyright (c) 2010 IBM Corporation. All rights reserved.
15-
* Copyright (c) 2014 Los Alamos National Security, LLC. All rights
15+
* Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights
1616
* reseved.
1717
* $COPYRIGHT$
1818
*
@@ -25,6 +25,7 @@
2525
#define OPAL_LIFO_H_HAS_BEEN_INCLUDED
2626

2727
#include "opal_config.h"
28+
#include <time.h>
2829
#include "opal/class/opal_list.h"
2930

3031
#include "opal/sys/atomic.h"
@@ -180,6 +181,52 @@ static inline opal_list_item_t *opal_lifo_push_atomic (opal_lifo_t *lifo,
180181
} while (1);
181182
}
182183

184+
#if OPAL_HAVE_ATOMIC_LLSC_PTR
185+
186+
static inline void _opal_lifo_release_cpu (void)
187+
{
188+
/* NTH: there are many ways to cause the current thread to be suspended. This one
189+
* should work well in most cases. Another approach would be to use poll (NULL, 0, ) but
190+
* the interval will be forced to be in ms (instead of ns or us). Note that there
191+
* is a performance improvement for the lifo test when this call is made on detection
192+
* of contention but it may not translate into actually MPI or application performance
193+
* improvements. */
194+
static struct timespec interval = { .tv_sec = 0, .tv_nsec = 100 };
195+
nanosleep (&interval, NULL);
196+
}
197+
198+
/* Retrieve one element from the LIFO. If we reach the ghost element then the LIFO
199+
* is empty so we return NULL.
200+
*/
201+
static inline opal_list_item_t *opal_lifo_pop_atomic (opal_lifo_t* lifo)
202+
{
203+
opal_list_item_t *item, *next;
204+
int attempt = 0;
205+
206+
do {
207+
if (++attempt == 5) {
208+
/* deliberatly suspend this thread to allow other threads to run. this should
209+
* only occur during periods of contention on the lifo. */
210+
_opal_lifo_release_cpu ();
211+
attempt = 0;
212+
}
213+
214+
item = (opal_list_item_t *) opal_atomic_ll_ptr (&lifo->opal_lifo_head.data.item);
215+
if (&lifo->opal_lifo_ghost == item) {
216+
return NULL;
217+
}
218+
219+
next = (opal_list_item_t *) item->opal_list_next;
220+
} while (!opal_atomic_sc_ptr (&lifo->opal_lifo_head.data.item, next));
221+
222+
opal_atomic_wmb ();
223+
224+
item->opal_list_next = NULL;
225+
return item;
226+
}
227+
228+
#else
229+
183230
/* Retrieve one element from the LIFO. If we reach the ghost element then the LIFO
184231
* is empty so we return NULL.
185232
*/
@@ -216,6 +263,8 @@ static inline opal_list_item_t *opal_lifo_pop_atomic (opal_lifo_t* lifo)
216263
return item;
217264
}
218265

266+
#endif /* OPAL_HAVE_ATOMIC_LLSC_PTR */
267+
219268
#endif
220269

221270
/* single-threaded versions of the lifo functions */

0 commit comments

Comments
 (0)