mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -05:00
profiler: use rt_events
Track the driver nodes and listen for rt events to collect stats.
This commit is contained in:
parent
cfd3bcd6b2
commit
7ae59ff399
5 changed files with 107 additions and 65 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue