ARGOBOTS
global.c
Go to the documentation of this file.
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  * See COPYRIGHT in top-level directory.
4  */
5 
6 #include "abti.h"
7 
13 /* Global Data */
14 ABTI_global *gp_ABTI_global = NULL;
15 
16 /* To indicate how many times ABT_init is called. */
17 static uint32_t g_ABTI_num_inits = 0;
18 /* A global lock protecting the initialization/finalization process */
19 static ABTI_spinlock g_ABTI_init_lock = ABTI_SPINLOCK_STATIC_INITIALIZER();
20 /* A flag whether Argobots has been initialized or not */
21 static ABTD_atomic_uint32 g_ABTI_initialized =
22  ABTD_ATOMIC_UINT32_STATIC_INITIALIZER(0);
23 
40 int ABT_init(int argc, char **argv)
41 {
42  ABTI_UNUSED(argc);
43  ABTI_UNUSED(argv);
44  int abt_errno = ABT_SUCCESS;
45 
46  /* First, take a global lock protecting the initialization/finalization
47  * process. Don't go to fn_exit before taking a lock */
48  ABTI_spinlock_acquire(&g_ABTI_init_lock);
49 
50  /* If Argobots has already been initialized, just return */
51  if (g_ABTI_num_inits++ > 0)
52  goto fn_exit;
53 
54  gp_ABTI_global = (ABTI_global *)ABTU_malloc(sizeof(ABTI_global));
55 
56  /* Initialize the system environment */
57  ABTD_env_init(gp_ABTI_global);
58 
59  /* Initialize memory pool */
60  ABTI_mem_init(gp_ABTI_global);
61 
62  /* Initialize IDs */
63  ABTI_thread_reset_id();
64  ABTI_task_reset_id();
65  ABTI_sched_reset_id();
66  ABTI_pool_reset_id();
67 
68  /* Initialize the ES array */
69  gp_ABTI_global->p_xstreams =
70  (ABTI_xstream **)ABTU_calloc(gp_ABTI_global->max_xstreams,
71  sizeof(ABTI_xstream *));
72  gp_ABTI_global->num_xstreams = 0;
73 
74  /* Initialize a spinlock */
75  ABTI_spinlock_clear(&gp_ABTI_global->xstreams_lock);
76 
77  /* Init the ES local data */
78  ABTI_local *p_local = NULL;
79  abt_errno = ABTI_local_init(&p_local);
80  ABTI_CHECK_ERROR_MSG(abt_errno, "ABTI_local_init");
81 
82  /* Create the primary ES */
83  ABTI_xstream *p_newxstream;
84  abt_errno = ABTI_xstream_create_primary(&p_local, &p_newxstream);
85  ABTI_CHECK_ERROR_MSG(abt_errno, "ABTI_xstream_create_primary");
86  p_local->p_xstream = p_newxstream;
87 
88  /* Create the primary ULT, i.e., the main thread */
89  ABTI_thread *p_main_thread;
90  abt_errno = ABTI_thread_create_main(p_local, p_newxstream, &p_main_thread);
91  /* Set as if p_newxstream is currently running the main thread. */
92  ABTD_atomic_relaxed_store_int(&p_main_thread->state,
94  p_main_thread->p_last_xstream = p_newxstream;
95  ABTI_CHECK_ERROR_MSG(abt_errno, "ABTI_thread_create_main");
96  gp_ABTI_global->p_thread_main = p_main_thread;
97  p_local->p_thread = p_main_thread;
98 
99  /* Start the primary ES */
100  abt_errno =
101  ABTI_xstream_start_primary(&p_local, p_newxstream, p_main_thread);
102  ABTI_CHECK_ERROR_MSG(abt_errno, "ABTI_xstream_start_primary");
103 
104  if (gp_ABTI_global->print_config == ABT_TRUE) {
105  ABTI_info_print_config(stdout);
106  }
107  ABTD_atomic_release_store_uint32(&g_ABTI_initialized, 1);
108 
109 fn_exit:
110  /* Unlock a global lock */
111  ABTI_spinlock_release(&g_ABTI_init_lock);
112  return abt_errno;
113 
114 fn_fail:
115  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
116  goto fn_exit;
117 }
118 
135 int ABT_finalize(void)
136 {
137  int abt_errno = ABT_SUCCESS;
138  ABTI_local *p_local = ABTI_local_get_local();
139 
140  /* First, take a global lock protecting the initialization/finalization
141  * process. Don't go to fn_exit before taking a lock */
142  ABTI_spinlock_acquire(&g_ABTI_init_lock);
143 
144  /* If Argobots is not initialized, just return */
145  if (g_ABTI_num_inits == 0) {
146  abt_errno = ABT_ERR_UNINITIALIZED;
147  goto fn_exit;
148  }
149  /* If Argobots is still referenced by others, just return */
150  if (--g_ABTI_num_inits != 0)
151  goto fn_exit;
152 
153  /* If called by an external thread, return an error. */
154  ABTI_CHECK_TRUE(p_local != NULL, ABT_ERR_INV_XSTREAM);
155 
156  ABTI_xstream *p_xstream = p_local->p_xstream;
157  ABTI_CHECK_TRUE_MSG(p_xstream->type == ABTI_XSTREAM_TYPE_PRIMARY,
159  "ABT_finalize must be called by the primary ES.");
160 
161  ABTI_thread *p_thread = p_local->p_thread;
162  ABTI_CHECK_TRUE_MSG(p_thread->type == ABTI_THREAD_TYPE_MAIN,
164  "ABT_finalize must be called by the primary ULT.");
165 
166  /* Set the join request */
167  ABTI_xstream_set_request(p_xstream, ABTI_XSTREAM_REQ_JOIN);
168 
169  /* We wait for the remaining jobs */
170  if (ABTD_atomic_acquire_load_int(&p_xstream->state) !=
172  /* Set the orphan request for the primary ULT */
173  ABTI_thread_set_request(p_thread, ABTI_THREAD_REQ_ORPHAN);
174 
175  LOG_EVENT("[U%" PRIu64 ":E%d] yield to scheduler\n",
176  ABTI_thread_get_id(p_thread), p_thread->p_last_xstream->rank);
177 
178  /* Switch to the top scheduler */
179  ABTI_sched *p_sched =
180  ABTI_xstream_get_top_sched(p_thread->p_last_xstream);
181  ABTI_thread_context_switch_thread_to_sched(&p_local, p_thread, p_sched);
182 
183  /* Back to the original thread */
184  LOG_EVENT("[U%" PRIu64 ":E%d] resume after yield\n",
185  ABTI_thread_get_id(p_thread), p_thread->p_last_xstream->rank);
186  }
187 
188  /* Remove the primary ULT */
189  ABTI_thread_free_main(p_local, p_thread);
190  p_local->p_thread = NULL;
191 
192  /* Free the primary ES */
193  abt_errno = ABTI_xstream_free(p_local, p_xstream);
194  p_local->p_xstream = NULL;
195  ABTI_CHECK_ERROR(abt_errno);
196 
197  /* Finalize the ES local data */
198  abt_errno = ABTI_local_finalize(&p_local);
199  ABTI_CHECK_ERROR(abt_errno);
200 
201  /* Free the ES array */
202  ABTU_free(gp_ABTI_global->p_xstreams);
203 
204  /* Finalize the memory pool */
205  ABTI_mem_finalize(gp_ABTI_global);
206 
207  /* Restore the affinity */
208  if (gp_ABTI_global->set_affinity == ABT_TRUE) {
209  ABTD_affinity_finalize();
210  }
211 
212  /* Free the ABTI_global structure */
214  gp_ABTI_global = NULL;
215  ABTD_atomic_release_store_uint32(&g_ABTI_initialized, 0);
216 
217 fn_exit:
218  /* Unlock a global lock */
219  ABTI_spinlock_release(&g_ABTI_init_lock);
220  return abt_errno;
221 
222 fn_fail:
223  HANDLE_ERROR_FUNC_WITH_CODE(abt_errno);
224  goto fn_exit;
225 }
226 
240 {
241  int abt_errno = ABT_SUCCESS;
242 
243  if (ABTD_atomic_acquire_load_uint32(&g_ABTI_initialized) == 0) {
244  abt_errno = ABT_ERR_UNINITIALIZED;
245  }
246 
247  return abt_errno;
248 }
249 
250 /* If new_size is equal to zero, we double max_xstreams.
251  * NOTE: This function currently cannot decrease max_xstreams.
252  */
253 void ABTI_global_update_max_xstreams(int new_size)
254 {
255  int i, cur_size;
256 
257  if (new_size != 0 && new_size < gp_ABTI_global->max_xstreams)
258  return;
259 
260  ABTI_spinlock_acquire(&gp_ABTI_global->xstreams_lock);
261 
262  static int max_xstreams_warning_once = 0;
263  if (max_xstreams_warning_once == 0) {
264  /* Because some Argobots functionalities depend on the runtime value
265  * ABT_MAX_NUM_XSTREAMS (or gp_ABTI_global->max_xstreams), changing this
266  * value at run-time can cause an error. For example, using ABT_mutex
267  * created before updating max_xstreams causes an error since
268  * ABTI_thread_htable's array size depends on ABT_MAX_NUM_XSTREAMS.
269  * To fix this issue, please set a larger number to ABT_MAX_NUM_XSTREAMS
270  * in advance. */
271  char *warning_message = (char *)malloc(sizeof(char) * 1024);
272  snprintf(warning_message, 1024,
273  "Warning: the number of execution streams exceeds "
274  "ABT_MAX_NUM_XSTREAMS (=%d), which may cause an unexpected "
275  "error.",
276  gp_ABTI_global->max_xstreams);
277  HANDLE_WARNING(warning_message);
278  free(warning_message);
279  max_xstreams_warning_once = 1;
280  }
281 
282  cur_size = gp_ABTI_global->max_xstreams;
283  new_size = (new_size > 0) ? new_size : cur_size * 2;
284  gp_ABTI_global->max_xstreams = new_size;
285  gp_ABTI_global->p_xstreams =
286  (ABTI_xstream **)ABTU_realloc(gp_ABTI_global->p_xstreams,
287  cur_size * sizeof(ABTI_xstream *),
288  new_size * sizeof(ABTI_xstream *));
289 
290  for (i = gp_ABTI_global->num_xstreams; i < new_size; i++) {
291  gp_ABTI_global->p_xstreams[i] = NULL;
292  }
293 
294  ABTI_spinlock_release(&gp_ABTI_global->xstreams_lock);
295 }
int ABT_init(int argc, char **argv)
Initialize the Argobots execution environment.
Definition: global.c:40
static ABTD_atomic_uint32 g_ABTI_initialized
Definition: global.c:21
ABTI_global * gp_ABTI_global
Definition: global.c:14
static ABTI_spinlock g_ABTI_init_lock
Definition: global.c:19
#define ABT_ERR_INV_THREAD
Definition: abt.h:80
static void * ABTU_malloc(size_t size)
Definition: abtu.h:39
#define HANDLE_WARNING(msg)
Definition: abti_error.h:220
#define HANDLE_ERROR_FUNC_WITH_CODE(n)
Definition: abti_error.h:241
static uint32_t g_ABTI_num_inits
Definition: global.c:17
static void * ABTU_realloc(void *ptr, size_t old_size, size_t new_size)
Definition: abtu.h:56
int ABT_finalize(void)
Terminate the Argobots execution environment.
Definition: global.c:135
#define ABT_SUCCESS
Definition: abt.h:64
#define LOG_EVENT(fmt,...)
Definition: abti_log.h:60
#define ABT_TRUE
Definition: abt.h:223
#define ABT_ERR_UNINITIALIZED
Definition: abt.h:65
#define ABT_ERR_INV_XSTREAM
Definition: abt.h:68
static void ABTU_free(void *ptr)
Definition: abtu.h:32
int ABT_initialized(void)
Check whether ABT_init() has been called.
Definition: global.c:239
static void * ABTU_calloc(size_t num, size_t size)
Definition: abtu.h:49