• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 7090909294

04 Dec 2023 06:26PM UTC coverage: 88.653% (+0.1%) from 88.517%
7090909294

push

github

fckxorg
bisect

5377 of 5986 branches covered (0.0%)

Branch coverage included in aggregate %.

13 of 13 new or added lines in 1 file covered. (100.0%)

20 existing lines in 3 files now uncovered.

20633 of 23353 relevant lines covered (88.35%)

2746472.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.67
/src/lj_sysprof.c
1
/*
2
** Implementation of sysprof - platform and Lua profiler.
3
*/
4

5
#define lj_sysprof_c
6
#define LUA_CORE
7

8
#include "lj_arch.h"
9
#include "lj_sysprof.h"
10

11
#if LJ_HASSYSPROF
12

13
#include "lj_obj.h"
14
#include "lj_debug.h"
15
#include "lj_dispatch.h"
16
#include "lj_frame.h"
17

18
#if LJ_HASJIT
19
#include "lj_jit.h"
20
#include "lj_trace.h"
21
#endif
22

23
#include "lj_wbuf.h"
24
#include "lj_profile_timer.h"
25
#include "lj_symtab.h"
26

27
#include <pthread.h>
28
#include <errno.h>
29
#include <execinfo.h>
30

31
/*
32
** Number of profiler frames we need to omit during stack
33
** unwinding.
34
**   +------------------------+
35
** 0 | default_backtrace_host |
36
**   +------------------------+
37
** 1 | stream_backtrace_host  |
38
**   +------------------------+
39
** 2 |  stream_{guest/host}   |
40
**   +------------------------+
41
** 3 |      stream_event      |
42
**   +------------------------+
43
** 4 | sysprof_record_sample  |
44
**   +------------------------+
45
** 5 | sysprof_signal_handler |
46
**   +------------------------+
47
*/
48
#define SYSPROF_HANDLER_STACK_DEPTH 6
49
#define SYSPROF_BACKTRACE_FRAME_MAX 512
50

51
/* Check that vmstate fits in 4 bits (see streaming format) */
52
#define vmstfit4(st) ((st & ~(uint32_t)((1 << 4) - 1)) == 0)
53

54
enum sysprof_state {
55
  /* Profiler is not running. */
56
  SPS_IDLE,
57
  /* Profiler is running. */
58
  SPS_PROFILE,
59
  /*
60
  ** Stopped in case of stopped or failed stream.
61
  ** Saved errno is set at luaM_sysprof_stop.
62
  */
63
  SPS_HALT
64
};
65

66
struct sysprof {
67
  global_State *g; /* Profiled VM. */
68
  pthread_t thread; /* Profiled thread. */
69
  volatile sig_atomic_t state; /* Internal state. */
70
  struct lj_wbuf out; /* Output accumulator. */
71
  struct luam_Sysprof_Counters counters; /* Profiling counters. */
72
  struct luam_Sysprof_Options opt; /* Profiling options. */
73
  luam_Sysprof_writer writer; /* Writer function for profile events. */
74
  luam_Sysprof_on_stop on_stop; /* Callback on profiling stopping. */
75
  luam_Sysprof_backtracer backtracer; /* Backtracing function for the host stack. */
76
  lj_profile_timer timer; /* Profiling timer. */
77
  int saved_errno; /* Saved errno when profiler failed. */
78
  uint32_t lib_adds; /* Number of libs loaded. Monotonic. */
79
};
80
/*
81
** XXX: Only one VM can be profiled at a time.
82
*/
83

84
static struct sysprof sysprof = {0};
85

86
/* --- Stream ------------------------------------------------------------- */
87

88
static const uint8_t ljp_header[] = {'l', 'j', 'p', LJP_FORMAT_VERSION,
89
                                      0x0, 0x0, 0x0};
90

91
static int stream_is_needed(struct sysprof *sp)
24✔
92
{
93
  return sp->opt.mode != LUAM_SYSPROF_DEFAULT;
24✔
94
}
95

96
static int is_unconfigured(struct sysprof *sp)
802✔
97
{
98
  return sp->backtracer == NULL || sp->on_stop == NULL || sp->writer == NULL;
274✔
99
}
100

101
static void stream_prologue(struct sysprof *sp)
6✔
102
{
103
  lj_symtab_dump(&sp->out, sp->g, &sp->lib_adds);
6✔
104
  lj_wbuf_addn(&sp->out, ljp_header, sizeof(ljp_header));
6✔
105
}
6✔
106

107
static void stream_epilogue(struct sysprof *sp)
6✔
108
{
109
  lj_wbuf_addbyte(&sp->out, LJP_EPILOGUE_BYTE);
6✔
110
}
111

112
static void stream_ffunc_impl(struct lj_wbuf *buf, uint8_t ffid)
7✔
113
{
114
  lj_wbuf_addbyte(buf, LJP_FRAME_FFUNC);
7✔
115
  lj_wbuf_addu64(buf, ffid);
5✔
116
}
5✔
117

118
static void stream_lfunc(struct lj_wbuf *buf, const GCfunc *func)
119
{
120
  lj_assertX(isluafunc(func), "bad lua function in sysprof stream");
121
  const GCproto *pt = funcproto(func);
122
  lj_assertX(pt != NULL, "bad lua function prototype in sysprof stream");
123
  lj_wbuf_addbyte(buf, LJP_FRAME_LFUNC);
124
  lj_wbuf_addu64(buf, (uintptr_t)pt);
125
  lj_wbuf_addu64(buf, (uint64_t)pt->firstline);
126
}
127

128
static void stream_cfunc(struct lj_wbuf *buf, const GCfunc *func)
18✔
129
{
130
  lj_assertX(iscfunc(func), "bad C function in sysprof stream");
18✔
131
  lj_wbuf_addbyte(buf, LJP_FRAME_CFUNC);
18✔
132
  lj_wbuf_addu64(buf, (uintptr_t)func->c.f);
18✔
133
}
18✔
134

135
static void stream_ffunc(struct lj_wbuf *buf, const GCfunc *func)
2✔
136
{
137
  lj_assertX(isffunc(func), "bad fast function in sysprof stream");
2✔
138
  stream_ffunc_impl(buf, func->c.ffid);
2✔
139
}
2✔
140

141
static void stream_frame_lua(struct lj_wbuf *buf, const cTValue *frame)
288✔
142
{
143
  const GCfunc *func = frame_func(frame);
288✔
144
  lj_assertX(func != NULL, "bad function in sysprof stream");
288✔
145
  if (isluafunc(func))
288✔
146
    stream_lfunc(buf, func);
268✔
147
  else if (isffunc(func))
20✔
148
    stream_ffunc(buf, func);
2✔
149
  else if (iscfunc(func))
18✔
150
    stream_cfunc(buf, func);
18✔
151
  else
152
    /* Unreachable. */
153
    lj_assertX(0, "bad function type in sysprof stream");
288✔
154
}
288✔
155

156
static void stream_backtrace_lua(struct sysprof *sp, uint32_t vmstate)
24✔
157
{
158
  global_State *g = sp->g;
24✔
159
  struct lj_wbuf *buf = &sp->out;
24✔
160
  cTValue *top_frame = NULL, *frame = NULL, *bot = NULL;
24✔
161
  lua_State *L = NULL;
24✔
162

163
  lj_assertX(g != NULL, "uninitialized global state in sysprof state");
24✔
164
  L = gco2th(gcref(g->cur_L));
24✔
165
  lj_assertG(L != NULL, "uninitialized Lua state in sysprof state");
24✔
166
  /*
167
  ** Lua stack may be inconsistent during the execution of a
168
  ** fast-function, so instead of updating the `top_frame` for
169
  ** it, its `ffid` is set instead. The first frame on the
170
  ** result stack is streamed manually, and the rest of the
171
  ** stack is streamed based on the previous `top_frame` value.
172
  */
173
  if (vmstate == LJ_VMST_FFUNC) {
24✔
174
    uint8_t ffid = g->top_frame_info.ffid;
5✔
175
    stream_ffunc_impl(buf, ffid);
5✔
176
  }
177

178
  top_frame = g->top_frame_info.top_frame - 1;
24✔
179

180
  bot = tvref(L->stack) + LJ_FR2;
24✔
181
  /* Traverse frames backwards */
182
  for (frame = top_frame; frame > bot; frame = frame_prev(frame)) {
630✔
183
    if (frame_gc(frame) == obj2gco(L) || frame_isvarg(frame))
303✔
184
      continue;  /* Skip dummy frames. See lj_err_optype_call(). */
15✔
185
    stream_frame_lua(buf, frame);
288✔
186
  }
187

188
  lj_wbuf_addbyte(buf, LJP_FRAME_LUA_LAST);
24✔
189
}
24✔
190

191
static void *stream_frame_host(int frame_no, void *addr)
275✔
192
{
193
  struct sysprof *sp = &sysprof;
275✔
194
  /*
195
  ** We don't want the profiler stack to be streamed, as it will
196
  ** burden the profile with unnecessary information.
197
  */
198
  if (LJ_UNLIKELY(frame_no <= SYSPROF_HANDLER_STACK_DEPTH))
275✔
199
    return addr;
200
  else if (LJ_UNLIKELY(sp->opt.mode == LUAM_SYSPROF_LEAF &&
82✔
201
                         frame_no > SYSPROF_HANDLER_STACK_DEPTH))
202
    return NULL;
203

204
  lj_wbuf_addu64(&sp->out, (uintptr_t)addr);
82✔
205
  return addr;
82✔
206
}
207

208
static void default_backtrace_host(void *(writer)(int frame_no, void *addr))
33✔
209
{
210
  static void *backtrace_buf[SYSPROF_BACKTRACE_FRAME_MAX] = {};
33✔
211

212
  struct sysprof *sp = &sysprof;
33✔
213
  int max_depth = sp->opt.mode == LUAM_SYSPROF_LEAF
66✔
214
                  ? SYSPROF_HANDLER_STACK_DEPTH + 1
215
                  : SYSPROF_BACKTRACE_FRAME_MAX;
33✔
216
  const int depth = backtrace(backtrace_buf, max_depth);
33✔
217
  int level;
33✔
218

219
  lj_assertX(depth <= max_depth, "depth of C stack is too big");
33✔
220
  for (level = SYSPROF_HANDLER_STACK_DEPTH; level < depth; ++level) {
341✔
221
    if (!writer(level - SYSPROF_HANDLER_STACK_DEPTH + 1, backtrace_buf[level]))
275✔
222
      return;
223
  }
224
}
225

226
static void stream_backtrace_host(struct sysprof *sp)
33✔
227
{
228
  lj_assertX(sp->backtracer != NULL, "uninitialized sysprof backtracer");
33✔
229
  sp->backtracer(stream_frame_host);
33✔
230
  lj_wbuf_addu64(&sp->out, (uintptr_t)LJP_FRAME_HOST_LAST);
33✔
231
}
232

233
#if LJ_HASJIT
234
static void stream_trace(struct sysprof *sp, uint32_t vmstate)
3✔
235
{
236
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
3✔
237
  struct lj_wbuf *out = &sp->out;
3✔
238
  uint32_t traceno = sp->g->vmstate;
3✔
239
  jit_State *J = G2J(sp->g);
3✔
240
  GCtrace *trace = traceref(J, traceno);
3✔
241

242
  GCproto *startpt = gco2pt(gcref(trace->startpt));
3✔
243

244
  lj_wbuf_addu64(out, traceno);
3✔
245
  lj_wbuf_addu64(out, (uintptr_t)startpt);
3✔
246
  lj_wbuf_addu64(out, startpt->firstline);
3✔
247
}
3✔
248
#endif
249

250
static void stream_guest(struct sysprof *sp, uint32_t vmstate)
24✔
251
{
252
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
24✔
253
  stream_backtrace_lua(sp, vmstate);
24✔
254
  stream_backtrace_host(sp);
24✔
255
}
24✔
256

257
static void stream_host(struct sysprof *sp, uint32_t vmstate)
9✔
258
{
259
  struct lua_State *L = gco2th(gcref(sp->g->cur_L));
9✔
260
  lj_symtab_dump_newc(&sp->lib_adds, &sp->out, LJP_SYMTAB_CFUNC_EVENT, L);
9✔
261
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
9✔
262
  stream_backtrace_host(sp);
9✔
263
}
9✔
264

265
typedef void (*event_streamer)(struct sysprof *sp, uint32_t vmstate);
266

267
static event_streamer event_streamers[] = {
268
  /* XXX: order is important */
269
  stream_host,  /* LJ_VMST_INTERP */
270
  stream_guest, /* LJ_VMST_LFUNC */
271
  stream_guest, /* LJ_VMST_FFUNC */
272
  stream_guest, /* LJ_VMST_CFUNC */
273
  stream_host,  /* LJ_VMST_GC */
274
  stream_host,  /* LJ_VMST_EXIT */
275
  stream_host,  /* LJ_VMST_RECORD */
276
  stream_host,  /* LJ_VMST_OPT */
277
  stream_host,  /* LJ_VMST_ASM */
278
#if LJ_HASJIT
279
  stream_trace  /* LJ_VMST_TRACE */
280
#endif
281
};
282

283
static void stream_event(struct sysprof *sp, uint32_t vmstate)
284
{
285
  event_streamer stream = NULL;
286

287
  lj_assertX(vmstfit4(vmstate), "vmstate don't fit in 4 bits");
288
  stream = event_streamers[vmstate];
289
  lj_assertX(stream != NULL, "uninitialized sysprof stream");
290
  stream(sp, vmstate);
291
}
292

293
/* -- Signal handler ------------------------------------------------------ */
294

295
static void sysprof_record_sample(struct sysprof *sp, siginfo_t *info)
296
{
297
  global_State *g = sp->g;
298
  uint32_t _vmstate = ~(uint32_t)(g->vmstate);
299
  uint32_t vmstate = _vmstate < LJ_VMST_TRACE ? _vmstate : LJ_VMST_TRACE;
300

301
  lj_assertX(pthread_self() == sp->thread,
302
             "bad thread during sysprof record sample");
303

304
  /* Caveat: order of counters must match vmstate order in <lj_obj.h>. */
305
  ((uint64_t *)&sp->counters)[vmstate]++;
306

307
  sp->counters.samples++;
308

309
  if (!stream_is_needed(sp))
310
    return;
311

312
  stream_event(sp, vmstate);
313
  if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
314
    sp->saved_errno = lj_wbuf_errno(&sp->out);
315
    lj_wbuf_terminate(&sp->out);
316
    sp->state = SPS_HALT;
317
  }
318
}
319

320
static void sysprof_signal_handler(int sig, siginfo_t *info, void *ctx)
37✔
321
{
322
  struct sysprof *sp = &sysprof;
37✔
323
  UNUSED(sig);
37✔
324
  UNUSED(ctx);
37✔
325

326
  switch (sp->state) {
37✔
327
    case SPS_PROFILE:
37✔
328
      sysprof_record_sample(sp, info);
37✔
329
      break;
37✔
330

331
    case SPS_IDLE:
332
    case SPS_HALT:
333
      /* noop */
334
      break;
335

336
    default:
337
      lj_assertX(0, "bad sysprof profiler state");
338
      break;
339
  }
340
}
37✔
341

342
/* -- Internal ------------------------------------------------------------ */
343

344
static int sysprof_validate(struct sysprof *sp,
17✔
345
                            const struct luam_Sysprof_Options *opt)
346
{
347
  switch (sp->state) {
17✔
348
    case SPS_IDLE:
15✔
349
      if (opt->mode > LUAM_SYSPROF_CALLGRAPH) {
15✔
350
        return PROFILE_ERRUSE;
351
      } else if (opt->mode != LUAM_SYSPROF_DEFAULT &&
14✔
352
                 (opt->buf == NULL || opt->len == 0 || is_unconfigured(sp))) {
7✔
353
        return PROFILE_ERRUSE;
354
      } else if (opt->interval == 0) {
13✔
355
        return PROFILE_ERRUSE;
1✔
356
      }
357
      break;
358

359
    case SPS_PROFILE:
360
    case SPS_HALT:
361
      return PROFILE_ERRRUN;
362

363
    default:
364
      lj_assertX(0, "bad sysprof profiler state");
365
      break;
366
  }
367

368
  return PROFILE_SUCCESS;
369
}
370

371
static int sysprof_init(struct sysprof *sp, lua_State *L,
372
                        const struct luam_Sysprof_Options *opt)
373
{
374
  const int status = sysprof_validate(sp, opt);
375
  if (PROFILE_SUCCESS != status)
376
    return status;
377

378
  /* Copy validated options to sysprof state. */
379
  memcpy(&sp->opt, opt, sizeof(sp->opt));
380

381
  /* Init general fields. */
382
  sp->g = G(L);
383
  sp->thread = pthread_self();
384

385
  /* Reset counters. */
386
  memset(&sp->counters, 0, sizeof(sp->counters));
387

388
  /* Reset saved errno. */
389
  sp->saved_errno = 0;
390

391
  if (stream_is_needed(sp))
392
    lj_wbuf_init(&sp->out, sp->writer, opt->ctx, opt->buf, opt->len);
393

394
  return PROFILE_SUCCESS;
395
}
396

397
/* -- Public profiling API ------------------------------------------------ */
398

399
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
266✔
400
  struct sysprof *sp = &sysprof;
266✔
401

402
  if (sp->state != SPS_IDLE || writer == NULL)
266✔
403
    return PROFILE_ERRUSE;
404

405
  sp->writer = writer;
266✔
406
  if (!is_unconfigured(sp)) {
266✔
407
    sp->state = SPS_IDLE;
2✔
408
  }
409
  return PROFILE_SUCCESS;
410
}
411

412
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
266✔
413
  struct sysprof *sp = &sysprof;
266✔
414

415
  if (sp->state != SPS_IDLE || on_stop == NULL)
266✔
416
    return PROFILE_ERRUSE;
417

418
  sp->on_stop = on_stop;
266✔
419
  if (!is_unconfigured(sp)) {
266✔
420
    sp->state = SPS_IDLE;
2✔
421
  }
422
  return PROFILE_SUCCESS;
423
}
424

425
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
264✔
426
  struct sysprof *sp = &sysprof;
264✔
427

428
  if (sp->state != SPS_IDLE)
264✔
429
    return PROFILE_ERRUSE;
430
  if (backtracer == NULL) {
264✔
431
    sp->backtracer = default_backtrace_host;
264✔
432
    /*
433
    ** XXX: `backtrace` is not signal-safe, according to man,
434
    ** because it is lazy loaded on the first call, which triggers
435
    ** allocations. We need to call `backtrace` before starting profiling
436
    ** to avoid lazy loading.
437
    */
438
    void *dummy = NULL;
264✔
439
    backtrace(&dummy, 1);
264✔
440
  }
441
  else {
UNCOV
442
    sp->backtracer = backtracer;
×
443
  }
444
  if (!is_unconfigured(sp)) {
264✔
445
    sp->state = SPS_IDLE;
264✔
446
  }
447
  return PROFILE_SUCCESS;
448
}
449

450
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
17✔
451
{
452
  struct sysprof *sp = &sysprof;
17✔
453

454
  int status = sysprof_init(sp, L, opt);
17✔
455
  if (PROFILE_SUCCESS != status) {
17✔
456
    if (NULL != sp->on_stop) {
5✔
457
      /*
458
      ** Initialization may fail in case of unconfigured sysprof,
459
      ** so we cannot guarantee cleaning up resources in this case.
460
      */
461
      sp->on_stop(opt->ctx, opt->buf);
5✔
462
    }
463
    return status;
5✔
464
  }
465

466
  sp->state = SPS_PROFILE;
12✔
467

468
  if (stream_is_needed(sp)) {
12✔
469
    stream_prologue(sp);
6✔
470
    if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
6✔
471
      /* on_stop call may change errno value. */
UNCOV
472
      const int saved_errno = lj_wbuf_errno(&sp->out);
×
473
      /* Ignore possible errors. mp->out.buf may be NULL here. */
UNCOV
474
      sp->on_stop(opt->ctx, sp->out.buf);
×
UNCOV
475
      lj_wbuf_terminate(&sp->out);
×
UNCOV
476
      sp->state = SPS_IDLE;
×
UNCOV
477
      errno = saved_errno;
×
UNCOV
478
      return PROFILE_ERRIO;
×
479
    }
480
  }
481

482
  sp->timer.opt.interval_msec = opt->interval;
12✔
483
  sp->timer.opt.handler = sysprof_signal_handler;
12✔
484
  lj_profile_timer_start(&sp->timer);
12✔
485

486
  return PROFILE_SUCCESS;
12✔
487
}
488

489
int lj_sysprof_stop(lua_State *L)
272✔
490
{
491
  struct sysprof *sp = &sysprof;
272✔
492
  global_State *g = sp->g;
272✔
493
  struct lj_wbuf *out = &sp->out;
272✔
494

495
  if (SPS_IDLE == sp->state)
272✔
496
    return PROFILE_ERRRUN;
497
  else if (G(L) != g)
12✔
498
    return PROFILE_ERRUSE;
499

500
  lj_profile_timer_stop(&sp->timer);
12✔
501

502
  if (SPS_HALT == sp->state) {
12✔
UNCOV
503
    errno = sp->saved_errno;
×
UNCOV
504
    sp->state = SPS_IDLE;
×
505
    /* wbuf was terminated when error occurred. */
UNCOV
506
    return PROFILE_ERRIO;
×
507
  }
508

509
  sp->state = SPS_IDLE;
12✔
510

511
  if (stream_is_needed(sp)) {
12✔
512
    int cb_status = 0;
6✔
513

514
    stream_epilogue(sp);
6✔
515
    lj_wbuf_flush(out);
6✔
516

517
    cb_status = sp->on_stop(sp->opt.ctx, out->buf);
6✔
518
    if (LJ_UNLIKELY(lj_wbuf_test_flag(out, STREAM_ERRIO | STREAM_STOP)) ||
6✔
519
        cb_status != 0) {
UNCOV
520
      errno = lj_wbuf_errno(out);
×
UNCOV
521
      lj_wbuf_terminate(out);
×
UNCOV
522
      return PROFILE_ERRIO;
×
523
    }
524

525
    lj_wbuf_terminate(out);
6✔
526
  }
527

528
  return PROFILE_SUCCESS;
529
}
530

531
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
5✔
532
{
533
  const struct sysprof *sp = &sysprof;
5✔
534
  if (sp->state != SPS_IDLE)
5✔
535
    return PROFILE_ERRUSE;
536
  memcpy(counters, &sp->counters, sizeof(sp->counters));
5✔
537
  return PROFILE_SUCCESS;
5✔
538
}
539

540
void lj_sysprof_add_proto(const struct GCproto *pt)
57,099✔
541
{
542
  struct sysprof *sp = &sysprof;
57,099✔
543

544
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
57,099✔
545
    return;
546

547
  /*
548
  ** XXX: Avoid sampling during the symtab extension. That shouldn't have any
549
  ** significant effect on profile precision, but if it does, it's better to
550
  ** implement an async-safe queue for the symtab events.
551
  */
UNCOV
552
  sp->state = SPS_IDLE;
×
UNCOV
553
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_LFUNC_EVENT);
×
UNCOV
554
  lj_symtab_dump_proto(&sp->out, pt);
×
UNCOV
555
  sp->state = SPS_PROFILE;
×
556
}
557

558
#if LJ_HASJIT
559
void lj_sysprof_add_trace(const struct GCtrace *tr)
5,145✔
560
{
561
  struct sysprof *sp = &sysprof;
5,145✔
562

563
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
5,145✔
564
    return;
565

566
  /* See the comment about the sysprof state above. */
567
  sp->state = SPS_IDLE;
13✔
568
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_TRACE_EVENT);
13✔
569
  lj_symtab_dump_trace(&sp->out, tr);
13✔
570
  sp->state = SPS_PROFILE;
13✔
571
}
572
#endif /* LJ_HASJIT */
573

574
#else /* LJ_HASSYSPROF */
575

576
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
577
  UNUSED(writer);
578
  return PROFILE_ERRUSE;
579
}
580

581
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
582
  UNUSED(on_stop);
583
  return PROFILE_ERRUSE;
584
}
585

586
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
587
  UNUSED(backtracer);
588
  return PROFILE_ERRUSE;
589
}
590

591
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
592
{
593
  UNUSED(L);
594
  return PROFILE_ERRUSE;
595
}
596

597
int lj_sysprof_stop(lua_State *L)
598
{
599
  UNUSED(L);
600
  return PROFILE_ERRUSE;
601
}
602

603
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
604
{
605
  UNUSED(counters);
606
  return PROFILE_ERRUSE;
607
}
608

609
void lj_sysprof_add_proto(const struct GCproto *pt)
610
{
611
  UNUSED(pt);
612
}
613

614
#if LJ_HASJIT
615
void lj_sysprof_add_trace(const struct GCtrace *tr)
616
{
617
  UNUSED(tr);
618
}
619
#endif /* LJ_HASJIT */
620

621
#endif /* LJ_HASSYSPROF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc