mm: optimize thread stack usage on arm64 [1/1]

PD#SWPL-1219

Problem:
On arm64, thread stack is 16KB for each task. If running task number
is large, this type of memory may over 40MB. It's a large amount on
small memory platform. But most case thread only use less 4KB stack.
It's waste of memory and we need optimize it.

Solution:
1. Pre-allocate a vmalloc address space for task stack;
2. Only map 1st page for stack and handle page fault in EL1
   when stack growth triggered exception;
3. handle stack switch for exception.

Verify:
p212

Change-Id: I47f511ccfa2868d982bc10a820ed6435b6d52ba9
Signed-off-by: tao zeng <tao.zeng@amlogic.com>
This commit is contained in:
tao zeng
2018-10-15 15:20:38 +08:00
committed by Dongjin Kim
parent 19cd66c4b6
commit 76789cadf7
16 changed files with 853 additions and 0 deletions

View File

@@ -86,6 +86,10 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#ifdef CONFIG_AMLOGIC_VMAP
#include <linux/amlogic/vmap_stack.h>
#endif
#include <trace/events/sched.h>
#define CREATE_TRACE_POINTS
@@ -209,15 +213,22 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node)
tsk->stack_vm_area = find_vm_area(stack);
return stack;
#else
#ifdef CONFIG_AMLOGIC_VMAP
return aml_stack_alloc(node, tsk);
#else /* CONFIG_AMLOGIC_VMAP */
struct page *page = alloc_pages_node(node, THREADINFO_GFP,
THREAD_SIZE_ORDER);
return page ? page_address(page) : NULL;
#endif /* CONFIG_AMLOGIC_VMAP */
#endif
}
static inline void free_thread_stack(struct task_struct *tsk)
{
#ifdef CONFIG_AMLOGIC_VMAP
aml_stack_free(tsk);
#else /* CONFIG_AMLOGIC_VMAP */
kaiser_unmap_thread_stack(tsk->stack);
#ifdef CONFIG_VMAP_STACK
if (task_stack_vm_area(tsk)) {
@@ -241,6 +252,7 @@ static inline void free_thread_stack(struct task_struct *tsk)
#endif
__free_pages(virt_to_page(tsk->stack), THREAD_SIZE_ORDER);
#endif /* CONFIG_AMLOGIC_VMAP */
}
# else
static struct kmem_cache *thread_stack_cache;
@@ -285,6 +297,9 @@ static struct kmem_cache *mm_cachep;
static void account_kernel_stack(struct task_struct *tsk, int account)
{
#ifdef CONFIG_AMLOGIC_VMAP
aml_account_task_stack(tsk, account);
#else
void *stack = task_stack_page(tsk);
struct vm_struct *vm = task_stack_vm_area(tsk);
@@ -317,6 +332,7 @@ static void account_kernel_stack(struct task_struct *tsk, int account)
memcg_kmem_update_page_stat(first_page, MEMCG_KERNEL_STACK_KB,
account * (THREAD_SIZE / 1024));
}
#endif /* CONFIG_AMLOGIC_VMAP*/
}
static void release_task_stack(struct task_struct *tsk)
@@ -468,12 +484,23 @@ int __weak arch_dup_task_struct(struct task_struct *dst,
return 0;
}
#ifdef CONFIG_AMLOGIC_VMAP
static bool first_magic __read_mostly;
#endif
void set_task_stack_end_magic(struct task_struct *tsk)
{
unsigned long *stackend;
stackend = end_of_stack(tsk);
#ifdef CONFIG_AMLOGIC_VMAP
if (unlikely(!first_magic)) {
*stackend = STACK_END_MAGIC; /* for overflow detection */
first_magic = 1;
}
#else
*stackend = STACK_END_MAGIC; /* for overflow detection */
#endif
}
static struct task_struct *dup_task_struct(struct task_struct *orig, int node)