From d8c601cfb92bd6621ee77e1de21d33274bf368f0 Mon Sep 17 00:00:00 2001 From: Georgiy Tugai <3786806+Georgiy-Tugai@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:02:18 +0100 Subject: [PATCH 1/2] add performance tracing to pipeline phases --- distr/flecs.c | 88 ++++++++++++++++++++++++++++++++++ src/addons/pipeline/pipeline.c | 85 ++++++++++++++++++++++++++++++++ src/addons/pipeline/pipeline.h | 3 ++ 3 files changed, 176 insertions(+) diff --git a/distr/flecs.c b/distr/flecs.c index 2688fd0ba5..82b92535d2 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -25348,6 +25348,9 @@ struct ecs_pipeline_state_t { ecs_vec_t ops; /* Pipeline schedule */ ecs_vec_t systems; /* Vector with system ids */ + ecs_vec_t phase_offsets; /* Vector of offsets into phase_names (for perf tracing) */ + ecs_vec_t phase_names; /* Vector with phase names (for perf tracing) */ + ecs_entity_t last_system; /* Last system ran by pipeline */ ecs_id_record_t *idr_inactive; /* Cached record for quick inactive test */ int32_t match_count; /* Used to track of rebuild is necessary */ @@ -52683,6 +52686,17 @@ static void flecs_pipeline_free( ecs_allocator_t *a = &world->allocator; ecs_vec_fini_t(a, &p->ops, ecs_pipeline_op_t); ecs_vec_fini_t(a, &p->systems, ecs_entity_t); + +#ifdef FLECS_PERF_TRACE + ecs_vec_fini_t(a, &p->phase_offsets, int32_t); + int32_t i, count = ecs_vec_count(&p->phase_names); + const char** phase_names = ecs_vec_first_t(&p->phase_names, const char*); + for (i = 0; i < count; i ++) { + ecs_os_free(ECS_CONST_CAST(char*, phase_names[i])); + } + ecs_vec_fini_t(a, &p->phase_names, const char*); +#endif + ecs_os_free(p->iters); ecs_query_fini(p->query); ecs_os_free(p); @@ -52943,6 +52957,14 @@ bool flecs_pipeline_build( ecs_vec_reset_t(a, &pq->ops, ecs_pipeline_op_t); ecs_vec_reset_t(a, &pq->systems, ecs_entity_t); +#ifdef FLECS_PERF_TRACE + ecs_vec_reset_t(a, &pq->phase_offsets, int32_t); + ecs_vec_reset_t(a, &pq->phase_names, const char*); + /* Local map for building up phase_offsets & phase_names */ + ecs_map_t phase_offset_map; + ecs_map_init(&phase_offset_map, a); +#endif + bool multi_threaded = false; bool immediate = false; bool first = true; @@ -52953,6 +52975,23 @@ bool flecs_pipeline_build( bool is_active = ecs_table_get_type_index( world, it.table, EcsEmpty) == -1; +#ifdef FLECS_PERF_TRACE + ecs_entity_t phase = ecs_field_src(&it, 1); + + ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase); + int32_t phase_offset = 0; + if (!phase_offset_p) { + /* New phase, record its name into the name vector */ + phase_offset = ecs_vec_count(&pq->phase_names); + const char* phase_name = ecs_get_path(world, phase); + + ecs_map_insert(&phase_offset_map, phase, (uint64_t)(phase_offset)); + ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name; + } else { + phase_offset = (int32_t)*phase_offset_p; + } +#endif + int32_t i; for (i = 0; i < it.count; i ++) { flecs_poly_assert(poly[i].poly, ecs_system_t); @@ -53026,6 +53065,12 @@ bool flecs_pipeline_build( if (is_active) { ecs_vec_append_t(a, &pq->systems, ecs_entity_t)[0] = it.entities[i]; + +#ifdef FLECS_PERF_TRACE + /* Each system in the systems vector has a corresponding phase offset */ + ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset; +#endif + if (!op->count) { op->multi_threaded = multi_threaded; op->immediate = immediate; @@ -53042,6 +53087,10 @@ bool flecs_pipeline_build( ecs_map_fini(&ws.ids); ecs_map_fini(&ws.wildcard_ids); +#ifdef FLECS_PERF_TRACE + ecs_map_fini(&phase_offset_map); +#endif + op = ecs_vec_first_t(&pq->ops, ecs_pipeline_op_t); if (!op) { @@ -53219,7 +53268,27 @@ int32_t flecs_run_pipeline_ops( ecs_entity_t* systems = ecs_vec_first_t(&pq->systems, ecs_entity_t); int32_t ran_since_merge = i - op->offset; +#ifdef FLECS_PERF_TRACE + int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t); + const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*); +#endif + for (; i < count; i++) { +#ifdef FLECS_PERF_TRACE + if (i > 0) { + int32_t phase = phase_offsets[i]; + int32_t last_phase = phase_offsets[i - 1]; + + if (phase != last_phase) { + /* Close the span of the previous phase and open the current one. + * The first/last phases are handled in flecs_run_pipeline because + * this function may run multiple times during one pipeline. */ + ecs_os_perf_trace_pop(phase_names[last_phase]); + ecs_os_perf_trace_push(phase_names[phase]); + } + } +#endif + ecs_entity_t system = systems[i]; const EcsPoly* poly = ecs_get_pair(world, system, EcsPoly, EcsSystem); flecs_poly_assert(poly->poly, ecs_system_t); @@ -53278,6 +53347,17 @@ void flecs_run_pipeline( // Update the pipeline before waking the workers. flecs_pipeline_update(world, pq, true); +#ifdef FLECS_PERF_TRACE + int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t); + const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*); + + if (phase_offsets && phase_names) { + /* Open the span of the first phase in the pipeline. + * Intermediate phases are handled in flecs_run_pipeline_ops. */ + ecs_os_perf_trace_push(phase_names[phase_offsets[0]]); + } +#endif + // If there are no operations to execute in the pipeline bail early, // no need to wake the workers since they have nothing to do. while (pq->cur_op != NULL) { @@ -53344,6 +53424,14 @@ void flecs_run_pipeline( flecs_pipeline_update(world, pq, false); } + +#ifdef FLECS_PERF_TRACE + if (phase_offsets && phase_names) { + int32_t last_phase_offset = ecs_vec_last_t(&pq->phase_offsets, int32_t)[0]; + /* Close the span of the first phase in the pipeline */ + ecs_os_perf_trace_pop(phase_names[last_phase_offset]); + } +#endif } static diff --git a/src/addons/pipeline/pipeline.c b/src/addons/pipeline/pipeline.c index f28fafc19d..1d141a69d8 100644 --- a/src/addons/pipeline/pipeline.c +++ b/src/addons/pipeline/pipeline.c @@ -17,6 +17,17 @@ static void flecs_pipeline_free( ecs_allocator_t *a = &world->allocator; ecs_vec_fini_t(a, &p->ops, ecs_pipeline_op_t); ecs_vec_fini_t(a, &p->systems, ecs_entity_t); + +#ifdef FLECS_PERF_TRACE + ecs_vec_fini_t(a, &p->phase_offsets, int32_t); + int32_t i, count = ecs_vec_count(&p->phase_names); + const char** phase_names = ecs_vec_first_t(&p->phase_names, const char*); + for (i = 0; i < count; i ++) { + ecs_os_free(ECS_CONST_CAST(char*, phase_names[i])); + } + ecs_vec_fini_t(a, &p->phase_names, const char*); +#endif + ecs_os_free(p->iters); ecs_query_fini(p->query); ecs_os_free(p); @@ -277,6 +288,14 @@ bool flecs_pipeline_build( ecs_vec_reset_t(a, &pq->ops, ecs_pipeline_op_t); ecs_vec_reset_t(a, &pq->systems, ecs_entity_t); +#ifdef FLECS_PERF_TRACE + ecs_vec_reset_t(a, &pq->phase_offsets, int32_t); + ecs_vec_reset_t(a, &pq->phase_names, const char*); + /* Local map for building up phase_offsets & phase_names */ + ecs_map_t phase_offset_map; + ecs_map_init(&phase_offset_map, a); +#endif + bool multi_threaded = false; bool immediate = false; bool first = true; @@ -287,6 +306,23 @@ bool flecs_pipeline_build( bool is_active = ecs_table_get_type_index( world, it.table, EcsEmpty) == -1; +#ifdef FLECS_PERF_TRACE + ecs_entity_t phase = ecs_field_src(&it, 1); + + ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase); + int32_t phase_offset = 0; + if (!phase_offset_p) { + /* New phase, record its name into the name vector */ + phase_offset = ecs_vec_count(&pq->phase_names); + const char* phase_name = ecs_get_path(world, phase); + + ecs_map_insert(&phase_offset_map, phase, (uint64_t)(phase_offset)); + ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name; + } else { + phase_offset = (int32_t)*phase_offset_p; + } +#endif + int32_t i; for (i = 0; i < it.count; i ++) { flecs_poly_assert(poly[i].poly, ecs_system_t); @@ -360,6 +396,12 @@ bool flecs_pipeline_build( if (is_active) { ecs_vec_append_t(a, &pq->systems, ecs_entity_t)[0] = it.entities[i]; + +#ifdef FLECS_PERF_TRACE + /* Each system in the systems vector has a corresponding phase offset */ + ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset; +#endif + if (!op->count) { op->multi_threaded = multi_threaded; op->immediate = immediate; @@ -376,6 +418,10 @@ bool flecs_pipeline_build( ecs_map_fini(&ws.ids); ecs_map_fini(&ws.wildcard_ids); +#ifdef FLECS_PERF_TRACE + ecs_map_fini(&phase_offset_map); +#endif + op = ecs_vec_first_t(&pq->ops, ecs_pipeline_op_t); if (!op) { @@ -553,7 +599,27 @@ int32_t flecs_run_pipeline_ops( ecs_entity_t* systems = ecs_vec_first_t(&pq->systems, ecs_entity_t); int32_t ran_since_merge = i - op->offset; +#ifdef FLECS_PERF_TRACE + int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t); + const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*); +#endif + for (; i < count; i++) { +#ifdef FLECS_PERF_TRACE + if (i > 0) { + int32_t phase = phase_offsets[i]; + int32_t last_phase = phase_offsets[i - 1]; + + if (phase != last_phase) { + /* Close the span of the previous phase and open the current one. + * The first/last phases are handled in flecs_run_pipeline because + * this function may run multiple times during one pipeline. */ + ecs_os_perf_trace_pop(phase_names[last_phase]); + ecs_os_perf_trace_push(phase_names[phase]); + } + } +#endif + ecs_entity_t system = systems[i]; const EcsPoly* poly = ecs_get_pair(world, system, EcsPoly, EcsSystem); flecs_poly_assert(poly->poly, ecs_system_t); @@ -612,6 +678,17 @@ void flecs_run_pipeline( // Update the pipeline before waking the workers. flecs_pipeline_update(world, pq, true); +#ifdef FLECS_PERF_TRACE + int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t); + const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*); + + if (phase_offsets && phase_names) { + /* Open the span of the first phase in the pipeline. + * Intermediate phases are handled in flecs_run_pipeline_ops. */ + ecs_os_perf_trace_push(phase_names[phase_offsets[0]]); + } +#endif + // If there are no operations to execute in the pipeline bail early, // no need to wake the workers since they have nothing to do. while (pq->cur_op != NULL) { @@ -678,6 +755,14 @@ void flecs_run_pipeline( flecs_pipeline_update(world, pq, false); } + +#ifdef FLECS_PERF_TRACE + if (phase_offsets && phase_names) { + int32_t last_phase_offset = ecs_vec_last_t(&pq->phase_offsets, int32_t)[0]; + /* Close the span of the first phase in the pipeline */ + ecs_os_perf_trace_pop(phase_names[last_phase_offset]); + } +#endif } static diff --git a/src/addons/pipeline/pipeline.h b/src/addons/pipeline/pipeline.h index 12aa8bb209..7ae50327cc 100644 --- a/src/addons/pipeline/pipeline.h +++ b/src/addons/pipeline/pipeline.h @@ -24,6 +24,9 @@ struct ecs_pipeline_state_t { ecs_vec_t ops; /* Pipeline schedule */ ecs_vec_t systems; /* Vector with system ids */ + ecs_vec_t phase_offsets; /* Vector of offsets into phase_names (for perf tracing) */ + ecs_vec_t phase_names; /* Vector with phase names (for perf tracing) */ + ecs_entity_t last_system; /* Last system ran by pipeline */ ecs_id_record_t *idr_inactive; /* Cached record for quick inactive test */ int32_t match_count; /* Used to track of rebuild is necessary */ From 13c2d0decb6835060ffeafe337aaf1f3748b9c77 Mon Sep 17 00:00:00 2001 From: Georgiy Tugai <3786806+Georgiy-Tugai@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:36:17 +0100 Subject: [PATCH 2/2] generalize performance tracing pipeline "phase" concept --- distr/flecs.c | 65 +++++++++++++++++++-------------- distr/flecs.h | 6 +++ include/flecs/addons/pipeline.h | 6 +++ src/addons/pipeline/pipeline.c | 63 ++++++++++++++++++-------------- src/addons/pipeline/pipeline.h | 2 + 5 files changed, 88 insertions(+), 54 deletions(-) diff --git a/distr/flecs.c b/distr/flecs.c index 82b92535d2..b2c4e0d765 100644 --- a/distr/flecs.c +++ b/distr/flecs.c @@ -25358,6 +25358,8 @@ struct ecs_pipeline_state_t { ecs_iter_t *iters; /* Iterator for worker(s) */ int32_t iter_count; + int8_t query_phase_term; /* Pipeline query phase term if != 0 (for perf tracing) */ + /* Members for continuing pipeline iteration after pipeline rebuild */ ecs_pipeline_op_t *cur_op; /* Current pipeline op */ int32_t cur_i; /* Index in current result */ @@ -52976,19 +52978,21 @@ bool flecs_pipeline_build( world, it.table, EcsEmpty) == -1; #ifdef FLECS_PERF_TRACE - ecs_entity_t phase = ecs_field_src(&it, 1); - - ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase); int32_t phase_offset = 0; - if (!phase_offset_p) { - /* New phase, record its name into the name vector */ - phase_offset = ecs_vec_count(&pq->phase_names); - const char* phase_name = ecs_get_path(world, phase); + if (pq->query_phase_term) { + ecs_entity_t phase = ecs_field_src(&it, pq->query_phase_term); - ecs_map_insert(&phase_offset_map, phase, (uint64_t)(phase_offset)); - ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name; - } else { - phase_offset = (int32_t)*phase_offset_p; + ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase); + if (!phase_offset_p) { + /* New phase, record its name into the name vector */ + phase_offset = ecs_vec_count(&pq->phase_names); + const char* phase_name = ecs_get_path(world, phase); + + ecs_map_insert(&phase_offset_map, phase, (uint64_t)(phase_offset)); + ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name; + } else { + phase_offset = (int32_t)*phase_offset_p; + } } #endif @@ -53067,8 +53071,10 @@ bool flecs_pipeline_build( it.entities[i]; #ifdef FLECS_PERF_TRACE - /* Each system in the systems vector has a corresponding phase offset */ - ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset; + if (pq->query_phase_term) { + /* Each system in the systems vector has a corresponding phase offset */ + ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset; + } #endif if (!op->count) { @@ -53275,16 +53281,18 @@ int32_t flecs_run_pipeline_ops( for (; i < count; i++) { #ifdef FLECS_PERF_TRACE - if (i > 0) { - int32_t phase = phase_offsets[i]; - int32_t last_phase = phase_offsets[i - 1]; - - if (phase != last_phase) { - /* Close the span of the previous phase and open the current one. - * The first/last phases are handled in flecs_run_pipeline because - * this function may run multiple times during one pipeline. */ - ecs_os_perf_trace_pop(phase_names[last_phase]); - ecs_os_perf_trace_push(phase_names[phase]); + if (pq->query_phase_term) { + if (i > 0) { + int32_t phase = phase_offsets[i]; + int32_t last_phase = phase_offsets[i - 1]; + + if (phase != last_phase) { + /* Close the span of the previous phase and open the current one. + * The first/last phases are handled in flecs_run_pipeline because + * this function may run multiple times during one pipeline. */ + ecs_os_perf_trace_pop(phase_names[last_phase]); + ecs_os_perf_trace_push(phase_names[phase]); + } } } #endif @@ -53351,7 +53359,7 @@ void flecs_run_pipeline( int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t); const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*); - if (phase_offsets && phase_names) { + if (pq->query_phase_term && phase_offsets && phase_names) { /* Open the span of the first phase in the pipeline. * Intermediate phases are handled in flecs_run_pipeline_ops. */ ecs_os_perf_trace_push(phase_names[phase_offsets[0]]); @@ -53426,7 +53434,7 @@ void flecs_run_pipeline( } #ifdef FLECS_PERF_TRACE - if (phase_offsets && phase_names) { + if (pq->query_phase_term && phase_offsets && phase_names) { int32_t last_phase_offset = ecs_vec_last_t(&pq->phase_offsets, int32_t)[0]; /* Close the span of the first phase in the pipeline */ ecs_os_perf_trace_pop(phase_names[last_phase_offset]); @@ -53465,7 +53473,8 @@ void flecs_run_startup_systems( { .id = EcsDisabled, .src.id = EcsUp, .trav = EcsChildOf, .oper = EcsNot } }, .order_by_callback = flecs_entity_compare - } + }, + .query_phase_term = 1, }); ecs_log_pop_2(); @@ -53595,6 +53604,7 @@ ecs_entity_t ecs_pipeline_init( ecs_pipeline_state_t *pq = ecs_os_calloc_t(ecs_pipeline_state_t); pq->query = query; + pq->query_phase_term = desc->query_phase_term; pq->match_count = -1; pq->idr_inactive = flecs_id_record_ensure(world, EcsEmpty); ecs_set(world, result, EcsPipeline, { pq }); @@ -53692,7 +53702,8 @@ void FlecsPipelineImport( { .id = EcsDisabled, .src.id = EcsUp, .trav = EcsChildOf, .oper = EcsNot } }, .order_by_callback = flecs_entity_compare - } + }, + .query_phase_term = 1, }); /* Cleanup thread administration when world is destroyed */ diff --git a/distr/flecs.h b/distr/flecs.h index 75eb41798a..e40ff96037 100644 --- a/distr/flecs.h +++ b/distr/flecs.h @@ -11921,6 +11921,12 @@ typedef struct ecs_pipeline_desc_t { * pipeline query works. */ ecs_query_desc_t query; + + /** The pipeline query's phase term (optional). + * If non-zero, the source entity of this term will be considered a "phase" + * for the purposes of performance tracing. + */ + int8_t query_phase_term; } ecs_pipeline_desc_t; /** Create a custom pipeline. diff --git a/include/flecs/addons/pipeline.h b/include/flecs/addons/pipeline.h index 02106b7dca..931607aef2 100644 --- a/include/flecs/addons/pipeline.h +++ b/include/flecs/addons/pipeline.h @@ -113,6 +113,12 @@ typedef struct ecs_pipeline_desc_t { * pipeline query works. */ ecs_query_desc_t query; + + /** The pipeline query's phase term (optional). + * If non-zero, the source entity of this term will be considered a "phase" + * for the purposes of performance tracing. + */ + int8_t query_phase_term; } ecs_pipeline_desc_t; /** Create a custom pipeline. diff --git a/src/addons/pipeline/pipeline.c b/src/addons/pipeline/pipeline.c index 1d141a69d8..7d1fc0f3db 100644 --- a/src/addons/pipeline/pipeline.c +++ b/src/addons/pipeline/pipeline.c @@ -307,19 +307,21 @@ bool flecs_pipeline_build( world, it.table, EcsEmpty) == -1; #ifdef FLECS_PERF_TRACE - ecs_entity_t phase = ecs_field_src(&it, 1); - - ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase); int32_t phase_offset = 0; - if (!phase_offset_p) { - /* New phase, record its name into the name vector */ - phase_offset = ecs_vec_count(&pq->phase_names); - const char* phase_name = ecs_get_path(world, phase); + if (pq->query_phase_term) { + ecs_entity_t phase = ecs_field_src(&it, pq->query_phase_term); - ecs_map_insert(&phase_offset_map, phase, (uint64_t)(phase_offset)); - ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name; - } else { - phase_offset = (int32_t)*phase_offset_p; + ecs_map_val_t* phase_offset_p = ecs_map_get(&phase_offset_map, phase); + if (!phase_offset_p) { + /* New phase, record its name into the name vector */ + phase_offset = ecs_vec_count(&pq->phase_names); + const char* phase_name = ecs_get_path(world, phase); + + ecs_map_insert(&phase_offset_map, phase, (uint64_t)(phase_offset)); + ecs_vec_append_t(a, &pq->phase_names, const char*)[0] = phase_name; + } else { + phase_offset = (int32_t)*phase_offset_p; + } } #endif @@ -398,8 +400,10 @@ bool flecs_pipeline_build( it.entities[i]; #ifdef FLECS_PERF_TRACE - /* Each system in the systems vector has a corresponding phase offset */ - ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset; + if (pq->query_phase_term) { + /* Each system in the systems vector has a corresponding phase offset */ + ecs_vec_append_t(a, &pq->phase_offsets, int32_t)[0] = phase_offset; + } #endif if (!op->count) { @@ -606,16 +610,18 @@ int32_t flecs_run_pipeline_ops( for (; i < count; i++) { #ifdef FLECS_PERF_TRACE - if (i > 0) { - int32_t phase = phase_offsets[i]; - int32_t last_phase = phase_offsets[i - 1]; - - if (phase != last_phase) { - /* Close the span of the previous phase and open the current one. - * The first/last phases are handled in flecs_run_pipeline because - * this function may run multiple times during one pipeline. */ - ecs_os_perf_trace_pop(phase_names[last_phase]); - ecs_os_perf_trace_push(phase_names[phase]); + if (pq->query_phase_term) { + if (i > 0) { + int32_t phase = phase_offsets[i]; + int32_t last_phase = phase_offsets[i - 1]; + + if (phase != last_phase) { + /* Close the span of the previous phase and open the current one. + * The first/last phases are handled in flecs_run_pipeline because + * this function may run multiple times during one pipeline. */ + ecs_os_perf_trace_pop(phase_names[last_phase]); + ecs_os_perf_trace_push(phase_names[phase]); + } } } #endif @@ -682,7 +688,7 @@ void flecs_run_pipeline( int32_t* phase_offsets = ecs_vec_first_t(&pq->phase_offsets, int32_t); const char** phase_names = ecs_vec_first_t(&pq->phase_names, const char*); - if (phase_offsets && phase_names) { + if (pq->query_phase_term && phase_offsets && phase_names) { /* Open the span of the first phase in the pipeline. * Intermediate phases are handled in flecs_run_pipeline_ops. */ ecs_os_perf_trace_push(phase_names[phase_offsets[0]]); @@ -757,7 +763,7 @@ void flecs_run_pipeline( } #ifdef FLECS_PERF_TRACE - if (phase_offsets && phase_names) { + if (pq->query_phase_term && phase_offsets && phase_names) { int32_t last_phase_offset = ecs_vec_last_t(&pq->phase_offsets, int32_t)[0]; /* Close the span of the first phase in the pipeline */ ecs_os_perf_trace_pop(phase_names[last_phase_offset]); @@ -796,7 +802,8 @@ void flecs_run_startup_systems( { .id = EcsDisabled, .src.id = EcsUp, .trav = EcsChildOf, .oper = EcsNot } }, .order_by_callback = flecs_entity_compare - } + }, + .query_phase_term = 1, }); ecs_log_pop_2(); @@ -926,6 +933,7 @@ ecs_entity_t ecs_pipeline_init( ecs_pipeline_state_t *pq = ecs_os_calloc_t(ecs_pipeline_state_t); pq->query = query; + pq->query_phase_term = desc->query_phase_term; pq->match_count = -1; pq->idr_inactive = flecs_id_record_ensure(world, EcsEmpty); ecs_set(world, result, EcsPipeline, { pq }); @@ -1023,7 +1031,8 @@ void FlecsPipelineImport( { .id = EcsDisabled, .src.id = EcsUp, .trav = EcsChildOf, .oper = EcsNot } }, .order_by_callback = flecs_entity_compare - } + }, + .query_phase_term = 1, }); /* Cleanup thread administration when world is destroyed */ diff --git a/src/addons/pipeline/pipeline.h b/src/addons/pipeline/pipeline.h index 7ae50327cc..9f109c0fda 100644 --- a/src/addons/pipeline/pipeline.h +++ b/src/addons/pipeline/pipeline.h @@ -34,6 +34,8 @@ struct ecs_pipeline_state_t { ecs_iter_t *iters; /* Iterator for worker(s) */ int32_t iter_count; + int8_t query_phase_term; /* Pipeline query phase term if != 0 (for perf tracing) */ + /* Members for continuing pipeline iteration after pipeline rebuild */ ecs_pipeline_op_t *cur_op; /* Current pipeline op */ int32_t cur_i; /* Index in current result */