Skip to content

Commit

Permalink
drm/i915: Sysfs interface to get GFX shmem usage
Browse files Browse the repository at this point in the history
There is a requirement of a new interface for achieving below
functionalities:

Need to provide Client based detailed information about the
distribution of Graphics memory
Need to provide an interface which can provide info about the
sharing of Graphics buffers between the clients.
The client based interface would also aid in debugging of
memory usage/consumption by each client & debug memleak
related issues.

With this new interface,

In case of memleak scenarios, we can easily zero in on the
culprit client which is unexpectedly holding on the Graphics
buffers for an inordinate amount of time.
We can get an estimate of the instantaneous memory footprint
of every Graphics client.
We can now trace all the processes sharing a particular
Graphics buffer.
By means of this patch we try to provide a sysfs interface
to achieve the mentioned functionalities.

There are two files created in sysfs:
'i915_gem_meminfo' will provide summary of the graphics
resources used by each graphics client.
'i915_gem_objinfo' will provide detailed view of each object
created by individual clients.

Rebased for kernel v4.19 1A (Fan Yugang)

Removes useless shmem_inode_info->info_lock per Jeremy's optimization.
Removes useless object info for each pid for performance optimization.
Adds CONFIG_DRM_I915_MEMTRACK which depends on
CONFIG_DRM_I915_CAPTURE_ERROR to pass kernel config test.

Rebased for kernel v5.4 (He, Yue) (Wan, Shuang)

Rebased for kernel v5.10 and v5.15 (He, Yue)

Rebased for kernel v5.15 (kui, wen)

Rebased for kernel v6.1 (kui, wen)

Tracked-On: OAM-121426
Signed-off-by: Wenkui <[email protected]>
  • Loading branch information
beckwen committed Jun 27, 2024
1 parent e8a8c0c commit 67718e0
Show file tree
Hide file tree
Showing 15 changed files with 1,350 additions and 5 deletions.
4 changes: 4 additions & 0 deletions drivers/gpu/drm/drm_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
/* from BKL pushdown */
DEFINE_MUTEX(drm_global_mutex);

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
EXPORT_SYMBOL(drm_global_mutex);
#endif

bool drm_dev_needs_global_mutex(struct drm_device *dev)
{
/*
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/drm_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
uint32_t handle);

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
#define DRM_MAGIC_HASH_ORDER \
4 /**< Size of key hash table. Must be power of 2. */
#endif
/* drm_drv.c */
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
void drm_minor_release(struct drm_minor *minor);
Expand Down
10 changes: 10 additions & 0 deletions drivers/gpu/drm/i915/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ config DRM_I915_COMPRESS_ERROR

If in doubt, say "Y".

config DRM_I915_MEMTRACK
bool "Enable shmem usage status track"
depends on DRM_I915_CAPTURE_ERROR
default y
help
This option enables shmem usage status track of system summary and
each process.

If in doubt, say "N".

config DRM_I915_USERPTR
bool "Always enable userptr support"
depends on DRM_I915
Expand Down
13 changes: 13 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_mman.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_mmap *args = data;
struct drm_i915_gem_object *obj;
unsigned long addr;
#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
int ret;
#endif

/*
* mmap ioctl is disallowed for all discrete platforms,
Expand Down Expand Up @@ -127,6 +130,11 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,

err:
i915_gem_object_put(obj);
#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
ret = i915_obj_insert_virt_addr(obj, addr, false, false);
if (ret)
return ret;
#endif
return addr;
}

Expand Down Expand Up @@ -408,6 +416,11 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
(ggtt->gmadr.start + i915_ggtt_offset(vma)) >> PAGE_SHIFT,
min_t(u64, vma->size, area->vm_end - area->vm_start),
&ggtt->iomap);
#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
ret = i915_obj_insert_virt_addr(obj, (unsigned long)area->vm_start,
true, true);
#endif

if (ret)
goto err_fence;

Expand Down
26 changes: 26 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
obj->mm.madv = I915_MADV_WILLNEED;
INIT_RADIX_TREE(&obj->mm.get_page.radix, GFP_KERNEL | __GFP_NOWARN);
mutex_init(&obj->mm.get_page.lock);
#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
/*
* Mark the object as not having backing pages, as no allocation
* for it yet
*/
obj->has_backing_pages = 0;
INIT_LIST_HEAD(&obj->pid_info);
#endif
INIT_RADIX_TREE(&obj->mm.get_dma_page.radix, GFP_KERNEL | __GFP_NOWARN);
mutex_init(&obj->mm.get_dma_page.lock);
}
Expand Down Expand Up @@ -229,6 +237,13 @@ bool i915_gem_object_can_bypass_llc(struct drm_i915_gem_object *obj)
return IS_JSL_EHL(i915);
}

static int i915_gem_open_object(struct drm_gem_object *gem, struct drm_file *file)
{
struct drm_i915_gem_object *obj = to_intel_bo(gem);

return i915_gem_obj_insert_pid(obj);
}

static void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
{
struct drm_i915_gem_object *obj = to_intel_bo(gem);
Expand Down Expand Up @@ -383,6 +398,16 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj)
if (obj->base.import_attach)
drm_prime_gem_destroy(&obj->base, NULL);

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
if (!obj->stolen && (obj->has_backing_pages == 1)) {
struct drm_i915_private *dev_priv =
to_i915(obj->base.dev);

dev_priv->mm.phys_mem_total -= obj->base.size;
obj->has_backing_pages = 0;
}
i915_gem_obj_remove_all_pids(obj);
#endif
drm_gem_free_mmap_offset(&obj->base);

if (obj->ops->release)
Expand Down Expand Up @@ -888,6 +913,7 @@ int __init i915_objects_module_init(void)

static const struct drm_gem_object_funcs i915_gem_object_funcs = {
.free = i915_gem_free_object,
.open = i915_gem_open_object,
.close = i915_gem_close_object,
.export = i915_gem_prime_export,
};
Expand Down
7 changes: 7 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_object_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,9 @@ struct drm_i915_gem_object {
*/
unsigned int cache_dirty:1;

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
unsigned int has_backing_pages : 1;
#endif
/* @is_dpt: Object houses a display page table (DPT) */
unsigned int is_dpt:1;

Expand Down Expand Up @@ -687,6 +690,10 @@ struct drm_i915_gem_object {
bool created:1;
} ttm;

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
struct list_head pid_info;
#endif

/*
* Record which PXP key instance this object was created against (if
* any), so we can use it to determine if the encryption is valid by
Expand Down
21 changes: 20 additions & 1 deletion drivers/gpu/drm/i915/gem/i915_gem_shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,14 @@ static int shmem_get_pages(struct drm_i915_gem_object *obj)

if (i915_gem_object_can_bypass_llc(obj))
obj->cache_dirty = true;

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
if (obj->has_backing_pages == 0) {
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);

dev_priv->mm.phys_mem_total += obj->base.size;
obj->has_backing_pages = 1;
}
#endif
__i915_gem_object_set_pages(obj, st);

return 0;
Expand Down Expand Up @@ -286,6 +293,18 @@ shmem_truncate(struct drm_i915_gem_object *obj)
shmem_truncate_range(file_inode(obj->base.filp), 0, (loff_t)-1);
obj->mm.madv = __I915_MADV_PURGED;
obj->mm.pages = ERR_PTR(-EFAULT);
#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
/*
* Mark the object as not having backing pages, as physical space
* returned back to kernel
*/
if (obj->has_backing_pages == 1) {
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);

dev_priv->mm.phys_mem_total -= obj->base.size;
obj->has_backing_pages = 0;
}
#endif

return 0;
}
Expand Down
6 changes: 5 additions & 1 deletion drivers/gpu/drm/i915/i915_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,11 @@ static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)

i915_gem_context_close(file);
i915_drm_client_put(file_priv->client);

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
i915_gem_remove_sysfs_file_entry(dev, file);
put_pid(file_priv->tgid);
kfree(file_priv->process_name);
#endif
kfree_rcu(file_priv, rcu);

/* Catch up with all the deferred frees from "this" client */
Expand Down
20 changes: 20 additions & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ struct i915_gem_mm {
/* shrinker accounting, also useful for userland debugging */
u64 shrink_memory;
u32 shrink_count;
#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
size_t phys_mem_total;
#endif
};

struct i915_virtual_gpu {
Expand Down Expand Up @@ -256,6 +259,10 @@ struct drm_i915_private {

bool preserve_bios_swizzle;

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
struct kobject memtrack_kobj;
bool mmtkobj_initialized;
#endif
unsigned int fsb_freq, mem_freq, is_ddr3;
unsigned int skl_preferred_vco_freq;

Expand Down Expand Up @@ -546,6 +553,19 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
return ((mask << (msb - pb)) & (mask << (msb - s))) & BIT(msb);
}

#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
int i915_get_pid_cmdline(struct task_struct *task, char *buffer);
int i915_gem_obj_insert_pid(struct drm_i915_gem_object *obj);
void i915_gem_obj_remove_all_pids(struct drm_i915_gem_object *obj);
int i915_obj_insert_virt_addr(struct drm_i915_gem_object *obj,
unsigned long addr, bool is_map_gtt,
bool is_mutex_locked);
int i915_get_drm_clients_info(struct drm_i915_error_state_buf *m,
struct drm_device *dev);
int i915_gem_get_obj_info(struct drm_i915_error_state_buf *m,
struct drm_device *dev, struct pid *tgid);
#endif

#define IS_MOBILE(i915) (INTEL_INFO(i915)->is_mobile)
#define IS_DGFX(i915) (INTEL_INFO(i915)->is_dgfx)

Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/i915/i915_file_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ struct drm_i915_file_private {
struct drm_file *file;
struct rcu_head rcu;
};
#if IS_ENABLED(CONFIG_DRM_I915_MEMTRACK)
char *process_name;
struct pid *tgid;
struct bin_attribute *obj_attr;
#endif

/** @proto_context_lock: Guards all struct i915_gem_proto_context
* operations
Expand Down
Loading

0 comments on commit 67718e0

Please sign in to comment.