使用哈希桶管理进程页面

前言

前面通过bloom过滤器已经成功添加页面映射关系,现在在这个基础上来实现区分冷热页面的功能:
1、冷热页面根据pte_young判断页面最近是否被访问过,每次遍历完后通过pte_mkold清除。
2、每个周期遍历5次,设计8bit向量保存遍历结果,高5bit每1bit代表本次遍历结果,低3bit代表周期内总的访问次数。
3、使用hash桶管理每个页面的向量。
4、每个周期的第一次遍历添加bloom映射;每次遍历根据bloom映射结果添加页面到hash桶。
5、创建6个链表,将周期内访问次数相同的页面管理在一起。
6、每个周期的第五次遍历添加页面到链表。

一、驱动代码

test.c:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/miscdevice.h>

#include <linux/sched.h>
#include <linux/dcache.h>
#include <asm/fcntl.h>
#include <asm/processor.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/gpio.h>
#include <linux/sched/rt.h>
#include <uapi/linux/sched/types.h>
#include <linux/pid.h> 
#include <linux/delay.h>

#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/compiler.h>
#include <linux/mm.h>
#include <linux/page-flags.h>
#include <asm/pgtable.h>


#include "bloom.h"
#include "hash-bucket.h"

#define MY_DEV_NAME "my_dev"

#define TEST_PROC_DIR              "page_test"
#define TEST_PROC_NAME             "pid"

/*-------------------------------------------------------------------------*/

struct proc_dir_entry *test_proc_dir = NULL;
static int pid = -1;

static int test_proc_show(struct seq_file *m, void *v)
{
    seq_printf(m, "echo pid to start.now:");
    
    if(0 == pid)
    {
        seq_printf(m, "off\n");
    }else
    {
        seq_printf(m, "%d\n", pid);
    }
	
	return 0; //!! must be 0, or will show nothing T.T
}

static ssize_t test_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos)
{
    char *tmp = kzalloc((count + 1), GFP_KERNEL);
    if(!tmp){
        return -ENOMEM;
    }
    
    memset(tmp, 0x00, count+1);
    if(copy_from_user(tmp, buffer, count))
    {
        kfree(tmp);
        return -EFAULT;
    }
	
	sscanf(tmp, "%d", &pid);
 
    kfree(tmp);
    return count;
}

static int test_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, test_proc_show, NULL);
}

static struct file_operations proc_fops = {
    .owner = THIS_MODULE,
    .open = test_proc_open,
    .read = seq_read,
    .write = test_proc_write,
    .llseek = seq_lseek,
    .release = single_release,
};

static int init_test_proc(void)
{
    struct proc_dir_entry *file = NULL;
    
    test_proc_dir = proc_mkdir(TEST_PROC_DIR, NULL);
    if(NULL == test_proc_dir){
        pr_err("%s Create %s failed\n", __func__, TEST_PROC_DIR);
        return -EINVAL;
    }

    file = proc_create(TEST_PROC_NAME, 666, test_proc_dir,  &proc_fops);
    if(!file){
        pr_err("%s Create %s failed\n", __func__, TEST_PROC_NAME);
        return -EINVAL;
    }

    return 0;
}

static void proc_test_exit(void)
{
    proc_remove(test_proc_dir);
}


/*-------------------------------------------------------------------------*/


static int test_open(struct inode *inode, struct file *file)
{
	int major = MAJOR(inode->i_rdev);
	int minor = MINOR(inode->i_rdev);

	pr_info("%s: major=%d, minor=%d\n", __func__, major, minor);
	return 0;
}

static int test_release(struct inode *inode, struct file *file)
{
	pr_info("%s \n", __func__);

	return 0;
}

static ssize_t test_read(struct file *file, char __user *buf, size_t lbuf, loff_t *ppos)
{
	pr_info("%s \n", __func__);
	return 0;
}

static ssize_t test_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
	pr_info("%s \n", __func__);
	return 0;

}

static const struct file_operations test_fops = {
	.owner = THIS_MODULE,
	.open = test_open,
	.release = test_release,
	.read = test_read,
	.write = test_write
};

static struct miscdevice test_misc_device ={

	.minor = MISC_DYNAMIC_MINOR,
	.name = MY_DEV_NAME,
	.fops = &test_fops,
};

static struct task_struct  *thread_task;
static struct bloom bloom;
struct task_struct *get_task_by_pid(pid_t pid) {
    struct pid *proc_pid;
    struct task_struct *task;
 
    // 获取PID对象
    proc_pid = find_get_pid(pid);
    if (!proc_pid)
        return NULL;
 
    // 通过PID对象获取进程描述符
    task = pid_task(proc_pid, PIDTYPE_PID);
    if (!task) {
        put_pid(proc_pid);
        return NULL;
    }
 
    // 如果不需要再使用proc_pid,则释放它
    put_pid(proc_pid);
 
    // 返回进程描述符
    return task;
}

static unsigned long get_task_rss(struct mm_struct *mm)
{
    unsigned long anon, file, shmem;
    
	anon = get_mm_counter(mm, MM_ANONPAGES);
	file = get_mm_counter(mm, MM_FILEPAGES);
	shmem = get_mm_counter(mm, MM_SHMEMPAGES);

    return anon+file+shmem;
}

pte_t * virt2pte(struct mm_struct *mm, unsigned long vaddr)
{
    pgd_t *pgd;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *pte;
	//unsigned long pfn;
	//unsigned long phys;
    //struct page *page;
	
    // 获取PGD(页全局目录)
    pgd = pgd_offset(mm, vaddr);
    if (pgd_none(*pgd) || pgd_bad(*pgd)) {
        // PGD条目不存在或无效
        return NULL;
    }

    // 获取PUD(页上级目录)
    pud = pud_offset(pgd, vaddr);
    if (pud_none(*pud) || pud_bad(*pud)) {
        // PUD条目不存在或无效
        return NULL;
    }

    // 获取PMD(页中间目录)
    pmd = pmd_offset(pud, vaddr);
    if (pmd_none(*pmd) || !pmd_present(*pmd)) {
        // PMD条目不存在或无效,或者页面不在内存中
        return NULL;
    }

    // 使用pte_offset获取PTE(页表条目)
    pte = pte_offset_kernel(pmd, vaddr);
    if (!pte_present(*pte)) {
        // PTE条目不存在或无效
        return NULL;
    }
    
	return pte;
	//if (!(page = pte_page(*pte))){
   //     return 0;
	//}
	//phys = page_to_phys(page);
	
    // 现在可以安全地访问PTE了
    // 例如,获取页面帧号(PFN)
    //pfn = pte_pfn(*pte);

#if 0
	if(PageAnon(page))
	{
		//bit0为1,匿名映射
		printk("anon: pfn %lu, phy 0x%08lx, vaddr 0x%08lx\n", pfn, phys, vaddr);
	}
	else
	{
		//bit0为0,文件缓存
		printk("file: pfn %lu, phy 0x%08lx, vaddr 0x%08lx\n", pfn, phys, vaddr);
	}
#endif

	//return pfn;
}

static struct list_head    lrulists[6];
static int pid_thread(void *arg)
{
    struct task_struct *task;
    struct mm_struct *mm;
	struct vm_area_struct *vma = 0;
	struct HashTable *ht;
	pte_t *pte;
	struct PageInfo *pos, *n;

	unsigned long vpage = 0;	
	unsigned long pfn = 0;
	unsigned long rss = 0;
	unsigned long entries = 0;
	unsigned long collisions = 0;
	unsigned long check = 0;
	int hash_table_size = 0;
	unsigned char value = 0;
	int count = 0;
	
	while(pid == -1)
	{
		msleep(1000);
	}
	
    task = get_task_by_pid(pid); // 获取当前任务组长指针
    if (!task) {
        printk("Failed to find the process.\n");
        return -1;
    }
    
    mm = task->mm; // 获取进程的内存管理信息
    if (!mm || !mm->pgd) {
        printk("Invalid memory management information or page global directory is not initialized.\n");
        return -1;
    }
    
    rss = get_task_rss(mm);
    entries = 8*rss;
    bloom_init(&bloom, entries);
    
    hash_table_size = rss;
    ht = InitHashTable(hash_table_size);
    INIT_LIST_HEAD(&lrulists[0]);
    INIT_LIST_HEAD(&lrulists[1]);
    INIT_LIST_HEAD(&lrulists[2]);
    INIT_LIST_HEAD(&lrulists[3]);
    INIT_LIST_HEAD(&lrulists[4]);
    INIT_LIST_HEAD(&lrulists[5]);
    
    count = 0;
    while(count < 5)
    {
    	if (mm && mm->mmap){
            for (vma = mm->mmap; vma; vma = vma->vm_next){
                for (vpage = vma->vm_start; vpage < vma->vm_end; vpage += PAGE_SIZE){
                    pte = virt2pte(mm, vpage);

                    if(pte != NULL)
                    {
                        pfn = pte_pfn(*pte);
                        if(0 == count)
                        {
                            //先check,判断是否已经添加
                            if(!bloom_check(&bloom, (void *)&pfn, 8))
                            {
                                //如果是第一次扫描且页面未添加,则添加记录
                                bloom_add(&bloom, (void *)&pfn, 8);
                                collisions++;
                                if(pte_young(*pte))
                                {
                                    pte_mkold(*pte);
                                    value = 7-count;
                                }
                                else
                                {
                                    value = 0;
                                }

                                InsertNode(ht, pfn, value, hash_table_size);
                            }
                        }
                        else
                        {
                            //页面已添加
                            if(bloom_check(&bloom, (void *)&pfn, 8))
                            {
                                check++;
                                if(pte_young(*pte))
                                {
                                    pte_mkold(*pte);
                                    value = 7-count;
                                    InsertNode(ht, pfn, value, hash_table_size);
                                }

                                 if(4 == count)
                                {
                                    //最后一次扫描,创建LRU链表
                                    struct HashNode *tmp = NULL;
                                    unsigned char visits = 0;
                                    tmp = FindNode(ht, pfn, hash_table_size);
                                    if(tmp)
                                    {
                                        visits = (tmp->pageinfo->flag & 0x7);
                                        //printk("visits %x, list %p, lru %p\n", visits, &tmp->pageinfo->list, &lrulists[visits]);
                                        list_add(&tmp->pageinfo->list, &lrulists[visits]);
                                        
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        count++;
        msleep(1000*10);
    }
    
    printk("collisions %lu, check %lu, entries %lu\n", collisions, check/4, entries);
    display(ht, hash_table_size);

    for(count = 0; count < 6; count++)
    {
        printk("LRU[%d]:", count);
        
        list_for_each_entry_safe(pos,n, &lrulists[count], list) 
        {
            printk("%lu = %02x", pos->pfn, pos->flag);
        }
    }    

    FreeHashTable(ht, hash_table_size);
    bloom_free(&bloom);
	
	return 0;
}

static int __init test_init(void)
{
	int ret;

	pr_info("test_init\n");

	ret = misc_register(&test_misc_device);
	if (ret != 0 ) {
		pr_err("failed to misc_register");
		return ret;
	}
	thread_task = kthread_create(pid_thread, NULL, "pid-thread");
    wake_up_process(thread_task);
	init_test_proc();
	pr_err("Minor number = %d\n", test_misc_device.minor);

	return 0;
}

static void __exit test_exit(void)
{
	pr_info("test_exit\n");
    misc_deregister(&test_misc_device);
	proc_test_exit();
}

module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");

二、哈希桶

hash-bucket.c:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/miscdevice.h>

#include <linux/sched.h>
#include <linux/dcache.h>
#include <asm/fcntl.h>
#include <asm/processor.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/gpio.h>
#include <linux/sched/rt.h>
#include <uapi/linux/sched/types.h>
#include <linux/pid.h> 
#include <linux/delay.h>

#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/compiler.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>


#include "murmurhash2.h"
#include "hash-bucket.h"

static int SetPageFlag(unsigned char *value, char bit_index)
{
	unsigned char count = 0;
	unsigned char i, tmp;
	
	if(value == NULL)
	{
		return -1;
	}
	
	*value = (*value | (1 << bit_index));
	
	tmp = *value >> 3;
	
	for(i = 0; i < 5; i++)
	{
		if(tmp&0x1)
		{
			count++;
		}
		tmp  = tmp >> 1;
	}
	
	*value = ((*value & 0xF8) | count);

	return 0;
}

/*初始化哈希桶*/
struct HashTable *InitHashTable(int table_size)
{
    struct HashTable *t = (struct HashTable *)kmalloc(sizeof(struct HashTable), GFP_KERNEL);
    t->bucket = (struct HashNode *)kzalloc(table_size*(sizeof(struct HashNode)), GFP_KERNEL);
    
    return t;
}

/*哈希函数,根据生成哈希值*/
unsigned int Hash(const unsigned long key, int table_size)
{
    unsigned int seed = 0x9747b28c;
    register unsigned int a;
    register unsigned int b;
    register unsigned int x;
    
    a = murmurhash2(&key, 8, seed);
    b = murmurhash2(&key, 8, a);
    x = (a + b) % table_size;
    
    return x;
}

/*插入数据到hash表中*/
//bit_index 表示要设置的flag bit位,只能设置bit3~bit7
int InsertNode(struct HashTable *t, unsigned long key, unsigned char bit_index, int hash_table_size)
{
    int index;
	//e 当前链表节点,ep e的前一个链表节点
    struct HashNode *e, *ep;
    if(t == NULL){
		return -1;
	}

    index = Hash(key, hash_table_size);
    //如果现在桶为空,直接写入第一个桶节点
    if(NULL == t->bucket[index].pageinfo)
	{
	    t->bucket[index].pageinfo = (struct PageInfo*)kzalloc(sizeof(struct PageInfo), GFP_KERNEL);
        t->bucket[index].pageinfo->pfn = key;
        t->bucket[index].pageinfo->flag = 0;
        if((bit_index > 2) && (bit_index < 8))
        {
            SetPageFlag(&(t->bucket[index].pageinfo->flag), bit_index);
        }
    }
    else
	{
        e = ep = &(t->bucket[index]);
        /*先从已经存在的找*/
        while(e && e->pageinfo)
		{
            /*如果key值重复,替换相应的值*/
            if(e->pageinfo->pfn == key)
			{
				//更新值
                if((bit_index > 2) && (bit_index < 8))
                {
                    SetPageFlag(&(e->pageinfo->flag), bit_index);
                }
                return index;/*插入完成*/
            }
            ep = e;
            e = e->next;
        }
        /*没有在当前桶中找到,创建新的节点加入,并加入桶链表*/
        e = (struct HashNode *)kzalloc(sizeof(struct HashNode), GFP_KERNEL);
        if(NULL != e){
            e->pageinfo = (struct PageInfo*)kzalloc(sizeof(struct PageInfo), GFP_KERNEL);
            e->pageinfo->pfn = key;
            if((bit_index > 2) && (bit_index < 8))
            {
                SetPageFlag(&(e->pageinfo->flag), bit_index);
            }
            e->next = NULL;
            ep->next = e;
        }
    }
    
    return index;
}

struct HashNode *FindNode(struct HashTable *t, unsigned long key, int hash_table_size)
{
    int index;
	//e 当前链表节点,ep e的前一个链表节点
    struct HashNode *e, *ep;
    if(t == NULL){
		return NULL;
	}

    index = Hash(key, hash_table_size);
    //如果现在桶为空,直接返回NULL
    if(NULL == t->bucket[index].pageinfo)
	{
	    return NULL;
    }
    else
	{
        e = ep = &(t->bucket[index]);
        /*先从已经存在的找*/
        while(e && e->pageinfo)
		{
            /*key值匹配*/
            if(e->pageinfo->pfn == key)
			{
                return e;/*插入完成*/
            }
            ep = e;
            e = e->next;
        }
    }
    
    return NULL;
}

void FreeHashTable(struct HashTable *t, int table_size)
{
    int i;
	//e 当前链表节点,ep e的后一个链表节点
    struct HashNode *e, *ep;

    if(t == NULL){
		return ;
	}

    //先释放哈希桶链内存
    for(i = 0; i < table_size; i++){
        //如果哈希桶链不空
        if(t->bucket[i].next)
    	{
            e = ep = (t->bucket[i].next);
            /*next不为NULL,需要释放*/
            while(e)
    		{
                //释放前保存下一个next
                ep = e->next;
                kfree(e->pageinfo);
                kfree(e);
                e = ep;
            }
            t->bucket[i].next = NULL;
        }
    }

    //再释放哈希表节点
    kfree(t->bucket);

    //最后释放哈希桶
    kfree(t);

    t=NULL;
}


/*打印hash表*/

void display(struct HashTable *t, int hash_table_size)
{
    int i;
    struct HashNode *e;
    
    if(!t) {
        return;
    }

    for(i = 0; i < hash_table_size; i++){
        printk("bucket[%d]:", i);
        e = &(t->bucket[i]);
        while(e && e->pageinfo){
            printk("%lu = %02x",e->pageinfo->pfn, e->pageinfo->flag);
            e = e->next;
        }
        printk("\n");
    }
}

hash-bucket.h:

#ifndef _HASH_BUCKET
#define _HASH_BUCKET
#include <linux/list.h>

struct PageInfo
{
    unsigned long pfn;
    unsigned char flag;
    struct list_head list;
};

/*链表节点*/
struct HashNode
{
	struct PageInfo *pageinfo;
	struct HashNode *next;
};

/*顺序哈希桶*/
struct HashTable
{
    struct HashNode *bucket;
};

/*初始化哈希桶*/
struct HashTable *InitHashTable(int table_size);

/*哈希函数,根据生成哈希值*/
unsigned int Hash(const unsigned long key, int table_size);

/*插入数据到hash表中*/
int InsertNode(struct HashTable *t, unsigned long key, unsigned char value, int hash_table_size);
struct HashNode *FindNode(struct HashTable *t, unsigned long key, int hash_table_size);

/*释放hash表内存*/
void FreeHashTable(struct HashTable *t, int table_size);
int SetPageVector(unsigned char *value, char bit_index);

/*打印hash表*/

void display(struct HashTable *t, int hash_table_size);

#endif


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值