[Nouveau] Busy poll during commit
Greg Depoire--Ferrer
greg at gregdf.com
Mon Aug 8 20:57:30 UTC 2022
Hi,
Moving the cursor in circles on Linux 5.18 with a GTX 1070 mobile and a 120 Hz
display uses ~30% CPU.
Using perf shows most of the instructions are spent polling in
base507c_ntfy_wait_begun in drivers/gpu/drm/nouveau/dispnv50/base507c.c:
int
base507c_ntfy_wait_begun(struct nouveau_bo *bo, u32 offset,
struct nvif_device *device)
{
s64 time = nvif_msec(device, 2000ULL,
if (NVBO_TD32(bo, offset, NV_DISP_BASE_NOTIFIER_1, _0, STATUS, ==, BEGUN))
break;
usleep_range(1, 2);
);
return time < 0 ? time : 0;
}
That function is called from drivers/gpu/drm/nouveau/dispnv50/wndw.c:
int
nv50_wndw_wait_armed(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
struct nv50_disp *disp = nv50_disp(wndw->plane.dev);
if (asyw->set.ntfy) {
return wndw->func->ntfy_wait_begun(disp->sync,
asyw->ntfy.offset,
wndw->wndw.base.device);
}
return 0;
}
Which in turn is called from nv50_disp_atomic_commit_tail in
drivers/gpu/drm/nouveau/dispnv50/disp.c:
/* Wait for HW to signal completion. */
for_each_new_plane_in_state(state, plane, new_plane_state, i) {
struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state);
struct nv50_wndw *wndw = nv50_wndw(plane);
int ret = nv50_wndw_wait_armed(wndw, asyw);
if (ret)
NV_ERROR(drm, "%s: timeout\n", plane->name);
}
I haven't found many resources on how commits work. Could busy polling be
replaced by something else?
Additional information that might be helpful: with printks I found that
nv50_head_vblank_handler in drivers/gpu/drm/nouveau/dispnv50/head.c is always
called right before base507c_ntfy_wait_begun finished.
So for instance this patch drops the CPU usage by making sure that
base507c_ntfy_wait_begun does not even enter the loop using
drm_atomic_helper_wait_for_vblanks to wait for the vblank.
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 5863a689818c..f535ded86b2f 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -2186,6 +2186,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
if (atom->lock_core)
mutex_unlock(&disp->mutex);
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
/* Wait for HW to signal completion. */
for_each_new_plane_in_state(state, plane, new_plane_state, i) {
struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state);
Regards,
Greg
More information about the Nouveau
mailing list