Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19d5fdf9 authored by Suren Baghdasaryan's avatar Suren Baghdasaryan
Browse files

ANDROID: staging: android: ion: Expose total heap and pool sizes via sysfs



Add sysfs attributes to track ion total heap and pool memory allocations.
The following sysfs attributes are added:

/sys/kernel/ion/total_heaps_kb
/sys/kernel/ion/total_pools_kb

Bug: 138148041
Test: adb shell cat /sys/kernel/ion/*
Change-Id: If92770dc3389af865c619525f04d3ba0e013b244
Signed-off-by: default avatarSuren Baghdasaryan <surenb@google.com>
parent 8247c60a
Loading
Loading
Loading
Loading
+27 −0
Original line number Original line Diff line number Diff line
What:		/sys/kernel/ion
Date:		Dec 2019
KernelVersion:	4.14.158
Contact:	Suren Baghdasaryan <surenb@google.com>,
		Sandeep Patil <sspatil@google.com>
Description:
		The /sys/kernel/ion directory contains a snapshot of the
		internal state of ION memory heaps and pools.
Users:		kernel memory tuning tools

What:		/sys/kernel/ion/total_heaps_kb
Date:		Dec 2019
KernelVersion:	4.14.158
Contact:	Suren Baghdasaryan <surenb@google.com>,
		Sandeep Patil <sspatil@google.com>
Description:
		The total_heaps_kb file is read-only and specifies how much
		memory in Kb is allocated to ION heaps.

What:		/sys/kernel/ion/total_pools_kb
Date:		Dec 2019
KernelVersion:	4.14.158
Contact:	Suren Baghdasaryan <surenb@google.com>,
		Sandeep Patil <sspatil@google.com>
Description:
		The total_pools_kb file is read-only and specifies how much
		memory in Kb is allocated to ION pools.
+66 −2
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@


static struct ion_device *internal_dev;
static struct ion_device *internal_dev;
static int heap_id;
static int heap_id;
static atomic_long_t total_heap_bytes;


/* this function should only be called while dev->lock is held */
/* this function should only be called while dev->lock is held */
static void ion_buffer_add(struct ion_device *dev,
static void ion_buffer_add(struct ion_device *dev,
@@ -100,6 +101,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
	mutex_lock(&dev->buffer_lock);
	mutex_lock(&dev->buffer_lock);
	ion_buffer_add(dev, buffer);
	ion_buffer_add(dev, buffer);
	mutex_unlock(&dev->buffer_lock);
	mutex_unlock(&dev->buffer_lock);
	atomic_long_add(len, &total_heap_bytes);
	return buffer;
	return buffer;


err1:
err1:
@@ -128,6 +130,7 @@ static void _ion_buffer_destroy(struct ion_buffer *buffer)
	mutex_lock(&dev->buffer_lock);
	mutex_lock(&dev->buffer_lock);
	rb_erase(&buffer->node, &dev->buffers);
	rb_erase(&buffer->node, &dev->buffers);
	mutex_unlock(&dev->buffer_lock);
	mutex_unlock(&dev->buffer_lock);
	atomic_long_sub(buffer->size, &total_heap_bytes);


	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
	if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
		ion_heap_freelist_add(heap, buffer);
		ion_heap_freelist_add(heap, buffer);
@@ -568,6 +571,56 @@ void ion_device_add_heap(struct ion_heap *heap)
}
}
EXPORT_SYMBOL(ion_device_add_heap);
EXPORT_SYMBOL(ion_device_add_heap);


static ssize_t
total_heaps_kb_show(struct kobject *kobj, struct kobj_attribute *attr,
		    char *buf)
{
	u64 size_in_bytes = atomic_long_read(&total_heap_bytes);

	return sprintf(buf, "%llu\n", div_u64(size_in_bytes, 1024));
}

static ssize_t
total_pools_kb_show(struct kobject *kobj, struct kobj_attribute *attr,
		    char *buf)
{
	u64 size_in_bytes = ion_page_pool_nr_pages() * PAGE_SIZE;

	return sprintf(buf, "%llu\n", div_u64(size_in_bytes, 1024));
}

static struct kobj_attribute total_heaps_kb_attr =
	__ATTR_RO(total_heaps_kb);

static struct kobj_attribute total_pools_kb_attr =
	__ATTR_RO(total_pools_kb);

static struct attribute *ion_device_attrs[] = {
	&total_heaps_kb_attr.attr,
	&total_pools_kb_attr.attr,
	NULL,
};

ATTRIBUTE_GROUPS(ion_device);

static int ion_init_sysfs(void)
{
	struct kobject *ion_kobj;
	int ret;

	ion_kobj = kobject_create_and_add("ion", kernel_kobj);
	if (!ion_kobj)
		return -ENOMEM;

	ret = sysfs_create_groups(ion_kobj, ion_device_groups);
	if (ret) {
		kobject_put(ion_kobj);
		return ret;
	}

	return 0;
}

static int ion_device_create(void)
static int ion_device_create(void)
{
{
	struct ion_device *idev;
	struct ion_device *idev;
@@ -584,8 +637,13 @@ static int ion_device_create(void)
	ret = misc_register(&idev->dev);
	ret = misc_register(&idev->dev);
	if (ret) {
	if (ret) {
		pr_err("ion: failed to register misc device.\n");
		pr_err("ion: failed to register misc device.\n");
		kfree(idev);
		goto err_reg;
		return ret;
	}

	ret = ion_init_sysfs();
	if (ret) {
		pr_err("ion: failed to add sysfs attributes.\n");
		goto err_sysfs;
	}
	}


	idev->debug_root = debugfs_create_dir("ion", NULL);
	idev->debug_root = debugfs_create_dir("ion", NULL);
@@ -595,5 +653,11 @@ static int ion_device_create(void)
	plist_head_init(&idev->heaps);
	plist_head_init(&idev->heaps);
	internal_dev = idev;
	internal_dev = idev;
	return 0;
	return 0;

err_sysfs:
	misc_deregister(&idev->dev);
err_reg:
	kfree(idev);
	return ret;
}
}
subsys_initcall(ion_device_create);
subsys_initcall(ion_device_create);
+1 −0
Original line number Original line Diff line number Diff line
@@ -315,6 +315,7 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order);
void ion_page_pool_destroy(struct ion_page_pool *pool);
void ion_page_pool_destroy(struct ion_page_pool *pool);
struct page *ion_page_pool_alloc(struct ion_page_pool *pool);
struct page *ion_page_pool_alloc(struct ion_page_pool *pool);
void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
long ion_page_pool_nr_pages(void);


/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
 * @pool:		the pool
 * @pool:		the pool
+17 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,13 @@


#include "ion.h"
#include "ion.h"


/*
 * We avoid atomic_long_t to minimize cache flushes at the cost of possible
 * race which would result in a small accounting inaccuracy that we can
 * tolerate.
 */
static long nr_total_pages;

static inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
static inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
{
{
	if (fatal_signal_pending(current))
	if (fatal_signal_pending(current))
@@ -36,6 +43,7 @@ static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
		pool->low_count++;
		pool->low_count++;
	}
	}


	nr_total_pages += 1 << pool->order;
	mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
	mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
							1 << pool->order);
							1 << pool->order);
	mutex_unlock(&pool->mutex);
	mutex_unlock(&pool->mutex);
@@ -56,6 +64,7 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
	}
	}


	list_del(&page->lru);
	list_del(&page->lru);
	nr_total_pages -= 1 << pool->order;
	mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
	mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
							-(1 << pool->order));
							-(1 << pool->order));
	return page;
	return page;
@@ -97,6 +106,14 @@ static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
	return count << pool->order;
	return count << pool->order;
}
}


long ion_page_pool_nr_pages(void)
{
	/* Correct possible overflow caused by racing writes */
	if (nr_total_pages < 0)
		nr_total_pages = 0;
	return nr_total_pages;
}

int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
			 int nr_to_scan)
			 int nr_to_scan)
{
{