mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-09 04:38:03 +02:00
venus: add a more relaxed polling strategy
The default vn_relax is mainly targeting Vulkan commands expecting a rely like object creation and property queries. The defined relax reason here is VN_RELAX_REASON_RING_SPACE. The polling strategy involves more busy waits to overcome sleep penalty affecting cpu utilization, as well as an edge case for Android system server which forces to sleep longer even with trivial hrtimer interval. However, for the below relax reasons: - VN_RELAX_REASON_RING_SPACE - VN_RELAX_REASON_FENCE - VN_RELAX_REASON_SEMAPHORE - VN_RELAX_REASON_QUERY It's a waste of cpu cycles if we do more busy waits if the initial polled signals are not "ready". Having less busy waits there allows to jump to higher order of sleeps sooner to disturb the scheduler less until signaled. Signed-off-by: Yiwei Zhang <zzyiwei@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28287>
This commit is contained in:
parent
7dc2f62273
commit
1a475c70b2
2 changed files with 84 additions and 18 deletions
|
|
@ -179,6 +179,54 @@ vn_relax_reason_string(enum vn_relax_reason reason)
|
|||
return "";
|
||||
}
|
||||
|
||||
static struct vn_relax_profile
|
||||
vn_relax_get_profile(enum vn_relax_reason reason)
|
||||
{
|
||||
/* This is the helper to map a vn_relax_reason to a profile. For new
|
||||
* profiles added, we MUST also update the pre-calculated "first_warn_time"
|
||||
* in vn_watchdog_init() if the "first warn" comes sooner.
|
||||
*/
|
||||
|
||||
/* deliberately avoid default case for -Wswitch to catch upon compile */
|
||||
switch (reason) {
|
||||
case VN_RELAX_REASON_RING_SEQNO:
|
||||
/* warn every 4096 iters after having already slept ~3.5s:
|
||||
* (yielded 255 times)
|
||||
* stuck in wait with iter at 4096 (3.5s slept already)
|
||||
* stuck in wait with iter at 8192 (14s slept already)
|
||||
* stuck in wait with iter at 12288 (35s slept already)
|
||||
* ...
|
||||
* aborting after 895s
|
||||
*/
|
||||
return (struct vn_relax_profile){
|
||||
.base_sleep_us = 160,
|
||||
.busy_wait_order = 8,
|
||||
.warn_order = 12,
|
||||
.abort_order = 16,
|
||||
};
|
||||
case VN_RELAX_REASON_RING_SPACE:
|
||||
case VN_RELAX_REASON_FENCE:
|
||||
case VN_RELAX_REASON_SEMAPHORE:
|
||||
case VN_RELAX_REASON_QUERY:
|
||||
/* warn every 1024 iters after having already slept ~3.5s:
|
||||
* (yielded 15 times)
|
||||
* stuck in wait with iter at 1024 (3.5s slept already)
|
||||
* stuck in wait with iter at 2048 (14s slept already)
|
||||
* stuck in wait with iter at 3072 (35s slept already)
|
||||
* ...
|
||||
* aborting after 895s
|
||||
*/
|
||||
return (struct vn_relax_profile){
|
||||
.base_sleep_us = 160,
|
||||
.busy_wait_order = 4,
|
||||
.warn_order = 10,
|
||||
.abort_order = 14,
|
||||
};
|
||||
}
|
||||
|
||||
unreachable("unhandled vn_relax_reason");
|
||||
}
|
||||
|
||||
struct vn_relax_state
|
||||
vn_relax_init(struct vn_instance *instance, enum vn_relax_reason reason)
|
||||
{
|
||||
|
|
@ -190,7 +238,7 @@ vn_relax_init(struct vn_instance *instance, enum vn_relax_reason reason)
|
|||
return (struct vn_relax_state){
|
||||
.instance = instance,
|
||||
.iter = 0,
|
||||
.reason = reason,
|
||||
.profile = vn_relax_get_profile(reason),
|
||||
.reason_str = vn_relax_reason_string(reason),
|
||||
};
|
||||
}
|
||||
|
|
@ -198,31 +246,22 @@ vn_relax_init(struct vn_instance *instance, enum vn_relax_reason reason)
|
|||
void
|
||||
vn_relax(struct vn_relax_state *state)
|
||||
{
|
||||
const uint32_t base_sleep_us = state->profile.base_sleep_us;
|
||||
const uint32_t busy_wait_order = state->profile.busy_wait_order;
|
||||
const uint32_t warn_order = state->profile.warn_order;
|
||||
const uint32_t abort_order = state->profile.abort_order;
|
||||
|
||||
uint32_t *iter = &state->iter;
|
||||
const char *reason_str = state->reason_str;
|
||||
|
||||
/* Yield for the first 2^busy_wait_order times and then sleep for
|
||||
* base_sleep_us microseconds for the same number of times. After that,
|
||||
* keep doubling both sleep length and count.
|
||||
* Must also update pre-calculated "first_warn_time" in vn_relax_init().
|
||||
*/
|
||||
const uint32_t busy_wait_order = 8;
|
||||
const uint32_t base_sleep_us = 160;
|
||||
const uint32_t warn_order = 12;
|
||||
const uint32_t abort_order = 16;
|
||||
|
||||
(*iter)++;
|
||||
if (*iter < (1 << busy_wait_order)) {
|
||||
thrd_yield();
|
||||
return;
|
||||
}
|
||||
|
||||
/* warn occasionally if we have slept at least 1.28ms for 2048 times (plus
|
||||
* another 2047 shorter sleeps)
|
||||
*/
|
||||
if (unlikely(*iter % (1 << warn_order) == 0)) {
|
||||
struct vn_instance *instance = state->instance;
|
||||
vn_log(instance, "stuck in %s wait with iter at %d", reason_str, *iter);
|
||||
vn_log(instance, "stuck in %s wait with iter at %d", state->reason_str,
|
||||
*iter);
|
||||
|
||||
struct vn_ring *ring = instance->ring.ring;
|
||||
const uint32_t status = vn_ring_load_status(ring);
|
||||
|
|
|
|||
|
|
@ -212,10 +212,37 @@ enum vn_relax_reason {
|
|||
VN_RELAX_REASON_QUERY,
|
||||
};
|
||||
|
||||
/* vn_relax_profile defines the driver side polling behavior
|
||||
*
|
||||
* - base_sleep_us:
|
||||
* - the minimum polling interval after initial busy waits
|
||||
*
|
||||
* - busy_wait_order:
|
||||
* - initial 2 ^ busy_wait_order times thrd_yield()
|
||||
*
|
||||
* - warn_order:
|
||||
* - number of polls at order N:
|
||||
* - fn_cnt(N) = 2 ^ N
|
||||
* - interval of poll at order N:
|
||||
* - fn_step(N) = base_sleep_us * (2 ^ (N - busy_wait_order))
|
||||
* - warn occasionally if we have slept at least:
|
||||
* - for (i = busy_wait_order; i < warn_order; i++)
|
||||
* total_sleep += fn_cnt(i) * fn_step(i)
|
||||
*
|
||||
* - abort_order:
|
||||
* - similar to warn_order, but would abort() instead
|
||||
*/
|
||||
struct vn_relax_profile {
|
||||
uint32_t base_sleep_us;
|
||||
uint32_t busy_wait_order;
|
||||
uint32_t warn_order;
|
||||
uint32_t abort_order;
|
||||
};
|
||||
|
||||
struct vn_relax_state {
|
||||
struct vn_instance *instance;
|
||||
uint32_t iter;
|
||||
enum vn_relax_reason reason;
|
||||
const struct vn_relax_profile profile;
|
||||
const char *reason_str;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue