impl-node: improve node activation

Only activate the nodes when it was not-triggered, do this check with an
atomic compare-and-swap so that we only activate a node once.

We might be able to use this later to make sure that we resume the
untriggered peer nodes when we remove a node from the graph.
This commit is contained in:
Wim Taymans 2024-04-04 21:17:51 +02:00
parent 9cb4d820d5
commit 74de723ecc
2 changed files with 29 additions and 24 deletions

View file

@ -1888,13 +1888,16 @@ static inline void signal_sync(struct client *c)
state->pending, state->required);
if (pw_node_activation_state_dec(state)) {
l->activation->status = PW_NODE_ACTIVATION_TRIGGERED;
l->activation->signal_time = nsec;
if (SPA_ATOMIC_CAS(l->activation->status,
PW_NODE_ACTIVATION_NOT_TRIGGERED,
PW_NODE_ACTIVATION_TRIGGERED)) {
l->activation->signal_time = nsec;
pw_log_trace_fp("%p: signal %p %p", c, l, state);
pw_log_trace_fp("%p: signal %p %p", c, l, state);
if (SPA_UNLIKELY(write(l->signalfd, &cmd, sizeof(cmd)) != sizeof(cmd)))
pw_log_warn("%p: write failed %m", c);
if (SPA_UNLIKELY(write(l->signalfd, &cmd, sizeof(cmd)) != sizeof(cmd)))
pw_log_warn("%p: write failed %m", c);
}
}
}
}

View file

@ -1210,10 +1210,17 @@ static inline uint64_t get_time_ns(struct spa_system *system)
return SPA_TIMESPEC_TO_NSEC(&ts);
}
static inline void wake_target(struct pw_node_target *t)
static inline void wake_target(struct pw_node_target *t, uint64_t nsec)
{
if (SPA_UNLIKELY(spa_system_eventfd_write(t->system, t->fd, 1) < 0))
pw_log_warn("%p: write failed %m", t->node);
struct pw_node_activation *a = t->activation;
if (SPA_ATOMIC_CAS(a->status,
PW_NODE_ACTIVATION_NOT_TRIGGERED,
PW_NODE_ACTIVATION_TRIGGERED)) {
a->signal_time = nsec;
if (SPA_UNLIKELY(spa_system_eventfd_write(t->system, t->fd, 1) < 0))
pw_log_warn("%p: write failed %m", t->node);
}
}
/* called from data-loop decrement the dependency counter of the target and when
@ -1226,22 +1233,20 @@ static inline void trigger_target(struct pw_node_target *t, uint64_t nsec)
pw_log_trace_fp("%p: (%s-%u) state:%p pending:%d/%d", t->node,
t->name, t->id, state, state->pending, state->required);
if (pw_node_activation_state_dec(state)) {
a->status = PW_NODE_ACTIVATION_TRIGGERED;
a->signal_time = nsec;
wake_target(t);
}
if (pw_node_activation_state_dec(state))
wake_target(t, nsec);
}
/* called from data-loop when all the targets of a node need to be triggered */
static inline int trigger_targets(struct pw_impl_node *this, int status, uint64_t nsec)
static inline int trigger_targets(struct pw_node_target *t, int status, uint64_t nsec)
{
struct pw_node_target *t;
struct pw_node_target *ta;
pw_log_trace_fp("%p: %s trigger targets %"PRIu64, this, this->name, nsec);
pw_log_trace_fp("%p: (%s-%u) trigger targets %"PRIu64,
t->node, t->name, t->id, nsec);
spa_list_for_each(t, &this->rt.target_list, link)
trigger_target(t, nsec);
spa_list_for_each(ta, &t->node->rt.target_list, link)
trigger_target(ta, nsec);
return 0;
}
@ -1323,7 +1328,7 @@ static inline int process_node(void *data)
/* we don't need to trigger targets when the node was driving the
* graph because that means we finished the graph. */
if (SPA_LIKELY(!this->driving)) {
trigger_targets(this, status, nsec);
trigger_targets(&this->rt.target, status, nsec);
} else {
/* calculate CPU time when finished */
a->signal_time = this->driver_start;
@ -1852,7 +1857,7 @@ static int node_ready(void *data, int status)
" pending %d/%d", node->name, node->info.id,
state, a->position.clock.duration,
pending, state->required);
wake_target(&node->rt.target);
wake_target(&node->rt.target, nsec);
check_states(node, nsec);
pw_impl_node_rt_emit_incomplete(node);
}
@ -1912,9 +1917,6 @@ again:
a->prev_signal_time = a->signal_time;
node->driver_start = nsec;
a->status = PW_NODE_ACTIVATION_TRIGGERED;
a->signal_time = nsec;
a->sync_timeout = SPA_MIN(min_timeout, DEFAULT_SYNC_TIMEOUT);
if (SPA_UNLIKELY(reposition_target != NULL)) {
@ -1946,7 +1948,7 @@ again:
spa_node_process_fast(p->mix);
}
/* now signal all the nodes we drive */
return trigger_targets(node, status, nsec);
return trigger_targets(&node->rt.target, status, nsec);
}
static int node_reuse_buffer(void *data, uint32_t port_id, uint32_t buffer_id)