diff --git a/src/modules/module-profiler.c b/src/modules/module-profiler.c index 5f084af8a..53c656a66 100644 --- a/src/modules/module-profiler.c +++ b/src/modules/module-profiler.c @@ -71,6 +71,16 @@ static const struct spa_dict_item module_props[] = { { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; +struct node { + struct spa_list link; + struct impl *impl; + + struct pw_impl_node *node; + struct spa_hook node_rt_listener; + + unsigned enabled:1; +}; + struct impl { struct pw_context *context; struct pw_properties *properties; @@ -84,6 +94,8 @@ struct impl { struct pw_global *global; struct spa_hook global_listener; + struct spa_list node_list; + int64_t count; uint32_t busy; uint32_t empty; @@ -94,7 +106,6 @@ struct impl { struct spa_ringbuffer buffer; uint8_t tmp[TMP_BUFFER]; uint8_t data[MAX_BUFFER]; - uint8_t flush[MAX_BUFFER + sizeof(struct spa_pod_struct)]; }; @@ -278,15 +289,88 @@ done: impl->count++; } +static void node_complete(void *data) +{ + struct node *n = data; + pw_log_info("complete"); + context_do_profile(n->impl, n->node); +} + +static struct pw_impl_node_rt_events node_rt_events = { + PW_VERSION_IMPL_NODE_RT_EVENTS, + .complete = node_complete, +}; + +static void enable_node_profiling(struct node *n, bool enabled) +{ + if (enabled && !n->enabled) { + SPA_FLAG_SET(n->node->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER); + pw_impl_node_add_rt_listener(n->node, &n->node_rt_listener, &node_rt_events, n); + } else if (!enabled && n->enabled) { + SPA_FLAG_CLEAR(n->node->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER); + pw_impl_node_remove_rt_listener(n->node, &n->node_rt_listener); + } + n->enabled = enabled; +} + +static void enable_profiling(struct impl *impl, bool enabled) +{ + struct node *n; + spa_list_for_each(n, &impl->node_list, link) + enable_node_profiling(n, enabled); +} + +static void context_driver_added(void *data, struct pw_impl_node *node) +{ + struct impl *impl = data; + struct node *n; + + n = calloc(1, sizeof(*n)); + if (n == NULL) + return; + + n->impl = impl; + n->node = node; + spa_list_append(&impl->node_list, &n->link); + + if (impl->busy > 0) + enable_node_profiling(n, true); +} + +static struct node *find_node(struct impl *impl, struct pw_impl_node *node) +{ + struct node *n; + spa_list_for_each(n, &impl->node_list, link) { + if (n->node == node) + return n; + } + return NULL; +} + +static void context_driver_removed(void *data, struct pw_impl_node *node) +{ + struct impl *impl = data; + struct node *n; + + n = find_node(impl, node); + if (n == NULL) + return; + + enable_node_profiling(n, false); + spa_list_remove(&n->link); + free(n); +} + static const struct pw_context_events context_events = { PW_VERSION_CONTEXT_EVENTS, - .profiler = context_do_profile, + .driver_added = context_driver_added, + .driver_removed = context_driver_removed, }; static void stop_listener(struct impl *impl) { if (impl->listening) { - pw_context_stop_profiler(impl->context); + enable_profiling(impl, false); impl->listening = false; } } @@ -329,7 +413,7 @@ global_bind(void *object, struct pw_impl_client *client, uint32_t permissions, if (++impl->busy == 1) { pw_log_info("%p: starting profiler", impl); - pw_context_start_profiler(impl->context); + enable_profiling(impl, true); impl->listening = true; } return 0; @@ -390,6 +474,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) if (impl == NULL) return -errno; + spa_list_init(&impl->node_list); pw_protocol_native_ext_profiler_init(context); pw_log_debug("module %p: new %s", impl, args); diff --git a/src/pipewire/context.c b/src/pipewire/context.c index fec6f634c..8f9745b3f 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -479,53 +479,6 @@ void pw_context_add_listener(struct pw_context *context, spa_hook_list_append(&context->listener_list, listener, events, data); } -static void node_complete(void *data) -{ - struct pw_impl_node *node = data; - pw_log_info("complete"); - pw_context_emit_profiler(node->context, node); -} - -static struct pw_impl_node_rt_events node_rt_events = { - PW_VERSION_IMPL_NODE_RT_EVENTS, - .complete = node_complete, -}; - -SPA_EXPORT -void pw_context_start_profiler(struct pw_context *context) -{ - struct pw_impl_node *n; - - pw_log_info("%d", context->profiling); - if (context->profiling++ > 0) - return; - - spa_list_for_each(n, &context->driver_list, driver_link) { - if (SPA_FLAG_IS_SET(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER)) - continue; - - SPA_FLAG_SET(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER); - pw_impl_node_add_rt_listener(n, &n->profiler_listener, &node_rt_events, n); - } -} - -SPA_EXPORT -void pw_context_stop_profiler(struct pw_context *context) -{ - struct pw_impl_node *n; - - pw_log_info("%d", context->profiling); - if (--context->profiling > 0) - return; - - spa_list_for_each(n, &context->driver_list, driver_link) { - if (!SPA_FLAG_IS_SET(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER)) - continue; - SPA_FLAG_CLEAR(n->rt.target.activation->flags, PW_NODE_ACTIVATION_FLAG_PROFILER); - pw_impl_node_remove_rt_listener(n, &n->profiler_listener); - } -} - SPA_EXPORT const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support) { diff --git a/src/pipewire/context.h b/src/pipewire/context.h index 5c4386728..c13dc8093 100644 --- a/src/pipewire/context.h +++ b/src/pipewire/context.h @@ -64,8 +64,11 @@ struct pw_context_events { void (*global_added) (void *data, struct pw_global *global); /** a global object was removed */ void (*global_removed) (void *data, struct pw_global *global); - /** a driver completed */ - void (*profiler) (void *data, struct pw_impl_node *node); + + /** a driver was added */ + void (*driver_added) (void *data, struct pw_impl_node *node); + /** a driver was removed */ + void (*driver_removed) (void *data, struct pw_impl_node *node); }; /** Make a new context object for a given main_loop. Ownership of the properties is taken */ @@ -171,11 +174,6 @@ int pw_context_set_object(struct pw_context *context, const char *type, void *va /** get an object from the context */ void *pw_context_get_object(struct pw_context *context, const char *type); -/** start the profiler, driver_completed events will be emited */ -void pw_context_start_profiler(struct pw_context *context); -/** stop the profiler */ -void pw_context_stop_profiler(struct pw_context *context); - /** * \} */ diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index ecf343bb5..87d860cb0 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -698,6 +698,13 @@ static inline void insert_driver(struct pw_context *context, struct pw_impl_node break; } spa_list_append(&n->driver_link, &node->driver_link); + pw_context_emit_driver_added(context, node); +} + +static inline void remove_driver(struct pw_context *context, struct pw_impl_node *node) +{ + spa_list_remove(&node->driver_link); + pw_context_emit_driver_removed(context, node); } static void update_io(struct pw_impl_node *node) @@ -941,8 +948,9 @@ static void check_properties(struct pw_impl_node *node) if (node->registered) { if (driver) insert_driver(context, node); - else - spa_list_remove(&node->driver_link); + else { + remove_driver(context, node); + } } if (driver && node->driver_node == node) node->driving = true; @@ -2044,7 +2052,7 @@ void pw_impl_node_destroy(struct pw_impl_node *node) if (node->registered) { spa_list_remove(&node->link); if (node->driver) - spa_list_remove(&node->driver_link); + remove_driver(context, node); } if (node->node) { diff --git a/src/pipewire/private.h b/src/pipewire/private.h index e53b4065a..7b0c584a3 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -371,7 +371,8 @@ int pw_loop_check(struct pw_loop *loop); #define pw_context_emit_check_access(c,cl) pw_context_emit(c, check_access, 0, cl) #define pw_context_emit_global_added(c,g) pw_context_emit(c, global_added, 0, g) #define pw_context_emit_global_removed(c,g) pw_context_emit(c, global_removed, 0, g) -#define pw_context_emit_profiler(c,n) pw_context_emit(c, profiler, 1, n) +#define pw_context_emit_driver_added(c,n) pw_context_emit(c, driver_added, 1, n) +#define pw_context_emit_driver_removed(c,n) pw_context_emit(c, driver_removed, 1, n) struct pw_context { struct pw_impl_core *core; /**< core object */ @@ -427,8 +428,6 @@ struct pw_context { long sc_pagesize; unsigned int freewheeling:1; - int profiling; - void *user_data; /**< extra user data */ }; @@ -730,7 +729,6 @@ struct pw_impl_node { uint64_t target_quantum; uint64_t driver_start; - struct spa_hook profiler_listener; void *user_data; /**< extra user data */ };