static int __init lowmem_init(void) { task_free_register(&task_nb); register_shrinker(&lowmem_shrinker); return 0; }
static int lowmem_shrink(struct shrinker *s, int nr_to_scan, gfp_t gfp_mask) { struct task_struct *p; struct task_struct *selected = NULL; int rem = 0; int tasksize; int i; int min_adj = OOM_ADJUST_MAX + 1; int selected_tasksize = 0; int selected_oom_adj; int array_size = ARRAY_SIZE(lowmem_adj); int other_free = global_page_state(NR_FREE_PAGES); int other_file = global_page_state(NR_FILE_PAGES); unsigned long flags; /* * 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) return 0; if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; for (i = 0; i < array_size; i++) { if (other_free < lowmem_minfree[i] && other_file < lowmem_minfree[i]) { min_adj = lowmem_adj[i]; break; } } if (min_adj == OOM_ADJUST_MAX + 1) return 0; if (nr_to_scan > 0) lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n", nr_to_scan, gfp_mask, other_free, other_file, min_adj); rem = global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + global_page_state(NR_INACTIVE_FILE); if (nr_to_scan <= 0) { lowmem_print(5, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); return rem; } selected_oom_adj = min_adj; read_lock(&tasklist_lock); for_each_process(p) { struct mm_struct *mm; struct signal_struct *sig; 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 = get_mm_rss(mm); task_unlock(p); if (tasksize <= 0) continue; 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; lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", p->pid, p->comm, oom_adj, tasksize); } if (selected) { spin_lock_irqsave(&lowmem_deathpending_lock, flags); if (!lowmem_deathpending) { lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", selected->pid, selected->comm, selected_oom_adj, selected_tasksize); lowmem_deathpending = selected; task_free_register(&task_nb); force_sig(SIGKILL, selected); rem -= selected_tasksize; } spin_unlock_irqrestore(&lowmem_deathpending_lock, flags); } else rem = -1; lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); read_unlock(&tasklist_lock); return rem; }
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) { struct task_struct *p; struct task_struct *selected = NULL; int rem = 0; int tasksize; int i; int min_adj = OOM_ADJUST_MAX + 1; int selected_tasksize = 0; int selected_oom_adj; int array_size = ARRAY_SIZE(lowmem_adj); int other_free = global_page_state(NR_FREE_PAGES); // int other_file = global_page_state(NR_FILE_PAGES); int other_file = global_page_state(NR_INACTIVE_FILE) + global_page_state(NR_ACTIVE_FILE); /* * 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 PERFOMANCE_RESEARCH LMK_LastWorkNumberPossProcesses = 0; LMK_PreviousWorkingTime = LMK_CurrentWorkingTime; LMK_CurrentWorkingTime = current_kernel_time(); printk("LowMemoryKiller has started!!!\n Worked <%d> times before PreviosWorkingTime<%ds><%dns>\n CurrentWorkingTime<%ds><%dns>\n", LMK_WorkCount++,LMK_PreviousWorkingTime.tv_sec,LMK_PreviousWorkingTime.tv_nsec,LMK_CurrentWorkingTime.tv_sec,LMK_CurrentWorkingTime.tv_nsec); #endif if (lowmem_deathpending) { #if PERFOMANCE_RESEARCH printk("LowMemoryKiller is going to exit because of lowmem_deathpending\n"); #endif return 0; } if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; for (i = 0; i < array_size; i++) { #if 1 if ((other_free + other_file) < lowmem_minfree[i]) #else if (other_free < lowmem_minfree[i] && other_file < lowmem_minfree[i]) #endif { min_adj = lowmem_adj[i]; break; } } if (min_adj == OOM_ADJUST_MAX + 1) return 0; if (nr_to_scan > 0) lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n", nr_to_scan, gfp_mask, other_free, other_file, min_adj); rem = global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + global_page_state(NR_INACTIVE_FILE); #if PERFOMANCE_RESEARCH printk("LowMemoryKiller semi-data: %d %x %d %d %d %d\n",nr_to_scan,gfp_mask,other_free,other_file,min_adj,rem); #endif if (nr_to_scan <= 0) { lowmem_print(5, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); return rem; } selected_oom_adj = min_adj; read_lock(&tasklist_lock); for_each_process(p) { struct mm_struct *mm; struct signal_struct *sig; 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 = get_mm_rss(mm); task_unlock(p); if (tasksize <= 0) continue; 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; lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", p->pid, p->comm, oom_adj, tasksize); #if PERFOMANCE_RESEARCH LMK_LastWorkNumberPossProcesses++; printk("LowMemoryKiller has found process for killing: pid=%d name=%s with oom_adj=%d\n", p->pid, p->comm,oom_adj); #endif } if (selected) { lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", selected->pid, selected->comm, selected_oom_adj, selected_tasksize); #if PERFOMANCE_RESEARCH printk("LowMemoryKiller is going to KILL: pid=%d name=%s with oom_adj=%d with size=%d (has chosen from %d)\n", selected->pid, selected->comm,selected_oom_adj, selected_tasksize,LMK_LastWorkNumberPossProcesses); LMK_TotalNUmberOfKilledProcesses++; #endif lowmem_deathpending = selected; task_free_register(&task_nb); force_sig(SIGKILL, selected); rem -= selected_tasksize; } else rem = -1; lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); read_unlock(&tasklist_lock); #if PERFOMANCE_RESEARCH LMK_TotalFreedMem+=selected_tasksize; printk("LowMemoryKiller : rem=%d, totalNumber=%d, selected_tasksize=%d, Totalfreed=%d ", rem, LMK_TotalNUmberOfKilledProcesses,selected_tasksize,LMK_TotalFreedMem); #endif return rem; }
static int drv_init(struct device *pdev) #endif { int ret; int result = -EINVAL; gceSTATUS status; gckGALDEVICE device = gcvNULL; struct class* device_class = gcvNULL; gcmkHEADER(); #if ENABLE_GPU_CLOCK_BY_DRIVER && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) { # if 0 struct clk * clk; clk = clk_get(NULL, "GCCLK"); if (IS_ERR(clk)) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): clk get error: %d\n", __FUNCTION__, __LINE__, PTR_ERR(clk) ); result = -ENODEV; gcmkONERROR(gcvSTATUS_GENERIC_IO); } /* * APMU_GC_156M, APMU_GC_312M, APMU_GC_PLL2, APMU_GC_PLL2_DIV2 currently. * Use the 2X clock. */ if (clk_set_rate(clk, coreClock * 2)) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Failed to set core clock.\n", __FUNCTION__, __LINE__ ); result = -EAGAIN; gcmkONERROR(gcvSTATUS_GENERIC_IO); } clk_enable(clk); #if defined(CONFIG_PXA_DVFM) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)) gc_pwr(1); # endif # endif } #endif printk(KERN_INFO "Galcore version %d.%d.%d.%d\n", gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD); /* when enable gpu profiler, we need to turn off gpu powerMangement */ if(gpuProfiler) powerManagement = 0; if (showArgs) { printk("galcore options:\n"); printk(" irqLine = %d\n", irqLine); printk(" registerMemBase = 0x%08lX\n", registerMemBase); printk(" registerMemSize = 0x%08lX\n", registerMemSize); if (irqLine2D != -1) { printk(" irqLine2D = %d\n", irqLine2D); printk(" registerMemBase2D = 0x%08lX\n", registerMemBase2D); printk(" registerMemSize2D = 0x%08lX\n", registerMemSize2D); } if (irqLineVG != -1) { printk(" irqLineVG = %d\n", irqLineVG); printk(" registerMemBaseVG = 0x%08lX\n", registerMemBaseVG); printk(" registerMemSizeVG = 0x%08lX\n", registerMemSizeVG); } printk(" contiguousSize = %ld\n", contiguousSize); printk(" contiguousBase = 0x%08lX\n", contiguousBase); printk(" bankSize = 0x%08lX\n", bankSize); printk(" fastClear = %d\n", fastClear); printk(" compression = %d\n", compression); printk(" signal = %d\n", signal); printk(" baseAddress = 0x%08lX\n", baseAddress); printk(" physSize = 0x%08lX\n", physSize); printk(" logFileSize = %d KB \n", logFileSize); printk(" powerManagement = %d\n", powerManagement); printk(" gpuProfiler = %d\n", gpuProfiler); #if ENABLE_GPU_CLOCK_BY_DRIVER printk(" coreClock = %lu\n", coreClock); #endif } if(logFileSize != 0) { gckDebugFileSystemInitialize(); } /* Create the GAL device. */ gcmkONERROR(gckGALDEVICE_Construct( irqLine, registerMemBase, registerMemSize, irqLine2D, registerMemBase2D, registerMemSize2D, irqLineVG, registerMemBaseVG, registerMemSizeVG, contiguousBase, contiguousSize, bankSize, fastClear, compression, baseAddress, physSize, signal, logFileSize, pdev, powerManagement, gpuProfiler, &device )); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) device->pool = dev_get_drvdata(pdev); #endif /* Start the GAL device. */ gcmkONERROR(gckGALDEVICE_Start(device)); if ((physSize != 0) && (device->kernels[gcvCORE_MAJOR] != gcvNULL) && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0)) { status = gckMMU_Enable(device->kernels[gcvCORE_MAJOR]->mmu, baseAddress, physSize); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, "Enable new MMU: status=%d\n", status); if ((device->kernels[gcvCORE_2D] != gcvNULL) && (device->kernels[gcvCORE_2D]->hardware->mmuVersion != 0)) { status = gckMMU_Enable(device->kernels[gcvCORE_2D]->mmu, baseAddress, physSize); gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, "Enable new MMU for 2D: status=%d\n", status); } /* Reset the base address */ device->baseAddress = 0; } #ifdef CONFIG_GPU_LOW_MEMORY_KILLER task_free_register(&task_nb); #endif #ifdef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT viv_gpu_resmem_handler.data = device->kernels[gcvCORE_MAJOR]; register_reserved_memory_account(&viv_gpu_resmem_handler); #endif /* Register the character device. */ ret = register_chrdev(major, DRV_NAME, &driver_fops); if (ret < 0) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Could not allocate major number for mmap.\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); } if (major == 0) { major = ret; } /* Create the device class. */ device_class = class_create(THIS_MODULE, "graphics_class"); if (IS_ERR(device_class)) { gcmkTRACE_ZONE( gcvLEVEL_ERROR, gcvZONE_DRIVER, "%s(%d): Failed to create the class.\n", __FUNCTION__, __LINE__ ); gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) device_create(device_class, NULL, MKDEV(major, 0), NULL, "galcore"); #else device_create(device_class, NULL, MKDEV(major, 0), "galcore"); #endif galDevice = device; gpuClass = device_class; gcmkTRACE_ZONE( gcvLEVEL_INFO, gcvZONE_DRIVER, "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n", __FUNCTION__, __LINE__, irqLine, contiguousSize, registerMemBase ); /* Success. */ gcmkFOOTER_NO(); return 0; OnError: /* Roll back. */ if (device_class != gcvNULL) { device_destroy(device_class, MKDEV(major, 0)); class_destroy(device_class); } if (device != gcvNULL) { gcmkVERIFY_OK(gckGALDEVICE_Stop(device)); gcmkVERIFY_OK(gckGALDEVICE_Destroy(device)); } gcmkFOOTER(); return result; }
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) { struct task_struct *p; struct task_struct *selected = NULL; int rem = 0; int tasksize; int i; int min_adj = OOM_ADJUST_MAX + 1; int selected_tasksize = 0; int selected_oom_adj; int array_size = ARRAY_SIZE(lowmem_adj); int other_free = global_page_state(NR_FREE_PAGES); int other_file = global_page_state(NR_FILE_PAGES); if (lowmem_deathpending) return 0; if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; for (i = 0; i < array_size; i++) { if (other_free < lowmem_minfree[i] && other_file < lowmem_minfree[i]) { min_adj = lowmem_adj[i]; break; } } if (nr_to_scan > 0) lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n", nr_to_scan, gfp_mask, other_free, other_file, min_adj); rem = global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + global_page_state(NR_INACTIVE_FILE); if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) { lowmem_print(5, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); return rem; } selected_oom_adj = min_adj; read_lock(&tasklist_lock); for_each_process(p) { struct mm_struct *mm; struct signal_struct *sig; 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 = get_mm_rss(mm); task_unlock(p); if (tasksize <= 0) continue; 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; lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", p->pid, p->comm, oom_adj, tasksize); } if (selected) { lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", selected->pid, selected->comm, selected_oom_adj, selected_tasksize); lowmem_deathpending = selected; task_free_register(&task_nb); force_sig(SIGKILL, selected); rem -= selected_tasksize; } lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); read_unlock(&tasklist_lock); return rem; }