diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /fs/proc/sprd_debug/proc_usermeminfo.c | |
Diffstat (limited to 'fs/proc/sprd_debug/proc_usermeminfo.c')
| -rw-r--r-- | fs/proc/sprd_debug/proc_usermeminfo.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/fs/proc/sprd_debug/proc_usermeminfo.c b/fs/proc/sprd_debug/proc_usermeminfo.c new file mode 100644 index 00000000..434cf4c0 --- /dev/null +++ b/fs/proc/sprd_debug/proc_usermeminfo.c @@ -0,0 +1,174 @@ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/pid.h> +#include <asm/uaccess.h> +#include <asm/current.h> +#include <linux/mm.h> + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("userspace process memory info device"); + +struct user_process_mem_info { + unsigned long vss; + unsigned long rss; + unsigned long rss_mapped; + unsigned long pss; + unsigned long uss; + int task_pid; +}; + +static int memoryinfo_flag = 0; + +static pte_t check_pte(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset(mm, address); + if (!pgd_present(*pgd)) + goto check_fail; + + pud = pud_offset(pgd, address); + if (!pud_present(*pud)) + goto check_fail; + + pmd = pmd_offset(pud, address); + if (!pmd_present(*pmd)) + goto check_fail; + if (pmd_trans_huge(*pmd)) + goto check_fail; + + pte = pte_offset_map(pmd, address); + if (!pte_present(*pte)) + goto check_fail; + + return *pte; + +check_fail: + return 0; +} + + +static struct page *check_pfn(pte_t pte) +{ + if (!pte_pfn(pte)) + return NULL; + else + return pfn_to_page(pte_pfn(pte)); +} + +int get_userprocess_meminfo(struct task_struct* p, struct user_process_mem_info *upmeminfo) +{ + struct vm_area_struct *vma = NULL; + if (p->mm == NULL) + return -1; + + upmeminfo->task_pid = p->pid; + for (vma = p->mm->mmap; vma; vma = vma->vm_next) { + unsigned long pagesize = PAGE_SIZE; + unsigned long step = vma->vm_start; + + for(; step < vma->vm_end; step += pagesize) { + pte_t pte; + int mapcount; + struct page *page; + + /*!!! VSS in procrank equals rss, and actually wrong !!!*/ + upmeminfo->vss += pagesize; /*vss*/ + pte = check_pte(p->mm, step); + if(!pte) continue; + + page = check_pfn(pte); + if(!page) continue; + + /*!!! RSS in procrank equals rss_mapped, and actually wrong !!!*/ + upmeminfo->rss += pagesize; /*rss*/ + mapcount = page_mapcount(page); + if(2 <= mapcount) { + upmeminfo->rss_mapped += pagesize; /*rss_mapped*/ + upmeminfo->pss += pagesize / mapcount; /*pss*/ + } else if (1 == mapcount) { + upmeminfo->rss_mapped += pagesize; /*rss_mapped*/ + upmeminfo->pss += pagesize; /*pss*/ + upmeminfo->uss += pagesize; /*uss*/ + } else if (0 == mapcount) { + /*this is the difference between rss & rss_mapped.*/ + } + } + } + + return 0; +} + +int user_process_meminfo_show(void) +{ + struct task_struct *p = NULL; + struct user_process_mem_info upmeminfo; + + printk(KERN_INFO "%5s %11s %9s %11s %9s %9s %s\n", + "pid", "vss", "rss", "rss_mapped", "pss", "uss", "name"); + + printk(KERN_INFO "-----------------------------------------------------------------\n"); + for_each_process(p) { + memset(&upmeminfo, 0, sizeof(upmeminfo)); + if (get_userprocess_meminfo(p, &upmeminfo)) + continue; + + printk(KERN_INFO "%5d %10luK %8luK %10luK %8luK %8luK %s\n", + upmeminfo.task_pid, + upmeminfo.vss >> 10, + upmeminfo.rss >> 10, + upmeminfo.rss_mapped >> 10, + upmeminfo.pss >> 10, + upmeminfo.uss >> 10, + p->comm); + } + + return 0; +} + +static int proc_user_process_meminfo_show(struct seq_file *m, void *v) +{ + struct task_struct *p = NULL; + struct user_process_mem_info upmeminfo; + + seq_printf(m, "%5s %11s %9s %11s %9s %9s %s\n", + "pid", "vss", "rss", "rss_mapped", "pss", "uss", "name"); + + seq_printf(m, "-----------------------------------------------------------------\n"); + for_each_process(p) { + memset(&upmeminfo, 0, sizeof(upmeminfo)); + if (get_userprocess_meminfo(p, &upmeminfo)) + continue; + + seq_printf(m, "%5d %10luK %8luK %10luK %8luK %8luK %s\n", + upmeminfo.task_pid, + upmeminfo.vss >> 10, + upmeminfo.rss >> 10, + upmeminfo.rss_mapped >> 10, + upmeminfo.pss >> 10, + upmeminfo.uss >> 10, + p->comm); + } + + return 0; +} + +static int proc_user_process_meminfo_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_user_process_meminfo_show, NULL); +} + +struct file_operations user_process_meminfo_fops = { + .open = proc_user_process_meminfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + |
