ggerganov commited on
Commit
ae956e7
·
1 Parent(s): 9ed1355

ggml : fix thread-safety of ggml_init and ggml_free

Browse files
Files changed (1) hide show
  1. ggml.c +34 -0
ggml.c CHANGED
@@ -1136,6 +1136,7 @@ struct ggml_state {
1136
 
1137
  // global state
1138
  struct ggml_state g_state;
 
1139
 
1140
  ////////////////////////////////////////////////////////////////////////////////
1141
 
@@ -1265,6 +1266,17 @@ int ggml_up64(int n) {
1265
  ////////////////////////////////////////////////////////////////////////////////
1266
 
1267
  struct ggml_context * ggml_init(struct ggml_init_params params) {
 
 
 
 
 
 
 
 
 
 
 
1268
  static bool is_first_call = true;
1269
  if (is_first_call) {
1270
  const uint64_t t_start = ggml_time_us(); UNUSED(t_start);
@@ -1308,6 +1320,9 @@ struct ggml_context * ggml_init(struct ggml_init_params params) {
1308
 
1309
  if (ctx == NULL) {
1310
  GGML_PRINT_DEBUG("%s: no unused context found\n", __func__);
 
 
 
1311
  return NULL;
1312
  }
1313
 
@@ -1322,10 +1337,25 @@ struct ggml_context * ggml_init(struct ggml_init_params params) {
1322
 
1323
  ggml_assert_aligned(ctx->mem_buffer);
1324
 
 
 
 
 
1325
  return ctx;
1326
  }
1327
 
1328
  void ggml_free(struct ggml_context * ctx) {
 
 
 
 
 
 
 
 
 
 
 
1329
  for (int i = 0; i < GGML_MAX_CONTEXTS; i++) {
1330
  if (&g_state.contexts[i].context == ctx) {
1331
  g_state.contexts[i].used = false;
@@ -1337,11 +1367,15 @@ void ggml_free(struct ggml_context * ctx) {
1337
  free(ctx->mem_buffer);
1338
  }
1339
 
 
 
1340
  return;
1341
  }
1342
  }
1343
 
1344
  GGML_PRINT_DEBUG("%s: context not found\n", __func__);
 
 
1345
  }
1346
 
1347
  size_t ggml_used_mem(const struct ggml_context * ctx) {
 
1136
 
1137
  // global state
1138
  struct ggml_state g_state;
1139
+ atomic_bool g_state_barrier = 0;
1140
 
1141
  ////////////////////////////////////////////////////////////////////////////////
1142
 
 
1266
  ////////////////////////////////////////////////////////////////////////////////
1267
 
1268
  struct ggml_context * ggml_init(struct ggml_init_params params) {
1269
+ // make this function thread safe
1270
+ {
1271
+ int processing = atomic_fetch_add(&g_state_barrier, 1);
1272
+ while (processing > 0) {
1273
+ // wait for other threads to finish
1274
+ atomic_fetch_sub(&g_state_barrier, 1);
1275
+ sched_yield();
1276
+ processing = atomic_fetch_add(&g_state_barrier, 1);
1277
+ }
1278
+ }
1279
+
1280
  static bool is_first_call = true;
1281
  if (is_first_call) {
1282
  const uint64_t t_start = ggml_time_us(); UNUSED(t_start);
 
1320
 
1321
  if (ctx == NULL) {
1322
  GGML_PRINT_DEBUG("%s: no unused context found\n", __func__);
1323
+
1324
+ atomic_fetch_sub(&g_state_barrier, 1);
1325
+
1326
  return NULL;
1327
  }
1328
 
 
1337
 
1338
  ggml_assert_aligned(ctx->mem_buffer);
1339
 
1340
+ GGML_PRINT_DEBUG("%s: context initialized\n", __func__);
1341
+
1342
+ atomic_fetch_sub(&g_state_barrier, 1);
1343
+
1344
  return ctx;
1345
  }
1346
 
1347
  void ggml_free(struct ggml_context * ctx) {
1348
+ // make this function thread safe
1349
+ {
1350
+ int processing = atomic_fetch_add(&g_state_barrier, 1);
1351
+ while (processing > 0) {
1352
+ // wait for other threads to finish
1353
+ atomic_fetch_sub(&g_state_barrier, 1);
1354
+ sched_yield();
1355
+ processing = atomic_fetch_add(&g_state_barrier, 1);
1356
+ }
1357
+ }
1358
+
1359
  for (int i = 0; i < GGML_MAX_CONTEXTS; i++) {
1360
  if (&g_state.contexts[i].context == ctx) {
1361
  g_state.contexts[i].used = false;
 
1367
  free(ctx->mem_buffer);
1368
  }
1369
 
1370
+ atomic_fetch_sub(&g_state_barrier, 1);
1371
+
1372
  return;
1373
  }
1374
  }
1375
 
1376
  GGML_PRINT_DEBUG("%s: context not found\n", __func__);
1377
+
1378
+ atomic_fetch_sub(&g_state_barrier, 1);
1379
  }
1380
 
1381
  size_t ggml_used_mem(const struct ggml_context * ctx) {