summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXianzhong <b07117@freescale.com>2012-11-09 21:28:03 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2012-11-12 14:24:14 +0800
commit4429a55b3cd51291ffc4c4ee59b9acf18398978e (patch)
tree420938e25dc7a28dfdaa52116c31d0b5f0759841
parent6f4bfd20b2a1b3a11a2bece474bb806712c4a318 (diff)
ENGR00232951 the force contiguous lowmem killer
The killer only work when force contiguous memory allocation fail,the work routinue: 1. register task free callback 2. force contiguous lowmem shrink 1> initialize min_adj to 0, kill itself in case other process cannot be killed 2> polling all process and find the available process(higher oom_adj, higher gpu memory) 3> select the best available process and send SIGKILL to kill it 3. try to allocate force contiguous memory again 4. unregister task free and exit shrinking state when memory is ready Signed-off-by: Xianzhong <b07117@freescale.com> Acked-by: Lily Zhang
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c
index b14bf79c038a..370c663fd2d6 100644
--- a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c
@@ -425,6 +425,115 @@ gckKERNEL_Destroy(
return gcvSTATUS_OK;
}
+#ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/oom.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+
+static struct task_struct *lowmem_deathpending;
+static unsigned long lowmem_deathpending_timeout;
+
+static int
+task_notify_func(struct notifier_block *self, unsigned long val, void *data);
+
+static struct notifier_block task_nb = {
+ .notifier_call = task_notify_func,
+};
+
+static int
+task_notify_func(struct notifier_block *self, unsigned long val, void *data)
+{
+ struct task_struct *task = data;
+
+ if (task == lowmem_deathpending)
+ lowmem_deathpending = NULL;
+
+ return NOTIFY_OK;
+}
+
+static int force_contiguous_lowmem_shrink(IN gckKERNEL Kernel)
+{
+ struct task_struct *p;
+ struct task_struct *selected = NULL;
+ int tasksize;
+ int ret = -1;
+ int min_adj = 0;
+ int selected_tasksize = 0;
+ int selected_oom_adj;
+ /*
+ * If we already have a death outstanding, then
+ * bail out right away; indicating to vmscan
+ * that we have nothing further to offer on
+ * this pass.
+ *
+ */
+ if (lowmem_deathpending &&
+ time_before_eq(jiffies, lowmem_deathpending_timeout))
+ return 0;
+ selected_oom_adj = min_adj;
+
+ read_lock(&tasklist_lock);
+ for_each_process(p) {
+ struct mm_struct *mm;
+ struct signal_struct *sig;
+ gcuDATABASE_INFO info;
+ int oom_adj;
+
+ task_lock(p);
+ mm = p->mm;
+ sig = p->signal;
+ if (!mm || !sig) {
+ task_unlock(p);
+ continue;
+ }
+ oom_adj = sig->oom_adj;
+ if (oom_adj < min_adj) {
+ task_unlock(p);
+ continue;
+ }
+
+ tasksize = 0;
+ if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_VIDEO_MEMORY, &info) == gcvSTATUS_OK){
+ tasksize += info.counters.bytes / PAGE_SIZE;
+ }
+ if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_CONTIGUOUS, &info) == gcvSTATUS_OK){
+ tasksize += info.counters.bytes / PAGE_SIZE;
+ }
+
+ task_unlock(p);
+
+ if (tasksize <= 0)
+ continue;
+
+ gckOS_Print("<gpu> pid %d (%s), adj %d, size %d \n", p->pid, p->comm, oom_adj, tasksize);
+
+ if (selected) {
+ if (oom_adj < selected_oom_adj)
+ continue;
+ if (oom_adj == selected_oom_adj &&
+ tasksize <= selected_tasksize)
+ continue;
+ }
+ selected = p;
+ selected_tasksize = tasksize;
+ selected_oom_adj = oom_adj;
+ }
+ if (selected) {
+ gckOS_Print("<gpu> send sigkill to %d (%s), adj %d, size %d\n",
+ selected->pid, selected->comm,
+ selected_oom_adj, selected_tasksize);
+ lowmem_deathpending = selected;
+ lowmem_deathpending_timeout = jiffies + HZ;
+ force_sig(SIGKILL, selected);
+ ret = 0;
+ }
+ read_unlock(&tasklist_lock);
+ return ret;
+}
+
+#endif
/*******************************************************************************
**
@@ -465,6 +574,9 @@ _AllocateMemory(
gcuVIDMEM_NODE_PTR node = gcvNULL;
gctBOOL tileStatusInVirtual;
gctBOOL forceContiguous = gcvFALSE;
+#ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
+ gctBOOL forceContiguousShrinking = gcvFALSE;
+#endif
gcmkHEADER_ARG("Kernel=0x%x *Pool=%d Bytes=%lu Alignment=%lu Type=%d",
Kernel, *Pool, Bytes, Alignment, Type);
@@ -472,6 +584,9 @@ _AllocateMemory(
gcmkVERIFY_ARGUMENT(Pool != gcvNULL);
gcmkVERIFY_ARGUMENT(Bytes != 0);
+#ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
+_AllocateMemory_Retry:
+#endif
/* Get initial pool. */
switch (pool = *Pool)
{
@@ -617,10 +732,34 @@ _AllocateMemory(
if (node == gcvNULL)
{
+
+#ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
+ if(forceContiguous == gcvTRUE)
+ {
+ if(forceContiguousShrinking == gcvFALSE)
+ {
+ forceContiguousShrinking = gcvTRUE;
+ task_free_register(&task_nb);
+ }
+
+ if(force_contiguous_lowmem_shrink(Kernel) == 0)
+ {
+ /* Sleep 1 millisecond. */
+ gckOS_Delay(gcvNULL, 1);
+ goto _AllocateMemory_Retry;
+ }
+ }
+#endif
/* Nothing allocated. */
gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
}
+#ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
+ if(forceContiguous == gcvTRUE && forceContiguousShrinking == gcvTRUE)
+ {
+ task_free_unregister(&task_nb);
+ }
+#endif
/* Return node and pool used for allocation. */
*Node = node;