static_embeddings 1.5.6 → 1.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 550531f7573a8d05e8d5a3a1ae0fa301c01d77b238573ae11834797e8ac44a0f
4
- data.tar.gz: 57f487c729296e3a858604dc64aa146aa6dd6e372a45961d90a61564e3c1b117
3
+ metadata.gz: a8e174dd93ba3b3e9ee25047fd28ea5ba980d096a4922c0b8325c366208bff65
4
+ data.tar.gz: 741e0cc35791d9a335c82a05aed18e3388232828824168ff59ed1751c281e8a8
5
5
  SHA512:
6
- metadata.gz: 52162c96d458dffaaec8498cd712678b4727b29ddaa66eadf7834893113a6bd05f636cc47a2f84d969f76eb4651fe57664212fdb4ac2925449827b9d3a69a9bf
7
- data.tar.gz: 115a0b0f3ff9d82cea099fc0ee24385034d8bcc66ca4ff9337f2213608ee4d611215b6d3400fe39aecf562cf201f5f5044eab7f9863fbdc813362c0af0eb7739
6
+ metadata.gz: 58462ed4c203fb657630d092e1a4aa85857e5d44106bb97feae26f12579fc4b6d88d20632e462624ad0cb93e1d0d0e735f91ee12aaec80b637d29b313e6dc53d
7
+ data.tar.gz: 80e9897969dfe6aace3d851f1a11ffb6610b628cddc35239301a676b2ce32d97d1a8a614ae6dca0526703e61d6d813af89965d0906c593392e66cdd25f7e16da
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.7
4
+
5
+ ### Fixed
6
+
7
+ - Model mappings are no longer closed while embedding, warmup, or token-ID
8
+ operations are using them without the GVL. `Model#close` raises
9
+ `StaticEmbeddings::Error` while such an operation is active.
10
+ - Tokenizer code-point writes now verify the capacity invariant after growth.
11
+ - Resolved Clang conversion warnings and formatting issues in the native code.
12
+
3
13
  ## 1.5.6
4
14
 
5
15
  Multi-source WordPiece release. The native `.semb` v3 runtime is unchanged; new
@@ -5,9 +5,8 @@
5
5
  #include <string.h>
6
6
 
7
7
  static const char *const se_alloc_category_names[SE_ALLOC_CATEGORY_COUNT] = {
8
- "unknown", "scratch", "batch_input", "batch_output",
9
- "batch_stats", "batch_index", "token_ids", "topk_query",
10
- "topk_best", "topk_matrix_copy", "format_validate", "model_file"};
8
+ "unknown", "scratch", "batch_input", "batch_output", "batch_stats", "batch_index",
9
+ "token_ids", "topk_query", "topk_best", "topk_matrix_copy", "format_validate", "model_file"};
11
10
 
12
11
  const char *se_alloc_category_name(se_alloc_category_t category) {
13
12
  if ((unsigned)category >= SE_ALLOC_CATEGORY_COUNT)
@@ -176,7 +175,8 @@ void *se_alloc_stats_realloc(se_alloc_category_t category, void *ptr, size_t byt
176
175
  if (old_header->h.magic != SE_ALLOC_STATS_MAGIC)
177
176
  abort();
178
177
 
179
- se_alloc_category_t old_category = normalize_category((se_alloc_category_t)old_header->h.category);
178
+ se_alloc_category_t old_category =
179
+ normalize_category((se_alloc_category_t)old_header->h.category);
180
180
  size_t old_bytes = old_header->h.size;
181
181
  se_alloc_header_t *new_header = (se_alloc_header_t *)realloc(old_header, total);
182
182
  if (!new_header)
@@ -223,8 +223,7 @@ void se_alloc_stats_snapshot(se_alloc_stats_t out[SE_ALLOC_CATEGORY_COUNT]) {
223
223
  for (size_t i = 0; i < SE_ALLOC_CATEGORY_COUNT; i++) {
224
224
  out[i].current_bytes = atomic_load_size(&se_alloc_stats[i].current_bytes);
225
225
  out[i].peak_bytes = atomic_load_size(&se_alloc_stats[i].peak_bytes);
226
- out[i].total_allocated_bytes =
227
- atomic_load_size(&se_alloc_stats[i].total_allocated_bytes);
226
+ out[i].total_allocated_bytes = atomic_load_size(&se_alloc_stats[i].total_allocated_bytes);
228
227
  out[i].total_freed_bytes = atomic_load_size(&se_alloc_stats[i].total_freed_bytes);
229
228
  out[i].alloc_count = atomic_load_size(&se_alloc_stats[i].alloc_count);
230
229
  out[i].realloc_count = atomic_load_size(&se_alloc_stats[i].realloc_count);
@@ -35,7 +35,7 @@ static void write_u16le(uint8_t *dst, uint16_t v) {
35
35
  }
36
36
 
37
37
  static uint16_t read_u16le(const uint8_t *src) {
38
- return (uint16_t)src[0] | ((uint16_t)src[1] << 8);
38
+ return (uint16_t)((uint16_t)src[0] | ((uint16_t)src[1] << 8));
39
39
  }
40
40
 
41
41
  uint16_t se_float_to_f16_bits(float value) {
@@ -512,6 +512,8 @@ static int append_segment_cp(token_state_t *st, uint32_t cp) {
512
512
  st->segment_ascii = 0;
513
513
  if (!grow_u32(&st->scratch->cps, &st->scratch->cps_cap, st->segment_len + 1))
514
514
  return 0;
515
+ if (st->segment_len >= st->scratch->cps_cap)
516
+ return 0;
515
517
  st->scratch->cps[st->segment_len++] = cp;
516
518
  return 1;
517
519
  }
@@ -906,6 +908,10 @@ static se_status_t tokenize_ascii_run(token_state_t *st, const uint8_t *input, s
906
908
  return oom(st, "building token segment");
907
909
  }
908
910
  }
911
+ if (st->segment_len >= sc->cps_cap) {
912
+ *ip = i;
913
+ return oom(st, "building token segment");
914
+ }
909
915
  sc->cps[st->segment_len++] =
910
916
  (lc && b >= 'A' && b <= 'Z') ? (uint32_t)(b + 32u) : (uint32_t)b;
911
917
  i++;
@@ -73,8 +73,7 @@ float se_dot_product_f32(const float *q, const float *row, size_t dim) {
73
73
  return dot;
74
74
  }
75
75
 
76
- float se_dot_and_row_sq_f32(const float *q, const float *row, size_t dim,
77
- float *row_sq_out) {
76
+ float se_dot_and_row_sq_f32(const float *q, const float *row, size_t dim, float *row_sq_out) {
78
77
  size_t j = 0;
79
78
  #if defined(SE_HAVE_NEON)
80
79
  float32x4_t d0 = vdupq_n_f32(0.0f);
@@ -93,6 +93,7 @@ RUBY_FUNC_EXPORTED void Init_static_embeddings(void);
93
93
  typedef struct {
94
94
  se_model_t model;
95
95
  int open;
96
+ unsigned int active_ops;
96
97
  } model_wrapper_t;
97
98
 
98
99
  static void model_free(void *ptr) {
@@ -177,7 +178,7 @@ static void check_text_encoding_mode(VALUE str, long index, se_encoding_validati
177
178
  rb_enc_name(enc));
178
179
  }
179
180
 
180
- int cr = ENC_CODERANGE(str);
181
+ int cr = (int)ENC_CODERANGE(str);
181
182
  if (cr == ENC_CODERANGE_UNKNOWN) {
182
183
  if (mode == SE_VALIDATE_ENCODING_PREFIX)
183
184
  return;
@@ -216,6 +217,7 @@ typedef struct {
216
217
 
217
218
  typedef struct {
218
219
  const se_model_t *model;
220
+ model_wrapper_t *owner;
219
221
  batch_input_t input;
220
222
  uint32_t max_tokens;
221
223
  float *out;
@@ -228,6 +230,8 @@ typedef struct {
228
230
  se_error_t error;
229
231
  } batch_job_t;
230
232
 
233
+ static void run_job(batch_job_t *job, size_t total_bytes);
234
+
231
235
  static void job_fail(batch_job_t *job, se_error_t err, size_t index) {
232
236
  if (job->failed)
233
237
  return;
@@ -361,6 +365,21 @@ static VALUE fiber_worker_ensure(VALUE wrapper) {
361
365
  return Qnil;
362
366
  }
363
367
 
368
+ static VALUE run_job_body(VALUE arg) {
369
+ batch_job_t *job = (batch_job_t *)(uintptr_t)arg;
370
+ size_t total_bytes = 0;
371
+ for (size_t i = 0; i < job->input.count; i++)
372
+ total_bytes += job->input.lengths[i];
373
+ run_job(job, total_bytes);
374
+ return Qnil;
375
+ }
376
+
377
+ static VALUE run_job_ensure(VALUE arg) {
378
+ batch_job_t *job = (batch_job_t *)(uintptr_t)arg;
379
+ job->owner->active_ops--;
380
+ return Qnil;
381
+ }
382
+
364
383
  static void run_job(batch_job_t *job, size_t total_bytes) {
365
384
  VALUE scheduler = current_fiber_scheduler();
366
385
 
@@ -386,11 +405,8 @@ static void run_job(batch_job_t *job, size_t total_bytes) {
386
405
 
387
406
  static VALUE protected_run_job(VALUE arg) {
388
407
  batch_job_t *job = (batch_job_t *)(uintptr_t)arg;
389
- size_t total_bytes = 0;
390
- for (size_t i = 0; i < job->input.count; i++)
391
- total_bytes += job->input.lengths[i];
392
- run_job(job, total_bytes);
393
- return Qnil;
408
+ job->owner->active_ops++;
409
+ return rb_ensure(run_job_body, arg, run_job_ensure, arg);
394
410
  }
395
411
 
396
412
  static VALUE model_alloc(VALUE klass) {
@@ -422,6 +438,8 @@ static VALUE model_close(VALUE self) {
422
438
  model_wrapper_t *w;
423
439
  TypedData_Get_Struct(self, model_wrapper_t, &model_type, w);
424
440
  if (w->open) {
441
+ if (w->active_ops != 0)
442
+ rb_raise(eError, "model is busy with an active operation");
425
443
  se_model_close(&w->model);
426
444
  w->open = 0;
427
445
  }
@@ -474,18 +492,40 @@ typedef struct {
474
492
  size_t pages;
475
493
  } warmup_job_t;
476
494
 
495
+ typedef struct {
496
+ VALUE self;
497
+ model_wrapper_t *owner;
498
+ warmup_job_t job;
499
+ } warmup_run_t;
500
+
477
501
  static void *warmup_execute(void *arg) {
478
502
  warmup_job_t *job = (warmup_job_t *)arg;
479
503
  job->pages = se_model_warmup(job->model);
480
504
  return NULL;
481
505
  }
482
506
 
507
+ static VALUE warmup_body(VALUE arg) {
508
+ warmup_run_t *run = (warmup_run_t *)(uintptr_t)arg;
509
+ rb_thread_call_without_gvl(warmup_execute, &run->job, NULL, NULL);
510
+ RB_GC_GUARD(run->self);
511
+ return Qnil;
512
+ }
513
+
514
+ static VALUE warmup_ensure(VALUE arg) {
515
+ warmup_run_t *run = (warmup_run_t *)(uintptr_t)arg;
516
+ run->owner->active_ops--;
517
+ return Qnil;
518
+ }
519
+
483
520
  static VALUE model_warmup(VALUE self) {
484
521
  model_wrapper_t *w = get_model(self);
485
- warmup_job_t job;
486
- job.model = &w->model;
487
- job.pages = 0;
488
- rb_thread_call_without_gvl(warmup_execute, &job, NULL, NULL);
522
+ warmup_run_t run;
523
+ run.self = self;
524
+ run.owner = w;
525
+ run.job.model = &w->model;
526
+ run.job.pages = 0;
527
+ w->active_ops++;
528
+ rb_ensure(warmup_body, (VALUE)(uintptr_t)&run, warmup_ensure, (VALUE)(uintptr_t)&run);
489
529
  RB_GC_GUARD(self);
490
530
  return self;
491
531
  }
@@ -829,6 +869,7 @@ static VALUE embed_texts_internal(VALUE self, VALUE texts, int is_array, size_t
829
869
  batch_job_t job;
830
870
  memset(&job, 0, sizeof(job));
831
871
  job.model = model;
872
+ job.owner = w;
832
873
  job.max_tokens = max_tokens;
833
874
  job.out = run.out;
834
875
  job.stats = run.stats;
@@ -1116,6 +1157,7 @@ typedef struct {
1116
1157
 
1117
1158
  typedef struct {
1118
1159
  VALUE ids_value;
1160
+ model_wrapper_t *owner;
1119
1161
  const se_model_t *model;
1120
1162
  uint32_t max_tokens;
1121
1163
  uint32_t *ids;
@@ -1126,6 +1168,7 @@ typedef struct {
1126
1168
  se_token_stats_t *stats_out;
1127
1169
  se_token_stats_t stats;
1128
1170
  int truncated;
1171
+ int active;
1129
1172
  } ids_run_t;
1130
1173
 
1131
1174
  typedef struct {
@@ -1197,7 +1240,11 @@ static VALUE embed_token_ids_body(VALUE arg) {
1197
1240
  se_error_clear(&job.error);
1198
1241
 
1199
1242
  if (run->n >= SE_IDS_GVL_UNLOCK_THRESHOLD) {
1243
+ run->owner->active_ops++;
1244
+ run->active = 1;
1200
1245
  rb_thread_call_without_gvl(ids_execute, &job, ids_unblock_cancel, &job);
1246
+ run->owner->active_ops--;
1247
+ run->active = 0;
1201
1248
  rb_thread_check_ints();
1202
1249
  if (job.cancelled)
1203
1250
  rb_raise(rb_eInterrupt, "operation cancelled");
@@ -1225,6 +1272,8 @@ static VALUE embed_token_ids_body(VALUE arg) {
1225
1272
 
1226
1273
  static VALUE embed_token_ids_ensure(VALUE arg) {
1227
1274
  ids_run_t *run = (ids_run_t *)(uintptr_t)arg;
1275
+ if (run->active)
1276
+ run->owner->active_ops--;
1228
1277
  se_free(run->ids);
1229
1278
  se_free(run->out);
1230
1279
  run->ids = NULL;
@@ -1280,6 +1329,7 @@ static VALUE embed_token_ids_value(VALUE self, VALUE ids_value, VALUE max_tokens
1280
1329
  ids_run_t run;
1281
1330
  memset(&run, 0, sizeof(run));
1282
1331
  run.ids_value = ids_value;
1332
+ run.owner = w;
1283
1333
  run.model = &w->model;
1284
1334
  run.max_tokens = max_tokens;
1285
1335
  run.n = n;
@@ -1,3 +1,3 @@
1
1
  module StaticEmbeddings
2
- VERSION = "1.5.6"
2
+ VERSION = "1.5.7"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: static_embeddings
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.6
4
+ version: 1.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Haydarov