前言
前面通过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
177

被折叠的 条评论
为什么被折叠?



