kgsl pool
Posted bubbleben
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kgsl pool相关的知识,希望对你有一定的参考价值。
&soc
....
msm_gpu: qcom,kgsl-3d0@2C00000
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
status = "ok";
reg = <0x2c00000 0x40000>, <0x2c61000 0x800>,
<0x6900000 0x44000>, <0x780000 0x6fff>;
reg-names = "kgsl_3d0_reg_memory", "cx_dbgc",
"qdss_gfx", "qfprom_memory";
interrupts = <0 300 0>;
interrupts-names = "kgsl_3d0_irq";
qcom,id = <0>;
qcom,chipid = <>;
qcom,initial-pwrlevel = <5>;
...
/* GPU Mempools */
// kgsl pool配置
qcom,gpu-mempools
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,gpu-mempools";
/* 4K Page Pool configuration */
qcom,gpu-mempool@0
reg = <0>;
qcom,mempool-page-size = <4096>;
qcom,mempool-reserved = <2048>;
qcom,mempool-allocate;
;
/* 8K Page Pool configuration */
qcom,gpu-mempool@1
reg = <1>;
qcom,mempool-page-size = <8192>;
qcom,mempool-reserved = <1024>;
qcom,mempool-allocate;
;
/* 64K Page Pool configuration */
qcom,gpu-mempool@2
reg = <2>;
qcom,mempool-page-size = <65536>;
qcom,mempool-reserved = <256>;
qcom,mempool-allocate;
;
/* 1M Page Pool configuration */
qcom,gpu-mempool@3
reg = <3>;
qcom,mempool-page-size = <1048576>;
qcom,mempool-reserved = <32>;
;
...
1. kgsl_probe_page_pools
static int kgsl_pool_max_pages;
static struct kgsl_page_pool kgsl_pools[6];
void kgsl_probe_page_pools(void)
struct device_node *node, *child;
int index = 0;
// qcom,gpu-mempools节点
node = of_find_compatible_node(NULL, NULL, "qcom,gpu-mempools");
if (!node)
return;
/* Get Max pages limit for mempool */
// 获取最大页面限制
of_property_read_u32(node, "qcom,mempool-max-pages",
&kgsl_pool_max_pages);
// 初始化kgsl pool缓存[见第2节]
kgsl_pool_cache_init();
// 遍历qcom,gpu-mempools下的每个节点
for_each_child_of_node(node, child)
// 解析每个qcom,gpu-mempool节点[见第3节]
if (!kgsl_of_parse_mempool(&kgsl_pools[index], child))
index++;
if (index == ARRAY_SIZE(kgsl_pools))
of_node_put(child);
break;
// kgsl池的数量
kgsl_num_pools = index;
of_node_put(node);
/* Initialize shrinker */
// 注册shrinker: 在内存紧张时触发回收[见第4节]
register_shrinker(&kgsl_pool_shrinker);
2. kgsl_pool_cache_init
// 支持kgsl pool排序
#ifdef CONFIG_QCOM_KGSL_SORT_POOL
struct kgsl_pool_page_entry
phys_addr_t physaddr;
struct page *page;
struct rb_node node;
;
static struct kmem_cache *addr_page_cache;
/**
* struct kgsl_page_pool - Structure to hold information for the pool
* @pool_order: Page order describing the size of the page
* @page_count: Number of pages currently present in the pool
* @reserved_pages: Number of pages reserved at init for the pool
* @list_lock: Spinlock for page list in the pool
* @pool_rbtree: RB tree with all pages held/reserved in this pool
* @mempool: Mempool to pre-allocate tracking structs for pages in this pool
*/
struct kgsl_page_pool
unsigned int pool_order;
unsigned int page_count;
unsigned int reserved_pages;
spinlock_t list_lock;
// 通过基数树对池内持有/预留的页面进行排序
struct rb_root pool_rbtree;
mempool_t *mempool;
;
static void *_pool_entry_alloc(gfp_t gfp_mask, void *arg)
return kmem_cache_alloc(addr_page_cache, gfp_mask);
static void _pool_entry_free(void *element, void *arg)
return kmem_cache_free(addr_page_cache, element);
static int
__kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
struct rb_node **node, *parent;
struct kgsl_pool_page_entry *new_page, *entry;
gfp_t gfp_mask = GFP_KERNEL & ~__GFP_DIRECT_RECLAIM;
new_page = pool->mempool ? mempool_alloc(pool->mempool, gfp_mask) :
kmem_cache_alloc(addr_page_cache, gfp_mask);
if (new_page == NULL)
return -ENOMEM;
spin_lock(&pool->list_lock);
node = &pool->pool_rbtree.rb_node;
new_page->physaddr = page_to_phys(p);
new_page->page = p;
while (*node != NULL)
parent = *node;
entry = rb_entry(parent, struct kgsl_pool_page_entry, node);
if (new_page->physaddr < entry->physaddr)
node = &parent->rb_left;
else
node = &parent->rb_right;
rb_link_node(&new_page->node, parent, node);
rb_insert_color(&new_page->node, &pool->pool_rbtree);
pool->page_count++;
spin_unlock(&pool->list_lock);
return 0;
static struct page *
__kgsl_pool_get_page(struct kgsl_page_pool *pool)
struct rb_node *node;
struct kgsl_pool_page_entry *entry;
struct page *p;
node = rb_first(&pool->pool_rbtree);
if (!node)
return NULL;
entry = rb_entry(node, struct kgsl_pool_page_entry, node);
p = entry->page;
rb_erase(&entry->node, &pool->pool_rbtree);
if (pool->mempool)
mempool_free(entry, pool->mempool);
else
kmem_cache_free(addr_page_cache, entry);
pool->page_count--;
return p;
static void kgsl_pool_list_init(struct kgsl_page_pool *pool)
// 初始化基数树
pool->pool_rbtree = RB_ROOT;
static void kgsl_pool_cache_init(void)
addr_page_cache = KMEM_CACHE(kgsl_pool_page_entry, 0);
static void kgsl_pool_cache_destroy(void)
kmem_cache_destroy(addr_page_cache);
static void kgsl_destroy_page_pool(struct kgsl_page_pool *pool)
mempool_destroy(pool->mempool);
#else
/**
* struct kgsl_page_pool - Structure to hold information for the pool
* @pool_order: Page order describing the size of the page
* @page_count: Number of pages currently present in the pool
* @reserved_pages: Number of pages reserved at init for the pool
* @list_lock: Spinlock for page list in the pool
* @page_list: List of pages held/reserved in this pool
*/
struct kgsl_page_pool
// 池子的阶数
unsigned int pool_order;
// 池子页面数量
unsigned int page_count;
// 池子预留的页面数量
unsigned int reserved_pages;
spinlock_t list_lock;
// 通过链表对池内持有/预留页面进行管理
struct list_head page_list;
;
static int
__kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
spin_lock(&pool->list_lock);
// 将页面插入表尾
list_add_tail(&p->lru, &pool->page_list);
// 池内页面数量加1
pool->page_count++;
spin_unlock(&pool->list_lock);
return 0;
static struct page *
__kgsl_pool_get_page(struct kgsl_page_pool *pool)
struct page *p;
// 从表头取出页面
p = list_first_entry_or_null(&pool->page_list, struct page, lru);
if (p)
// 池内页面数量减1
pool->page_count--;
// 将页面从池中移除
list_del(&p->lru);
return p;
static void kgsl_pool_list_init(struct kgsl_page_pool *pool)
INIT_LIST_HEAD(&pool->page_list);
static void kgsl_pool_cache_init(void)
static void kgsl_pool_cache_destroy(void)
static void kgsl_destroy_page_pool(struct kgsl_page_pool *pool)
#endif
3. kgsl_of_parse_mempool
static int kgsl_of_parse_mempool(struct kgsl_page_pool *pool,
struct device_node *node)
u32 size;
int order;
// 解析qcom,mempool-page-size:页面大小, 单位为字节
if (of_property_read_u32(node, "qcom,mempool-page-size", &size))
return -EINVAL;
// 根据页面大小获取阶数
order = get_order(size);
// 最大支持7阶页面
if (order > 8)
pr_err("kgsl: %pOF: pool order %d is too big\\n", node, order);
return -EINVAL;
// 初始化池子阶数
pool->pool_order = order;
spin_lock_init(&pool->list_lock);
// 初始化池子链表
kgsl_pool_list_init(pool);
// 预留页面[见3.1节]
kgsl_pool_reserve_pages(pool, node);
return 0;
3.1 kgsl_pool_reserve_pages
static void kgsl_pool_reserve_pages(struct kgsl_page_pool *pool,
struct device_node *node)
u32 reserved = 0;
int i;
// 解析qcom,mempool-reserved:预留的页面数量, 以4K的池子为例, 预留2048个页面
of_property_read_u32(node, "qcom,mempool-reserved", &reserved);
/* Limit the total number of reserved pages to 4096 */
// 预留页面不能超过4096
pool->reserved_pages = min_t(u32, reserved, 4096);
#if IS_ENABLED(CONFIG_QCOM_KGSL_SORT_POOL)
/*
* Pre-allocate tracking structs for reserved_pages so that
* the pool can hold them even in low memory conditions
*/
pool->mempool = mempool_create(pool->reserved_pages,
_pool_entry_alloc, _pool_entry_free, NULL);
#endif
for (i = 0; i < pool->reserved_pages; i++)
// 根据阶数初始化分配标志位[见3.1.1节]
gfp_t gfp_mask = kgsl_gfp_mask(pool->pool_order);
struct page *page;
// 向伙伴系统申请分配对应阶数的物理页面
page = alloc_pages(gfp_mask, pool->pool_order);
// 将页面加入池中[见3.1.2节]
_kgsl_pool_add_page(pool, page);
3.1.1 kgsl_gfp_mask
/*
* The user can set this from debugfs to force failed memory allocations to
* fail without trying OOM first. This is a debug setting useful for
* stress applications that want to test failure cases without pushing the
* system into unrecoverable OOM panics
*/
bool kgsl_sharedmem_noretry_flag;
gfp_t kgsl_gfp_mask(int page_order)
gfp_t gfp_mask = __GFP_HIGHMEM;
// 非0阶
if (page_order > 0)
gfp_mask |= __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN;
// 禁止回收
gfp_mask &= ~__GFP_RECLAIM;
else
// 0阶
gfp_mask |= GFP_KERNEL;
// 分配失败时禁止重试和警告
if (kgsl_sharedmem_noretry_flag)
gfp_mask |= __GFP_NORETRY | __GFP_NOWARN;
return gfp_mask;
3.1.2 _kgsl_pool_add_page
/* Add a page to specified pool */
static void
_kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
if (!p)
return;
/*
* Sanity check to make sure we don't re-pool a page that
* somebody else has a reference to.
*/
if (WARN_ON(unlikely(page_count(p) > 1)))
__free_pages(p, pool->pool_order);
return;
// 如第2节所示: 将页面加入池中的基数树或者链表, 添加成功返回0
if (__kgsl_pool_add_page(pool, p))
__free_pages(p, pool->pool_order);
trace_kgsl_pool_free_page(pool->pool_order);
return;
trace_kgsl_pool_add_page(pool->pool_order, pool->page_count);
mod_node_page_state(page_pgdat(p), NR_KERNEL_MISC_RECLAIMABLE,
(1 << pool->pool_order));
4. kgsl_pool_shrinker
/* Shrinker callback data*/
static struct shrinker kgsl_pool_shrinker =
// 计算扫描的页面
.count_objects = kgsl_pool_shrink_count_objects,
// 回收页面
.scan_objects = kgsl_pool_shrink_scan_objects,
.seeks = DEFAULT_SEEKS,
.batch = 0,
;
5. kgsl_get_page_size
int kgsl_get_page_size(size_t size, unsigned int align)
size_t pool;
// 遍历每个大于4K, 小于等于1M的内存池
for (pool = SZ_1M; pool > PAGE_SIZE; pool >>= 1)
// 判断是否有对应的满足条件的kgsl池[见5.1节]
if ((align >= ilog2(pool)) && (size >= pool) &&
kgsl_pool_available(pool))
return pool;
return PAGE_SIZE;
5.1 kgsl_pool_available
/*
* Return true if the pool of specified page size is supported
* or no pools are supported otherwise return false.
*/
static bool kgsl_pool_available(unsigned int page_size)
// 确定阶数
int order = get_order(page_size);
// kgsl池个数
if (!kgsl_num_pools)
return true;
// 根据阶数确认是否有对应的kgsl池
return (kgsl_get_pool_index(order) >= 0);
5.2 kgsl_get_pool_index
/* Return the index of the pool for the specified order */
static int kgsl_get_pool_index(int order)
int i;
// 按阶数从小到大遍历每个kgsl池
for (i = 0; i < kgsl_num_pools; i++)
// 传入的阶数如果与某个kgsl池的阶数一致, 则返回其索引
if (kgsl_pools[i].pool_order == order)
return i;
return -EINVAL;
6. kgsl_pool_alloc_page
int kgsl_pool_alloc_page(int *page_size, struct page **pages,
unsigned int pages_len, unsigned int *align,
struct device *dev)
int j;
int pcount = 0;
struct kgsl_page_pool *pool;
struct page *page = NULL;
struct page *p = NULL;
// 根据页面大小确认阶数
int order = get_order(以上是关于kgsl pool的主要内容,如果未能解决你的问题,请参考以下文章
php-fpm的pool池子php慢日志记录open_basedirphp-fpm进程管理
12.21 php-fpm的pool 12.22 php-fpm慢执行日志 12.23 open_basedir 12.24 php-fpm进程管理