Skip to content

Commit d705e30

Browse files
committed
add performance tracing to pipeline stages
1 parent 08da32a commit d705e30

3 files changed

Lines changed: 176 additions & 0 deletions

File tree

distr/flecs.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25308,6 +25308,9 @@ struct ecs_pipeline_state_t {
2530825308
ecs_vec_t ops; /* Pipeline schedule */
2530925309
ecs_vec_t systems; /* Vector with system ids */
2531025310

25311+
ecs_vec_t phase_offsets; /* Vector of offsets into phase_names (for perf tracing) */
25312+
ecs_vec_t phase_names; /* Vector with phase names (for perf tracing) */
25313+
2531125314
ecs_entity_t last_system; /* Last system ran by pipeline */
2531225315
ecs_id_record_t *idr_inactive; /* Cached record for quick inactive test */
2531325316
int32_t match_count; /* Used to track of rebuild is necessary */
@@ -52630,6 +52633,17 @@ static void flecs_pipeline_free(
5263052633
ecs_allocator_t *a = &world->allocator;
5263152634
ecs_vec_fini_t(a, &p->ops, ecs_pipeline_op_t);
5263252635
ecs_vec_fini_t(a, &p->systems, ecs_entity_t);
52636+
52637+
#ifdef FLECS_PERF_TRACE
52638+
ecs_vec_fini_t(a, &p->phase_offsets, int32_t);
52639+
int32_t i, count = ecs_vec_count(&p->phase_names);
52640+
const char** phase_names = ecs_vec_first_t(&p->phase_names, const char*);
52641+
for (i = 0; i < count; i ++) {
52642+
ecs_os_free(ECS_CONST_CAST(char*, phase_names[i]));
52643+
}
52644+
ecs_vec_fini_t(a, &p->phase_names, const char*);
52645+
#endif
52646+
5263352647
ecs_os_free(p->iters);
5263452648
ecs_query_fini(p->query);
5263552649
ecs_os_free(p);
@@ -52890,6 +52904,14 @@ bool flecs_pipeline_build(
5289052904
ecs_vec_reset_t(a, &pq->ops, ecs_pipeline_op_t);
5289152905
ecs_vec_reset_t(a, &pq->systems, ecs_entity_t);
5289252906

52907+
#ifdef FLECS_PERF_TRACE
52908+
ecs_vec_reset_t(a, &pq->phase_offsets, int32_t);
52909+
ecs_vec_reset_t(a, &pq->phase_names, const char*);
52910+
/* Local map for building up phase_offsets & phase_names */
52911+
ecs_map_t phase_offset_map;
52912+
ecs_map_init(&phase_offset_map, a);
52913+
#endif
52914+
5289352915
bool multi_threaded = false;
5289452916
bool immediate = false;
5289552917
bool first = true;
@@ -52900,6 +52922,23 @@ bool flecs_pipeline_build(
5290052922
bool is_active = ecs_table_get_type_index(
5290152923
world, it.table, EcsEmpty) == -1;
5290252924

52925+
#ifdef FLECS_PERF_TRACE
52926+
ecs_entity_t phase = ecs_field_src(&it, 1);
52927+
52928+
ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase);
52929+
int32_t phase_offset = 0;
52930+
if (!phase_offset_p) {
52931+
/* New phase, record its name into the name vector */
52932+
phase_offset = ecs_vec_count(&pq->phase_names);
52933+
const char* phase_name = ecs_get_path(world, phase);
52934+
52935+
ecs_map_insert(&phase_offset_map, phase, (int64_t)(phase_offset));
52936+
ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name;
52937+
} else {
52938+
phase_offset = (int64_t)*phase_offset_p;
52939+
}
52940+
#endif
52941+
5290352942
int32_t i;
5290452943
for (i = 0; i < it.count; i ++) {
5290552944
flecs_poly_assert(poly[i].poly, ecs_system_t);
@@ -52973,6 +53012,12 @@ bool flecs_pipeline_build(
5297353012
if (is_active) {
5297453013
ecs_vec_append_t(a, &pq->systems, ecs_entity_t)[0] =
5297553014
it.entities[i];
53015+
53016+
#ifdef FLECS_PERF_TRACE
53017+
/* Each system in the systems vector has a corresponding phase offset */
53018+
ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset;
53019+
#endif
53020+
5297653021
if (!op->count) {
5297753022
op->multi_threaded = multi_threaded;
5297853023
op->immediate = immediate;
@@ -52989,6 +53034,10 @@ bool flecs_pipeline_build(
5298953034
ecs_map_fini(&ws.ids);
5299053035
ecs_map_fini(&ws.wildcard_ids);
5299153036

53037+
#ifdef FLECS_PERF_TRACE
53038+
ecs_map_fini(&phase_offset_map);
53039+
#endif
53040+
5299253041
op = ecs_vec_first_t(&pq->ops, ecs_pipeline_op_t);
5299353042

5299453043
if (!op) {
@@ -53166,7 +53215,27 @@ int32_t flecs_run_pipeline_ops(
5316653215
ecs_entity_t* systems = ecs_vec_first_t(&pq->systems, ecs_entity_t);
5316753216
int32_t ran_since_merge = i - op->offset;
5316853217

53218+
#ifdef FLECS_PERF_TRACE
53219+
int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t);
53220+
const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*);
53221+
#endif
53222+
5316953223
for (; i < count; i++) {
53224+
#ifdef FLECS_PERF_TRACE
53225+
if (i > 0) {
53226+
int32_t phase = phase_offsets[i];
53227+
int32_t last_phase = phase_offsets[i - 1];
53228+
53229+
if (phase != last_phase) {
53230+
/* Close the span of the previous phase and open the current one.
53231+
* The first/last phases are handled in flecs_run_pipeline because
53232+
* this function may run multiple times during one pipeline. */
53233+
ecs_os_perf_trace_pop(phase_names[last_phase]);
53234+
ecs_os_perf_trace_push(phase_names[phase]);
53235+
}
53236+
}
53237+
#endif
53238+
5317053239
ecs_entity_t system = systems[i];
5317153240
const EcsPoly* poly = ecs_get_pair(world, system, EcsPoly, EcsSystem);
5317253241
flecs_poly_assert(poly->poly, ecs_system_t);
@@ -53225,6 +53294,17 @@ void flecs_run_pipeline(
5322553294
// Update the pipeline before waking the workers.
5322653295
flecs_pipeline_update(world, pq, true);
5322753296

53297+
#ifdef FLECS_PERF_TRACE
53298+
int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t);
53299+
const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*);
53300+
53301+
if (phase_offsets && phase_names) {
53302+
/* Open the span of the first phase in the pipeline.
53303+
* Intermediate phases are handled in flecs_run_pipeline_ops. */
53304+
ecs_os_perf_trace_push(phase_names[phase_offsets[0]]);
53305+
}
53306+
#endif
53307+
5322853308
// If there are no operations to execute in the pipeline bail early,
5322953309
// no need to wake the workers since they have nothing to do.
5323053310
while (pq->cur_op != NULL) {
@@ -53291,6 +53371,14 @@ void flecs_run_pipeline(
5329153371

5329253372
flecs_pipeline_update(world, pq, false);
5329353373
}
53374+
53375+
#ifdef FLECS_PERF_TRACE
53376+
if (phase_offsets && phase_names) {
53377+
int32_t last_phase_offset = ecs_vec_last_t(&pq->phase_offsets, int32_t)[0];
53378+
/* Close the span of the first phase in the pipeline */
53379+
ecs_os_perf_trace_pop(phase_names[last_phase_offset]);
53380+
}
53381+
#endif
5329453382
}
5329553383

5329653384
static

src/addons/pipeline/pipeline.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ static void flecs_pipeline_free(
1717
ecs_allocator_t *a = &world->allocator;
1818
ecs_vec_fini_t(a, &p->ops, ecs_pipeline_op_t);
1919
ecs_vec_fini_t(a, &p->systems, ecs_entity_t);
20+
21+
#ifdef FLECS_PERF_TRACE
22+
ecs_vec_fini_t(a, &p->phase_offsets, int32_t);
23+
int32_t i, count = ecs_vec_count(&p->phase_names);
24+
const char** phase_names = ecs_vec_first_t(&p->phase_names, const char*);
25+
for (i = 0; i < count; i ++) {
26+
ecs_os_free(ECS_CONST_CAST(char*, phase_names[i]));
27+
}
28+
ecs_vec_fini_t(a, &p->phase_names, const char*);
29+
#endif
30+
2031
ecs_os_free(p->iters);
2132
ecs_query_fini(p->query);
2233
ecs_os_free(p);
@@ -277,6 +288,14 @@ bool flecs_pipeline_build(
277288
ecs_vec_reset_t(a, &pq->ops, ecs_pipeline_op_t);
278289
ecs_vec_reset_t(a, &pq->systems, ecs_entity_t);
279290

291+
#ifdef FLECS_PERF_TRACE
292+
ecs_vec_reset_t(a, &pq->phase_offsets, int32_t);
293+
ecs_vec_reset_t(a, &pq->phase_names, const char*);
294+
/* Local map for building up phase_offsets & phase_names */
295+
ecs_map_t phase_offset_map;
296+
ecs_map_init(&phase_offset_map, a);
297+
#endif
298+
280299
bool multi_threaded = false;
281300
bool immediate = false;
282301
bool first = true;
@@ -287,6 +306,23 @@ bool flecs_pipeline_build(
287306
bool is_active = ecs_table_get_type_index(
288307
world, it.table, EcsEmpty) == -1;
289308

309+
#ifdef FLECS_PERF_TRACE
310+
ecs_entity_t phase = ecs_field_src(&it, 1);
311+
312+
ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase);
313+
int32_t phase_offset = 0;
314+
if (!phase_offset_p) {
315+
/* New phase, record its name into the name vector */
316+
phase_offset = ecs_vec_count(&pq->phase_names);
317+
const char* phase_name = ecs_get_path(world, phase);
318+
319+
ecs_map_insert(&phase_offset_map, phase, (int64_t)(phase_offset));
320+
ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name;
321+
} else {
322+
phase_offset = (int64_t)*phase_offset_p;
323+
}
324+
#endif
325+
290326
int32_t i;
291327
for (i = 0; i < it.count; i ++) {
292328
flecs_poly_assert(poly[i].poly, ecs_system_t);
@@ -360,6 +396,12 @@ bool flecs_pipeline_build(
360396
if (is_active) {
361397
ecs_vec_append_t(a, &pq->systems, ecs_entity_t)[0] =
362398
it.entities[i];
399+
400+
#ifdef FLECS_PERF_TRACE
401+
/* Each system in the systems vector has a corresponding phase offset */
402+
ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset;
403+
#endif
404+
363405
if (!op->count) {
364406
op->multi_threaded = multi_threaded;
365407
op->immediate = immediate;
@@ -376,6 +418,10 @@ bool flecs_pipeline_build(
376418
ecs_map_fini(&ws.ids);
377419
ecs_map_fini(&ws.wildcard_ids);
378420

421+
#ifdef FLECS_PERF_TRACE
422+
ecs_map_fini(&phase_offset_map);
423+
#endif
424+
379425
op = ecs_vec_first_t(&pq->ops, ecs_pipeline_op_t);
380426

381427
if (!op) {
@@ -553,7 +599,27 @@ int32_t flecs_run_pipeline_ops(
553599
ecs_entity_t* systems = ecs_vec_first_t(&pq->systems, ecs_entity_t);
554600
int32_t ran_since_merge = i - op->offset;
555601

602+
#ifdef FLECS_PERF_TRACE
603+
int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t);
604+
const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*);
605+
#endif
606+
556607
for (; i < count; i++) {
608+
#ifdef FLECS_PERF_TRACE
609+
if (i > 0) {
610+
int32_t phase = phase_offsets[i];
611+
int32_t last_phase = phase_offsets[i - 1];
612+
613+
if (phase != last_phase) {
614+
/* Close the span of the previous phase and open the current one.
615+
* The first/last phases are handled in flecs_run_pipeline because
616+
* this function may run multiple times during one pipeline. */
617+
ecs_os_perf_trace_pop(phase_names[last_phase]);
618+
ecs_os_perf_trace_push(phase_names[phase]);
619+
}
620+
}
621+
#endif
622+
557623
ecs_entity_t system = systems[i];
558624
const EcsPoly* poly = ecs_get_pair(world, system, EcsPoly, EcsSystem);
559625
flecs_poly_assert(poly->poly, ecs_system_t);
@@ -612,6 +678,17 @@ void flecs_run_pipeline(
612678
// Update the pipeline before waking the workers.
613679
flecs_pipeline_update(world, pq, true);
614680

681+
#ifdef FLECS_PERF_TRACE
682+
int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t);
683+
const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*);
684+
685+
if (phase_offsets && phase_names) {
686+
/* Open the span of the first phase in the pipeline.
687+
* Intermediate phases are handled in flecs_run_pipeline_ops. */
688+
ecs_os_perf_trace_push(phase_names[phase_offsets[0]]);
689+
}
690+
#endif
691+
615692
// If there are no operations to execute in the pipeline bail early,
616693
// no need to wake the workers since they have nothing to do.
617694
while (pq->cur_op != NULL) {
@@ -678,6 +755,14 @@ void flecs_run_pipeline(
678755

679756
flecs_pipeline_update(world, pq, false);
680757
}
758+
759+
#ifdef FLECS_PERF_TRACE
760+
if (phase_offsets && phase_names) {
761+
int32_t last_phase_offset = ecs_vec_last_t(&pq->phase_offsets, int32_t)[0];
762+
/* Close the span of the first phase in the pipeline */
763+
ecs_os_perf_trace_pop(phase_names[last_phase_offset]);
764+
}
765+
#endif
681766
}
682767

683768
static

src/addons/pipeline/pipeline.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ struct ecs_pipeline_state_t {
2424
ecs_vec_t ops; /* Pipeline schedule */
2525
ecs_vec_t systems; /* Vector with system ids */
2626

27+
ecs_vec_t phase_offsets; /* Vector of offsets into phase_names (for perf tracing) */
28+
ecs_vec_t phase_names; /* Vector with phase names (for perf tracing) */
29+
2730
ecs_entity_t last_system; /* Last system ran by pipeline */
2831
ecs_id_record_t *idr_inactive; /* Cached record for quick inactive test */
2932
int32_t match_count; /* Used to track of rebuild is necessary */

0 commit comments

Comments
 (0)