Commit f3099462 authored by Eric Anholt's avatar Eric Anholt

drm/vc4: Add an ioctl for labeling GEM BOs for summary stats

This has proven immensely useful for debugging memory leaks and
overallocation (which is a rather serious concern on the platform,
given that we typically run at about 256MB of CMA out of up to 1GB
total memory, with framebuffers that are about 8MB ecah).

The state of the art without this is to dump debug logs from every GL
application, guess as to kernel allocations based on bo_stats, and try
to merge that all together into a global picture of memory allocation
state.  With this, you can add a couple of calls to the debug build of
the 3D driver and get a pretty detailed view of GPU memory usage from
/debug/dri/0/bo_stats (or when we debug print to dmesg on allocation
failure).

The Mesa side currently labels at the gallium resource level (so you
see that a 1920x20 pixmap has been created, presumably for the window
system panel), but we could extend that to be even more useful with
glObjectLabel() names being sent all the way down to the kernel.

(partial) example of sorted debugfs output with Mesa labeling all
resources:

               kernel BO cache:  16392kb BOs (3)
       tiling shadow 1920x1080:   8160kb BOs (1)
       resource 1920x1080@32/0:   8160kb BOs (1)
scanout resource 1920x1080@32/0:   8100kb BOs (1)
                        kernel:   8100kb BOs (1)

v2: Use strndup_user(), use lockdep assertion instead of just a
    comment, fix an array[-1] reference, extend comment about name
    freeing.
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20170725182718.31468-2-eric@anholt.netReviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 95d7cbcb
This diff is collapsed.
...@@ -140,6 +140,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = { ...@@ -140,6 +140,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(VC4_GET_PARAM, vc4_get_param_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VC4_GET_PARAM, vc4_get_param_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VC4_SET_TILING, vc4_set_tiling_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VC4_SET_TILING, vc4_set_tiling_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(VC4_LABEL_BO, vc4_label_bo_ioctl, DRM_RENDER_ALLOW),
}; };
static struct drm_driver vc4_drm_driver = { static struct drm_driver vc4_drm_driver = {
...@@ -257,7 +258,9 @@ static int vc4_drm_bind(struct device *dev) ...@@ -257,7 +258,9 @@ static int vc4_drm_bind(struct device *dev)
vc4->dev = drm; vc4->dev = drm;
drm->dev_private = vc4; drm->dev_private = vc4;
vc4_bo_cache_init(drm); ret = vc4_bo_cache_init(drm);
if (ret)
goto dev_unref;
drm_mode_config_init(drm); drm_mode_config_init(drm);
...@@ -281,8 +284,9 @@ static int vc4_drm_bind(struct device *dev) ...@@ -281,8 +284,9 @@ static int vc4_drm_bind(struct device *dev)
component_unbind_all(dev, drm); component_unbind_all(dev, drm);
gem_destroy: gem_destroy:
vc4_gem_destroy(drm); vc4_gem_destroy(drm);
drm_dev_unref(drm);
vc4_bo_cache_destroy(drm); vc4_bo_cache_destroy(drm);
dev_unref:
drm_dev_unref(drm);
return ret; return ret;
} }
......
...@@ -11,6 +11,24 @@ ...@@ -11,6 +11,24 @@
#include <drm/drm_encoder.h> #include <drm/drm_encoder.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
/* Don't forget to update vc4_bo.c: bo_type_names[] when adding to
* this.
*/
enum vc4_kernel_bo_type {
/* Any kernel allocation (gem_create_object hook) before it
* gets another type set.
*/
VC4_BO_TYPE_KERNEL,
VC4_BO_TYPE_V3D,
VC4_BO_TYPE_V3D_SHADER,
VC4_BO_TYPE_DUMB,
VC4_BO_TYPE_BIN,
VC4_BO_TYPE_RCL,
VC4_BO_TYPE_BCL,
VC4_BO_TYPE_KERNEL_CACHE,
VC4_BO_TYPE_COUNT
};
struct vc4_dev { struct vc4_dev {
struct drm_device *dev; struct drm_device *dev;
...@@ -46,14 +64,14 @@ struct vc4_dev { ...@@ -46,14 +64,14 @@ struct vc4_dev {
struct timer_list time_timer; struct timer_list time_timer;
} bo_cache; } bo_cache;
struct vc4_bo_stats { u32 num_labels;
struct vc4_label {
const char *name;
u32 num_allocated; u32 num_allocated;
u32 size_allocated; u32 size_allocated;
u32 num_cached; } *bo_labels;
u32 size_cached;
} bo_stats;
/* Protects bo_cache and the BO stats. */ /* Protects bo_cache and bo_labels. */
struct mutex bo_lock; struct mutex bo_lock;
uint64_t dma_fence_context; uint64_t dma_fence_context;
...@@ -169,6 +187,11 @@ struct vc4_bo { ...@@ -169,6 +187,11 @@ struct vc4_bo {
/* normally (resv == &_resv) except for imported bo's */ /* normally (resv == &_resv) except for imported bo's */
struct reservation_object *resv; struct reservation_object *resv;
struct reservation_object _resv; struct reservation_object _resv;
/* One of enum vc4_kernel_bo_type, or VC4_BO_TYPE_COUNT + i
* for user-allocated labels.
*/
int label;
}; };
static inline struct vc4_bo * static inline struct vc4_bo *
...@@ -460,7 +483,7 @@ struct vc4_validated_shader_info { ...@@ -460,7 +483,7 @@ struct vc4_validated_shader_info {
struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size); struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size);
void vc4_free_object(struct drm_gem_object *gem_obj); void vc4_free_object(struct drm_gem_object *gem_obj);
struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size, struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t size,
bool from_cache); bool from_cache, enum vc4_kernel_bo_type type);
int vc4_dumb_create(struct drm_file *file_priv, int vc4_dumb_create(struct drm_file *file_priv,
struct drm_device *dev, struct drm_device *dev,
struct drm_mode_create_dumb *args); struct drm_mode_create_dumb *args);
...@@ -478,6 +501,8 @@ int vc4_get_tiling_ioctl(struct drm_device *dev, void *data, ...@@ -478,6 +501,8 @@ int vc4_get_tiling_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int vc4_label_bo_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int vc4_mmap(struct file *filp, struct vm_area_struct *vma); int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj); struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj);
int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
...@@ -485,7 +510,7 @@ struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev, ...@@ -485,7 +510,7 @@ struct drm_gem_object *vc4_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct dma_buf_attachment *attach,
struct sg_table *sgt); struct sg_table *sgt);
void *vc4_prime_vmap(struct drm_gem_object *obj); void *vc4_prime_vmap(struct drm_gem_object *obj);
void vc4_bo_cache_init(struct drm_device *dev); int vc4_bo_cache_init(struct drm_device *dev);
void vc4_bo_cache_destroy(struct drm_device *dev); void vc4_bo_cache_destroy(struct drm_device *dev);
int vc4_bo_stats_debugfs(struct seq_file *m, void *arg); int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
......
...@@ -774,7 +774,7 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) ...@@ -774,7 +774,7 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
goto fail; goto fail;
} }
bo = vc4_bo_create(dev, exec_size, true); bo = vc4_bo_create(dev, exec_size, true, VC4_BO_TYPE_BCL);
if (IS_ERR(bo)) { if (IS_ERR(bo)) {
DRM_ERROR("Couldn't allocate BO for binning\n"); DRM_ERROR("Couldn't allocate BO for binning\n");
ret = PTR_ERR(bo); ret = PTR_ERR(bo);
......
...@@ -320,7 +320,7 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, ...@@ -320,7 +320,7 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
size += xtiles * ytiles * loop_body_size; size += xtiles * ytiles * loop_body_size;
setup->rcl = &vc4_bo_create(dev, size, true)->base; setup->rcl = &vc4_bo_create(dev, size, true, VC4_BO_TYPE_RCL)->base;
if (IS_ERR(setup->rcl)) if (IS_ERR(setup->rcl))
return PTR_ERR(setup->rcl); return PTR_ERR(setup->rcl);
list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head, list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
......
...@@ -236,7 +236,8 @@ vc4_allocate_bin_bo(struct drm_device *drm) ...@@ -236,7 +236,8 @@ vc4_allocate_bin_bo(struct drm_device *drm)
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
while (true) { while (true) {
struct vc4_bo *bo = vc4_bo_create(drm, size, true); struct vc4_bo *bo = vc4_bo_create(drm, size, true,
VC4_BO_TYPE_BIN);
if (IS_ERR(bo)) { if (IS_ERR(bo)) {
ret = PTR_ERR(bo); ret = PTR_ERR(bo);
......
...@@ -40,6 +40,7 @@ extern "C" { ...@@ -40,6 +40,7 @@ extern "C" {
#define DRM_VC4_GET_PARAM 0x07 #define DRM_VC4_GET_PARAM 0x07
#define DRM_VC4_SET_TILING 0x08 #define DRM_VC4_SET_TILING 0x08
#define DRM_VC4_GET_TILING 0x09 #define DRM_VC4_GET_TILING 0x09
#define DRM_VC4_LABEL_BO 0x0a
#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl) #define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno) #define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
...@@ -51,6 +52,7 @@ extern "C" { ...@@ -51,6 +52,7 @@ extern "C" {
#define DRM_IOCTL_VC4_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_PARAM, struct drm_vc4_get_param) #define DRM_IOCTL_VC4_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_PARAM, struct drm_vc4_get_param)
#define DRM_IOCTL_VC4_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SET_TILING, struct drm_vc4_set_tiling) #define DRM_IOCTL_VC4_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SET_TILING, struct drm_vc4_set_tiling)
#define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling) #define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling)
#define DRM_IOCTL_VC4_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo)
struct drm_vc4_submit_rcl_surface { struct drm_vc4_submit_rcl_surface {
__u32 hindex; /* Handle index, or ~0 if not present. */ __u32 hindex; /* Handle index, or ~0 if not present. */
...@@ -311,6 +313,15 @@ struct drm_vc4_set_tiling { ...@@ -311,6 +313,15 @@ struct drm_vc4_set_tiling {
__u64 modifier; __u64 modifier;
}; };
/**
* struct drm_vc4_label_bo - Attach a name to a BO for debug purposes.
*/
struct drm_vc4_label_bo {
__u32 handle;
__u32 len;
__u64 name;
};
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment