diff -Naur a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h --- a/include/asm-i386/unistd.h Tue Jul 15 12:42:43 EDT 2003 +++ b/include/asm-i386/unistd.h Tue Jul 15 12:42:43 EDT 2003 277c277,282 < #define NR_syscalls 268 --- > #ifdef CONFIG_MEMORY_DIFF > #define __NR_memdiffctrl (__NR_clock_nanosleep+1) > #define NR_syscalls 269 > #else > #define NR_syscalls 268 > #endif diff -Naur a/include/linux/mm.h b/include/linux/mm.h --- a/include/linux/mm.h Tue Jul 15 12:42:43 EDT 2003 +++ b/include/linux/mm.h Tue Jul 15 12:42:43 EDT 2003 175a176,183 > #ifdef CONFIG_MEMORY_DIFF > /* > * We borrow the pte_chain's lock to protect the following 'class'. > */ > struct diff_mem_class* class; > pid_t pid; > #endif > 197a206,238 > #ifdef CONFIG_MEMORY_DIFF > /* > * We borrow the pte_chain's lock to protect the following page->class. > * The following two functions are copied from rmap_locking.h > */ > #define PG_classlock PG_chainlock > static inline void page_class_lock(struct page *page) > { > /* > * Assuming the lock is uncontended, this never enters > * the body of the outer loop. If it is contended, then > * within the inner loop a non-atomic test is used to > * busywait with less bus contention for a good time to > * attempt to acquire the lock bit. > */ > preempt_disable(); > #ifdef CONFIG_SMP > while (test_and_set_bit(PG_classlock, &page->flags)) { > while (test_bit(PG_classlock, &page->flags)) > cpu_relax(); > } > #endif > } > static inline void page_class_unlock(struct page *page) > { > #ifdef CONFIG_SMP > smp_mb__before_clear_bit(); > clear_bit(PG_classlock, &page->flags); > #endif > preempt_enable(); > } > #endif > diff -Naur a/include/linux/mm_inline.h b/include/linux/mm_inline.h --- a/include/linux/mm_inline.h Tue Jul 15 12:42:44 EDT 2003 +++ b/include/linux/mm_inline.h Tue Jul 15 12:42:44 EDT 2003 6a7,18 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) { > atomic_inc(&page->class->nr_active); > #if defined(CONFIG_MDIFF_CLASS_RECLAIM) && defined (CONFIG_MDIFF_CLASS_NEGATIVE) > atomic_inc(&page->class->nr_positivemove); > #endif > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missact); > #endif > #endif 13a26,43 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) { > atomic_inc(&page->class->nr_inactive); > #if defined(CONFIG_MDIFF_CLASS_RECLAIM) && defined (CONFIG_MDIFF_CLASS_NEGATIVE) > /* > * page may move from swap to inactive. this movement should > * count for positive move, > * and active to inactive should count for negative. But it will > * not reach here since it operates on the list directly > */ > atomic_inc(&page->class->nr_positivemove); > #endif > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missinact); > #endif > #endif 20a51,59 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) { > atomic_dec(&page->class->nr_active); > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missactsub); > #endif > #endif 27a67,74 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) > atomic_dec(&page->class->nr_inactive); > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missinactsub); > #endif > #endif 36a84,92 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) { > atomic_dec(&page->class->nr_active); > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missactsub); > #endif > #endif 38a95,102 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) > atomic_dec(&page->class->nr_inactive); > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missinactsub); > #endif > #endif diff -Naur a/include/linux/pagemap.h b/include/linux/pagemap.h --- a/include/linux/pagemap.h Tue Jul 15 12:42:44 EDT 2003 +++ b/include/linux/pagemap.h Tue Jul 15 12:42:44 EDT 2003 127a128,175 > #ifdef CONFIG_MEMORY_DIFF > page_class_lock(page); > if (!page_mapped(page)) { > /* > #ifdef CONFIG_MDIFF_PAGECACHE_CLASS > if (page->class) { > printk("page has class information already, mapping=%p:%p\n", > mapping, &swapper_space); > goto endit; > } > else > page->class = &pgcache_mem_class; > #else > */ > void* cls = page->class; > if (!current->class) { > printk("current thread has no class!,mp=%p,sw=%p\n",mapping,&swapper_space); > page->class = &def_mem_class; > } > else { > page->class = current->class; > page->pid = current->pid; > } > /* > #endif > */ > mem_class_get(page->class); > atomic_inc(&page->class->nr_total); > > > if (0) {// (!cls) { > /* check whether the page is already in LRU, then we may miss it */ > /* Wrong, we didn't hold the lock, so somebody else may ..., but temporarily before we find > * why it is added without setting class, ... , we should hold the zone LRU lock.*/ > printk("repair for leak page(type:%s)\n", PageActive(page) ? "Active":"Inactive"); > if (PageLRU(page)){ > if (PageActive(page)) > atomic_inc(&page->class->nr_active); > else > atomic_inc(&page->class->nr_inactive); > > } > } > > } > endit: > page_class_unlock(page); > #endif diff -Naur a/include/linux/proc_fs.h b/include/linux/proc_fs.h --- a/include/linux/proc_fs.h Tue Jul 15 12:42:44 EDT 2003 +++ b/include/linux/proc_fs.h Tue Jul 15 12:42:44 EDT 2003 226a227,230 > #ifdef CONFIG_MEMORY_DIFF > extern void proc_memclass_init(void); > #endif > diff -Naur a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Tue Jul 15 12:42:44 EDT 2003 +++ b/include/linux/sched.h Tue Jul 15 12:42:44 EDT 2003 218a219,229 > #ifdef CONFIG_MEMORY_DIFF > /* we will chain all tasks who share this active mm_struct > * into a list, so that we can do reverse mapping from > * mm_struct to tasks > * and this list should be protected by per mm_struct's > * peertask_lock; > */ > struct list_head tasklist; > spinlock_t peertask_lock; > struct diff_mem_class* class; > #endif 314a326,425 > #ifdef CONFIG_MEMORY_DIFF > > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > extern atomic_t missact; > extern atomic_t missinact; > extern atomic_t missactsub; > extern atomic_t missinactsub; > #endif > > extern spinlock_t mem_class_lock; > extern struct list_head diff_mem_list; > > /* All processes who are not assigned class explicitly belong > * to this default memory class. Refer to its initilization in > * init/main.c > */ > extern struct diff_mem_class def_mem_class; > > #ifdef CONFIG_MDIFF_PAGECACHE_CLASS > extern struct diff_mem_class pgcache_mem_class; > #endif > > #define mem_class_get(cls) do{ atomic_inc(&((cls)->count));}while(0) > #define mem_class_put(cls) \ > do{ if (atomic_dec_and_test(&((cls)->count))) if((cls)->classid) kfree(cls);}while(0) > > #define mem_class_free(cls) mem_class_put(cls) > > /* whether the page reclaimable */ > /* determined after shrink_list based on nr_shrinkscan/nr_posistive move as well as pgfault */ > #define MCLS_READY_SHRINK 1 > /* whether counts for refill_inactive */ > /* determined before call refill_inactive based on memory share threshold > * and maybe MCLS_READY_SHRINK. > */ > #define MCLS_READY_REFILL 2 > /* whether be selected as reclaimable candidate for reference check */ > /* determined after refill_inactive based on nr_active/nr_inactive */ > #define MCLS_READY_SCAN 3 > > #define MCLS_readyshrink(cls) test_bit(MCLS_READY_SHRINK, &(cls)->flags) > #define MCLS_readyrefill(cls) test_bit(MCLS_READY_REFILL, &(cls)->flags) > #define MCLS_readyscan(cls) test_bit(MCLS_READY_SCAN, &(cls)->flags) > > #define MCLS_set_readyshrink(cls) set_bit(MCLS_READY_SHRINK, &(cls)->flags) > #define MCLS_set_readyrefill(cls) set_bit(MCLS_READY_REFILL, &(cls)->flags) > #define MCLS_set_readyscan(cls) set_bit(MCLS_READY_SCAN, &(cls)->flags) > > #define MCLS_reset_readyshrink(cls) clear_bit(MCLS_READY_SHRINK, &(cls)->flags) > #define MCLS_reset_readyrefill(cls) clear_bit(MCLS_READY_REFILL, &(cls)->flags) > #define MCLS_reset_readyscan(cls) clear_bit(MCLS_READY_SCAN, &(cls)->flags) > > struct diff_mem_class { > /* suppose we link all diff_mem_class together */ > struct list_head list; > > unsigned long flags; > > /* > * It seems that the nr_active/nr_inactive per class should be > * maintained per-zone/per-node, but it will makes the structure > * too complex. Since there is only one node right now, and the > * concept of zone may disappear in the future, we only maintain > * a global nr_active/nr_inactive. > * Note that the total of nr_active of all class should equal to > * the sum of all nr_active in all zones. We use atomic_t type to > * avoid lock. It is impossible to use the per zone LRU lock unless > * we maintain per zone value later. > */ > atomic_t nr_total; > atomic_t nr_active; > atomic_t nr_inactive; > > /* > * We don't want to do complex calculation to determine how > * many pages to reclaim from each class every time we need to > * shrink the cache. We calculate a threshold based on memory > * share for each class, then if nr_total exceeds this value, > * the pages belonging to this class are candidates for reclaim. > * If no class exceeds the threashold (the value diffs for every > * class), all pages are candidates. But this should not happen > * often, since in that case, most likely there is no need to > * shrink cache. > * MCLS_READY_SRHINK bit in flag is used for this purpose. > * Note that there are still some physical pages we not count > * (kernel resources, socket buffer etc.), it is possible. > * One of our work is to determine a proper threshold based all > * these factors. > */ > unsigned long shrink_threshold; > > atomic_t count; > int classid; > }; > > #if defined(CONFIG_MDIFF_CLASS_RECLAIM) && \ > defined(CONFIG_MDIFF_CLASS_NEGATIVE) > void mem_class_priority_adjust_temp(struct diff_mem_class* cls); > void mem_class_priority_adjust(struct diff_mem_class* cls); > #endif 315a427 > #endif 340a453,460 > #ifdef CONFIG_MEMORY_DIFF > /* > * list of all tasks sharing ownership of mm. > */ > struct list_head peertask_list; > struct diff_mem_class* class; > #endif > diff -Naur a/fs/exec.c b/fs/exec.c --- a/fs/exec.c Tue Jul 15 12:42:44 EDT 2003 +++ b/fs/exec.c Tue Jul 15 12:42:44 EDT 2003 521a522,541 > > #ifdef CONFIG_MEMORY_DIFF > spin_lock(&mm->peertask_lock); > list_add_tail(&tsk->peertask_list, &mm->tasklist); > > if (!tsk->class) > BUG(); > > if (!mm->class) { > mem_class_get(tsk->class); > mm->class=tsk->class; > } > else{ > if (mm->class != tsk->class) { > printk("Mismatch of class for virtual memory space and task\n"); > } > } > spin_unlock(&mm->peertask_lock); > #endif > 776a797,800 > #ifdef CONFIG_MEMORY_DIFF > extern int idx_cls; > #endif > 1049a1074,1200 > #ifdef CONFIG_MEMORY_DIFF > /* > * the following 2 functions are from dcache.c to get the current directory inside of kernel > */ > /** > * d_path - return the path of a dentry > * @dentry: dentry to report > * @vfsmnt: vfsmnt to which the dentry belongs > * @root: root dentry > * @rootmnt: vfsmnt to which the root dentry belongs > * @buffer: buffer to return value in > * @buflen: buffer length > * > * Convert a dentry into an ASCII path name. If the entry has been deleted > * the string " (deleted)" is appended. Note that this is ambiguous. Returns > * the buffer. > * > * "buflen" should be %PAGE_SIZE or more. Caller holds the dcache_lock. > */ > static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, > struct dentry *root, struct vfsmount *rootmnt, > char *buffer, int buflen) > { > char * end = buffer+buflen; > char * retval; > int namelen; > > *--end = '\0'; > buflen--; > if (!IS_ROOT(dentry) && d_unhashed(dentry)) { > buflen -= 10; > end -= 10; > memcpy(end, " (deleted)", 10); > } > > /* Get '/' right */ > retval = end-1; > *retval = '/'; > > for (;;) { > struct dentry * parent; > > if (dentry == root && vfsmnt == rootmnt) > break; > if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { > /* Global root? */ > if (vfsmnt->mnt_parent == vfsmnt) > goto global_root; > dentry = vfsmnt->mnt_mountpoint; > vfsmnt = vfsmnt->mnt_parent; > continue; > } > parent = dentry->d_parent; > prefetch(parent); > namelen = dentry->d_name.len; > buflen -= namelen + 1; > if (buflen < 0) > return ERR_PTR(-ENAMETOOLONG); > end -= namelen; > memcpy(end, dentry->d_name.name, namelen); > *--end = '/'; > retval = end; > dentry = parent; > } > > return retval; > > global_root: > namelen = dentry->d_name.len; > buflen -= namelen; > if (buflen >= 0) { > retval -= namelen-1; /* hit the slash */ > memcpy(retval, dentry->d_name.name, namelen); > } else > retval = ERR_PTR(-ENAMETOOLONG); > return retval; > } > static long kgetcwd(char *buf, unsigned long size) > { > int error; > struct vfsmount *pwdmnt, *rootmnt; > struct dentry *pwd, *root; > char *page = (char *) __get_free_page(GFP_USER); > > if (!page) > return -ENOMEM; > > read_lock(¤t->fs->lock); > pwdmnt = mntget(current->fs->pwdmnt); > pwd = dget(current->fs->pwd); > rootmnt = mntget(current->fs->rootmnt); > root = dget(current->fs->root); > read_unlock(¤t->fs->lock); > > error = -ENOENT; > /* Has the current directory has been unlinked? */ > spin_lock(&dcache_lock); > if (pwd->d_parent == pwd || !d_unhashed(pwd)) { > unsigned long len; > char * cwd; > > cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); > spin_unlock(&dcache_lock); > > error = PTR_ERR(cwd); > if (IS_ERR(cwd)) > goto out; > > error = -ERANGE; > len = PAGE_SIZE + page - cwd; > if (len <= size) { > error = len; > strcpy(buf,cwd); > } > } else > spin_unlock(&dcache_lock); > > out: > dput(pwd); > mntput(pwdmnt); > dput(root); > mntput(rootmnt); > free_page((unsigned long) page); > return error; > } > > #endif 1063c1214,1251 < sched_balance_exec(); --- > #ifdef CONFIG_MEMORY_DIFF > char* cwd; > > if (filename[0]=='/') { > cwd = filename; > } > else{ > cwd = __getname(); > if (cwd) > kgetcwd(cwd,PATH_MAX); > } > > if (cwd[0]=='/') { > if (!strncmp(cwd+1,"class",5) ){ > int clsid = cwd[6]-'0'; > if (clsid>=0 && clsid<idx_cls) { > struct diff_mem_class* cls=NULL; > spin_lock(&mem_class_lock); > list_for_each_entry(cls, &diff_mem_list, list) { > if (cls->classid==clsid) > goto found_cls; > } > cls = NULL; > found_cls: > if (cls && cls!=current->class) { > if (current->class) { > // printk("put memclass classid=%d, count=%d\n", > // current->class->classid, > // atomic_read(¤t->class->count)); > mem_class_put(current->class); > } > mem_class_get(cls); > current->class = cls; > } > spin_unlock(&mem_class_lock); > } > } > } 1064a1253,1258 > if (filename[0]!='/' && cwd) > putname(cwd); > > #endif > sched_balance_exec(); > diff -Naur a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c --- a/fs/proc/proc_misc.c Tue Jul 15 12:42:44 EDT 2003 +++ b/fs/proc/proc_misc.c Tue Jul 15 12:42:44 EDT 2003 689a690,1209 > > #ifdef CONFIG_MEMORY_DIFF > > int shared_vars[0x10]; > > extern int idx_cls; > extern int sys_memdiffctrl(int type, int arg); > extern int memdiff_redefine(int clsid, int arg); > > #define MAX_PIN_MEM 400 > int num_pinmem = 0; > void* pinmem[MAX_PIN_MEM]; > > static int shared_vars_write_proc(struct file* file, const char* buffer, unsigned long count, void* data) > { > int index = (int)data; > if (index<0 || index>=sizeof(shared_vars)/sizeof(shared_vars[0])) { > return 0; > } > if (count>0) > sscanf(buffer, "%d", shared_vars+index); > return count; > } > > int shared_vars_read_proc(char* page, char**start, off_t off, int count, int *eof, void* data) > { > int index = (int)data; > > if (index<0 || index>=sizeof(shared_vars)/sizeof(shared_vars[0])) > return 0; > > if (off>0 || count<0x10) { > *eof=1; > *start=page; > return 0; > } > > count = sprintf(page, "%d", shared_vars[index]); > *eof = 1; > *start = page; > return count; > } > > static int memeat_write_proc(struct file*file, const char* buffer, > unsigned long count, void* data) > { > char info[0x20]; > int i, pin; > > if (count>sizeof(info)-1) > return -EINVAL; > > if (copy_from_user(info, buffer, count)) > return -EFAULT; > > sscanf(info, "%d\n",&pin); > if (pin<0) { > printk("invalid value write to memory pindown request\n"); > return -EINVAL; > } > if (pin>MAX_PIN_MEM) > pin = MAX_PIN_MEM; > > if (pin<num_pinmem) { > for (i=pin;i<num_pinmem;i++) { > vfree(pinmem[i]); > pinmem[i]=NULL; > } > num_pinmem=pin; > } > else { > for (i=num_pinmem; i<pin; i++) { > pinmem[i]=vmalloc(1<<20); > if (!pinmem[i]) > break; > } > num_pinmem=i; > } > > printk("Current pindown memory size: %d(MBytes)\n", num_pinmem); > > return count; > } > > int memeat_read_proc(char* page, char**start, off_t off, int count, > int *eof, void* data) > { > int n; > char* ptr; > struct list_head* l; > > ptr = page; > if ( count<10) { > *eof=1; > *start=page; > return 0; > } > memset(ptr,0x20,count); > > n = sprintf(ptr, "%d", num_pinmem); > if (off>=n) { > *eof=1; > *start=page; > return 0; > } > *start = page+off; > *eof=1; > > printk("actmis:%d,%d inactmis:%d,%d\n", missact, missactsub, missinact, missinactsub); > > if (0) > //if (atomic_read(&cls->nr_active)<0 || atomic_read(&cls->nr_inactive)<0) > { > int i, c; > int cnt[idx_cls+1]; > int act[4], inact[4]; > > spin_lock(&mem_class_lock); > /* calc the number of classes */ > list_for_each(l, &diff_mem_list) { > struct diff_mem_class* cls; > cls = list_entry(l, struct diff_mem_class, list ); > if ( cls->classid<4 ) { > act[cls->classid] = atomic_read(&cls->nr_active); > inact[cls->classid] = atomic_read(&cls->nr_inactive); > } > } > spin_unlock(&mem_class_lock); > printk("Act/Inact 0:%d,%d 2:%d,%d 3:%d,%d\n", act[0], inact[0], act[2], inact[2], act[3], inact[3]); > > for (c=0; c<2; c++) { > > struct page* pg; > struct zone* zone = &(contig_page_data.node_zones[c]); > if (!spin_trylock(&zone->lru_lock)) { > printk("fail to lock zone'lru\n"); > continue; > } > > memset(cnt, 0, sizeof(cnt)); > printk("class active number ="); > list_for_each_entry(pg, &zone->active_list, lru) > { > if (pg->class) { > if(pg->class->classid>=idx_cls) > cnt[idx_cls]++; > else > cnt[pg->class->classid]++; > } > else { > cnt[idx_cls]++; > } > } > for (i=0; i<idx_cls+1; i++) > printk("%d ", cnt[i]); > printk("\n"); > > memset(cnt, 0, sizeof(cnt)); > printk("class inactive number ="); > list_for_each_entry(pg, &zone->inactive_list, lru) > { > if (pg->class) { > if(pg->class->classid>=idx_cls) > cnt[idx_cls]++; > else > cnt[pg->class->classid]++; > } > else { > cnt[idx_cls]++; > } > } > for (i=0; i<idx_cls+1; i++) > printk("%d ", cnt[i]); > printk("\n"); > > spin_unlock(&zone->lru_lock); > } > } > return n-off; > } > > /* > * class definition write in the format of > classid, maxshare, minshare > */ > static int clsdef_write_proc( struct file *file, > const char *buffer, unsigned long count, void *data) > { > char info[0x20]; > int classid, softmaxshare; > > if (count>sizeof(info)-1) > return -EINVAL; > > if (copy_from_user(info, buffer, count)) > return -EFAULT; > > sscanf(info, "%d%d\n",&classid, &softmaxshare); > if (classid>idx_cls || classid<0) { > printk("invalid value write to memory class definition\n"); > return -EINVAL; > } > if (classid==idx_cls) { > // create new clas > sys_memdiffctrl(3,softmaxshare); > } > else { > // redefine the threshold > memdiff_redefine( classid, softmaxshare); > } > > printk("define class %d, %d\n", classid, softmaxshare); > > return count; > } > > #define MDIFF_CLSDEF_ENTRY_LEN 48 > #define MDIFF_CLSDEF_ENTRY_FORMAT "%5d %10lu %10d %10d\n" > > int clsdef_read_proc_ex(char* page, char**start, off_t off, int count, int *eof, void* data) > { > int n; > struct list_head* l; > char* buf; > char* ptr; > char entry[MDIFF_CLSDEF_ENTRY_LEN+16]; > > buf = kmalloc(idx_cls*MDIFF_CLSDEF_ENTRY_LEN, GFP_KERNEL); > if (!buf) { > *eof=1; > *start=page; > return 0; > } > > ptr = buf; > memset(buf,0x20,idx_cls*MDIFF_CLSDEF_ENTRY_LEN); > > spin_lock(&mem_class_lock); > /* calc the number of classes */ > list_for_each(l, &diff_mem_list) { > struct diff_mem_class* cls; > > if (ptr+MDIFF_CLSDEF_ENTRY_LEN> buf+idx_cls*MDIFF_CLSDEF_ENTRY_LEN) > break; > > cls = list_entry(l, struct diff_mem_class, list ); > n = sprintf(entry, MDIFF_CLSDEF_ENTRY_FORMAT, > cls->classid, > cls->shrink_threshold, > atomic_read(&cls->nr_active), > atomic_read(&cls->nr_inactive)); > memcpy(ptr+(MDIFF_CLSDEF_ENTRY_LEN-n), entry, n); > ptr += MDIFF_CLSDEF_ENTRY_LEN; > } > spin_unlock(&mem_class_lock); > > if (off>=(ptr-buf)) { > *eof=1; > *start=page; > kfree(buf); > return 0; > } > > if (count>(ptr-buf)-off) { > *eof=1; > memcpy(page,buf,(ptr-buf)-off); > *start=page; > kfree(buf); > return (ptr-buf)-off; > } > else { > *eof=0; > memcpy(page,buf,count); > *start=page; > kfree(buf); > return count; > } > > } > > int clsdef_read_proc(char* page, char**start, off_t off, int count, int *eof, void* data) > { > int n; > struct list_head* l; > char* ptr; > char entry[MDIFF_CLSDEF_ENTRY_LEN+16]; > > ptr = page; > if ( count<idx_cls*MDIFF_CLSDEF_ENTRY_LEN) { > *eof=1; > *start=page; > return 0; > } > memset(ptr,0x20,count); > > spin_lock(&mem_class_lock); > /* calc the number of classes */ > list_for_each(l, &diff_mem_list) { > struct diff_mem_class* cls; > > if (ptr+MDIFF_CLSDEF_ENTRY_LEN>page+count) > break; > > cls = list_entry(l, struct diff_mem_class, list ); > n = sprintf(entry, MDIFF_CLSDEF_ENTRY_FORMAT, > cls->classid, > cls->shrink_threshold, > atomic_read(&cls->nr_active), > atomic_read(&cls->nr_inactive)); > > if (n>MDIFF_CLSDEF_ENTRY_LEN) { > printk("not enough len for memdiff/classdef-entry\n"); > memcpy(ptr, entry, MDIFF_CLSDEF_ENTRY_LEN); > } > else > memcpy(ptr+(MDIFF_CLSDEF_ENTRY_LEN-n), entry, n); > ptr += MDIFF_CLSDEF_ENTRY_LEN; > } > spin_unlock(&mem_class_lock); > > if (off>=(ptr-page)) { > *eof=1; > *start=page; > return 0; > } > > *start = page+off; > *eof=1; > return ptr-page-off; > } > > //temporarily count pid < 4096 > #define COUNTPID_MAXIDX 8192 > int countall[COUNTPID_MAXIDX]; > #define MYMAXPID COUNTPID_MAXIDX-4 > #define MYLGPID COUNTPID_MAXIDX-3 > #define MYNOCLSPID COUNTPID_MAXIDX-2 > #define MYNOTSKPID COUNTPID_MAXIDX-1 > > int pgcount_read_proc(char* page, char**start, off_t off, int count, int *eof, void* data) > { > struct page* pg; > int cls = (int)data; > struct zone* zone = &(contig_page_data.node_zones[cls]); > char entry[0x20]; > > char * ptr = page; > int done=0; > int i, t; > > if (off>0) { > *eof = 1; > *start=page; > return 0; > } > > if (!spin_trylock(&zone->lru_lock)) { > *eof = 1; > *start=page; > return 0; > } > > memset(countall, 0, sizeof(countall)); > > list_for_each_entry(pg, &zone->active_list, lru) > { > if (pg->class) { > if (pg->pid>MYMAXPID) > countall[MYLGPID]++; > else if (pg->pid<0) > countall[MYNOTSKPID]++; > else > countall[pg->pid]++; > } > else { > countall[MYNOCLSPID]++; > } > } > list_for_each_entry(pg, &zone->inactive_list, lru) > { > if (pg->class) { > if (pg->pid>MYMAXPID) > countall[MYLGPID]++; > else if (pg->pid<0) > countall[MYNOTSKPID]++; > else > countall[pg->pid]++; > } > else { > countall[MYNOCLSPID]++; > } > } > > spin_unlock(&zone->lru_lock); > > for (i=0; i<=MYMAXPID; i++) { > if (countall[i]>0) { > struct task_struct *tsk = find_task_by_pid(i); > if ( tsk ) { > t = sprintf(entry, "%d %s\n",countall[i], tsk->comm); > if ( done+t <= count) { > memcpy(ptr, entry, t); > ptr += t; > done+= t; > } > else > goto finishit; > } > else > countall[MYNOTSKPID] += countall[i]; > } > } > > t = sprintf(entry, "%d noclass\n", countall[MYNOCLSPID]); > if ( done+t <= count) { > memcpy(ptr, entry, t); > ptr += t; > done+= t; > } > else > goto finishit; > > t = sprintf(entry, "%d notask\n", countall[MYNOTSKPID]); > if ( done+t <= count) { > memcpy(ptr, entry, t); > ptr += t; > done+= t; > } > else > goto finishit; > > t = sprintf(entry, "%d toolarge\n", countall[MYLGPID]); > if ( done+t <= count) { > memcpy(ptr, entry, t); > ptr += t; > done+= t; > } > else > goto finishit; > > finishit: > > *start = page; > *eof = 1; > return done; > } > > void __init proc_memclass_init(void) > { > /* > * prepare proc entries > */ > int i; > struct proc_dir_entry* res; > struct proc_dir_entry* mdiff_entry; > > res = proc_mkdir("memdiff", NULL); > if (!res) { > printk("make proc directory fail\n"); > return; > } > mdiff_entry = res; > > res = create_proc_entry("classdef",0, mdiff_entry); > if (!res) { > printk("make proc entry fail\n"); > return; > } > res->data = NULL; > res->read_proc = clsdef_read_proc; > res->write_proc = clsdef_write_proc; > > for (i=0; i<sizeof(shared_vars)/sizeof(shared_vars[0]); i++) { > char name[0x10]; > sprintf(name,"sharedvars%d", i); > res = create_proc_entry(name,0, mdiff_entry); > if (!res) { > printk("make proc entry fail\n"); > return; > } > res->data = (void*)i; > res->read_proc = shared_vars_read_proc; > res->write_proc = shared_vars_write_proc; > } > > res = create_proc_entry("pagecount0",0, mdiff_entry); > if (!res) { > printk("make proc entry fail\n"); > return; > } > res->data = (void*)0; > res->read_proc = pgcount_read_proc; > > res = create_proc_entry("pagecount1",0, mdiff_entry); > if (!res) { > printk("make proc entry fail\n"); > return; > } > res->data = (void*)1; > res->read_proc = pgcount_read_proc; > > res = create_proc_entry("pagecount2",0, mdiff_entry); > if (!res) { > printk("make proc entry fail\n"); > return; > } > res->data = (void*)2; > res->read_proc = pgcount_read_proc; > > res = create_proc_entry("memeat",0, mdiff_entry); > if (!res) { > printk("make proc entry fail\n"); > return; > } > res->data = NULL; > res->read_proc = memeat_read_proc; > res->write_proc = memeat_write_proc; > } > > #endif diff -Naur a/fs/proc/root.c b/fs/proc/root.c --- a/fs/proc/root.c Tue Jul 15 12:42:44 EDT 2003 +++ b/fs/proc/root.c Tue Jul 15 12:42:44 EDT 2003 79a80,83 > > #ifdef CONFIG_MEMORY_DIFF > proc_memclass_init(); > #endif diff -Naur a/init/Kconfig b/init/Kconfig --- a/init/Kconfig Tue Jul 15 12:42:44 EDT 2003 +++ b/init/Kconfig Tue Jul 15 12:42:44 EDT 2003 184a185,216 > menu "differentiated memory service" > > config MEMORY_DIFF > bool "differentiated memory basic" > default y > help > provide class based memory control > > config MDIFF_DEBUG_BEANCOUNTING > bool "debug the beancounting" > default y > depends on MEMORY_DIFF > help > debug the bean counting of class memory > > config MDIFF_PAGECACHE_CLASS > bool "pagecache class" > default y > depends on MEMORY_DIFF > help > assign all pages belonging to page cache one special class > > config MDIFF_CLASS_RECLAIM > bool "class based reclaim" > default y > depends on MEMORY_DIFF > help > reclaim pages baed on class memory share > > endmenu > > diff -Naur a/init/main.c b/init/main.c --- a/init/main.c Tue Jul 15 12:42:44 EDT 2003 +++ b/init/main.c Tue Jul 15 12:42:44 EDT 2003 117a118,155 > #ifdef CONFIG_MEMORY_DIFF > > /* > * The diff_mem_list is protected by mem_class_lock. This > * list may be accessed by regular processes or the timer > * function which monitor the activeness of class possibly > * running in interrupt context. > * The spinlock is enough to protect concurrently accesses > * from multiple processes on SMP, but it should disable BH > * if want to protected it from interrupt context. To > * save time, we don't disable BH, instead, we use > * !!!spin_trylock!!! in the timer function. If fail to lock, > * schedule itself again in future. > */ > spinlock_t mem_class_lock = SPIN_LOCK_UNLOCKED; > struct list_head diff_mem_list = LIST_HEAD_INIT(diff_mem_list); > > struct diff_mem_class def_mem_class; > #ifdef CONFIG_MDIFF_PAGECACHE_CLASS > struct diff_mem_class pgcache_mem_class; > #endif > > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > atomic_t missact = ATOMIC_INIT(0); > atomic_t missinact = ATOMIC_INIT(0); > atomic_t missactsub = ATOMIC_INIT(0); > atomic_t missinactsub = ATOMIC_INIT(0); > #endif > > #ifdef CONFIG_MDIFF_CLASS_NEGATIVE > /* set monitor interval as 1 second */ > int mmcls_monitor_interval = 1*HZ; > struct timer_list mmcls_monitor; > void class_memory_monitor(unsigned long arg); > #endif > > #endif > 383a422,455 > > #ifdef CONFIG_MEMORY_DIFF > /* > * No need to hold the lock since we are at the the very beginning > */ > memset(&def_mem_class, 0, sizeof(struct diff_mem_class)); > def_mem_class.classid = 0; > > /* make sure we will not do kfree for def class */ > atomic_set(&(def_mem_class.count),1); > list_add(&def_mem_class.list, &diff_mem_list); > > /* > * this one should be the 1st process. > * Does any other process will go through the "do_fork"? > */ > mem_class_get( &def_mem_class ); > current->class = &def_mem_class; > > #ifdef CONFIG_MDIFF_PAGECACHE_CLASS > memset(&pgcache_mem_class, 0, sizeof(struct diff_mem_class)); > pgcache_mem_class.classid=1; > /* make sure we will not do kfree for pgcache class */ > atomic_set(&(pgcache_mem_class.count),1); > list_add(&pgcache_mem_class.list, &diff_mem_list); > > /* > * this one should be the 1st process. > * Does any other process will go through the "do_fork"? > */ > mem_class_get(&pgcache_mem_class); > #endif > #endif > 436a509,512 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > /* we believe here the max_mapnr has already been set; */ > def_mem_class.shrink_threshold = max_mapnr*10/100; > #endif 586a663,676 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) && defined (CONFIG_MDIFF_CLASS_NEGATIVE) > /* > * start the timer function to monitor class activeness. > * The code should be moved to a module later. > */ > do { > struct timer_list* w = &mmcls_monitor; > init_timer(w); > w->expires = jiffies + mmcls_monitor_interval; > w->data = 0; > w->function = class_memory_monitor; > add_timer(w); > }while(0); > #endif 602a693,800 > > #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM) && defined(CONFIG_MDIFF_CLASS_NEGATIVE) > > /* > * This priority is related to the priority of shrink_cache > * Refer mm/vmscan.c > */ > #define MAX_SHRINK_PRIORITY 12 > > > #define _INTERVAL_ 2 > #define _MINSCAN_ 8 > #define _MAXLAMDA_ 5 > > /* static inline */ > void mem_class_priority_adjust_temp(struct diff_mem_class* cls) > { > int lamda, mr; > int scan = atomic_read(&cls->nr_shrinkscan); > > atomic_add( scan, &cls->nr_totalscan); > > mr= atomic_read(&cls->nr_positivemove)*100/(atomic_read(&cls->nr_totalscan)|1); > > atomic_set(&cls->nr_shrinkscan,0); > > lamda = scan/_MINSCAN_; > if (lamda>_MAXLAMDA_) > lamda = _MAXLAMDA_; > > atomic_set( &cls->shrink_priority_adjust, -((mr*lamda)/(_MAXLAMDA_*_INTERVAL_)) ); > } > > /* static inline */ > void mem_class_priority_adjust(struct diff_mem_class* cls) > { > int lamda, mr; > int pt = atomic_read(&cls->shrink_priority); > int scan = atomic_read(&cls->nr_totalscan); > int pmove=atomic_read(&cls->nr_positivemove); > > if (scan>_MINSCAN_) { > > mr= pmove*100/(scan); > > lamda = scan/_MINSCAN_; > if (lamda>_MAXLAMDA_) > lamda = _MAXLAMDA_; > > atomic_add( 1-((mr*lamda)/(_MAXLAMDA_*_INTERVAL_)), > &cls->shrink_priority); > > if ( atomic_read(&cls->shrink_priority)>MAX_SHRINK_PRIORITY) > atomic_set(&cls->shrink_priority,MAX_SHRINK_PRIORITY); > else if ( atomic_read(&cls->shrink_priority)<-1) > atomic_set(&cls->shrink_priority,-1); > } > else { > /* if there is no page or too less pages scaned, > * the positive move may from pgfault etc. > * which makes it also important, since the pgfault is > * considered in the positive > * move, we will not add it seperately. > */ > if (pmove>scan){ > atomic_dec(&cls->shrink_priority); > if ( atomic_read(&cls->shrink_priority)<-1) > atomic_set(&cls->shrink_priority,-1); > } > } > > atomic_set(&cls->nr_totalscan,0); > atomic_set(&cls->nr_positivemove,0); > > printk("[%d]%d,%d(pmove%d,scan%d,%d->%d) ",cls->classid, > atomic_read(&cls->nr_active),atomic_read(&cls->nr_inactive), > pmove, scan, pt,atomic_read(&cls->shrink_priority)); > } > > void class_memory_monitor(unsigned long arg) > { > struct timer_list* w = &mmcls_monitor; > struct diff_mem_class* cls; > > if (!spin_trylock(&mem_class_lock)) { > /* somebody hold the lock, let's schedule ourselves in future */ > init_timer(w); > w->expires = jiffies + 10; > w->data = arg+10; > w->function = class_memory_monitor; > add_timer(w); > } > > /* Now we hold the lock. */ > list_for_each_entry( cls, &diff_mem_list, list) { > mem_class_priority_adjust(cls); > } > spin_unlock(&mem_class_lock); > > printk("\n"); > init_timer(w); > w->expires = jiffies + mmcls_monitor_interval; > w->data = mmcls_monitor_interval; > w->function = class_memory_monitor; > add_timer(w); > } > > #endif diff -Naur a/kernel/exit.c b/kernel/exit.c --- a/kernel/exit.c Tue Jul 15 12:42:44 EDT 2003 +++ b/kernel/exit.c Tue Jul 15 12:42:44 EDT 2003 458a459,478 > > #ifdef CONFIG_MEMORY_DIFF > spin_lock(&mm->peertask_lock); > list_del(&tsk->peertask_list); > if (tsk->class){ > mem_class_put(tsk->class); > tsk->class=NULL; > } > > /* > * Even the tasklist is empty now for this memory, > * there may be page cache associated with this mm > */ > if (list_empty(&mm->tasklist)) { > mem_class_get(&def_mem_class); > mm->class=&def_mem_class; > } > spin_unlock(&mm->peertask_lock); > #endif > diff -Naur a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Tue Jul 15 12:42:44 EDT 2003 +++ b/kernel/fork.c Tue Jul 15 12:42:44 EDT 2003 64a65,75 > #ifdef CONFIG_MEMORY_DIFF > /* > * Record reserved memory share for class creation > */ > spinlock_t idx_cls_lock = SPIN_LOCK_UNLOCKED; > /* 0 is for default, and 1 is for page cache class */ > int idx_cls = 2; > /* already reserved 10% for default mem class */ > static int mem_reserved = 10; > #endif > 243a255,266 > #ifdef CONFIG_MEMORY_DIFF > INIT_LIST_HEAD(&tsk->peertask_list); > > if (orig->class) { > mem_class_get(orig->class); > tsk->class=orig->class; > } > else { > printk("unexpected null class for process\n"); > tsk->class=NULL; > } > #endif 373a397,403 > #ifdef CONFIG_MEMORY_DIFF > INIT_LIST_HEAD(&mm->tasklist); > if (current->class) > mem_class_get(current->class); > mm->class=current->class; > mm->peertask_lock = SPIN_LOCK_UNLOCKED; > #endif 408a439,448 > #ifdef CONFIG_MEMORY_DIFF > /* > * mm->class can be null and mm->tasklist can be empty > * BUG_ON( !mm->class||!list_empty(&mm->tasklist)); > */ > if (mm->class) { > mem_class_put(mm->class); > mm->class = NULL; > } > #endif 518a559,576 > #ifdef CONFIG_MEMORY_DIFF > spin_lock(&mm->peertask_lock); > list_add_tail(&tsk->peertask_list, &mm->tasklist); > > if (!tsk->class) > BUG(); > > if (!mm->class) { > mem_class_get(tsk->class); > mm->class=tsk->class; > } > else { > if (mm->class != tsk->class) { > printk("Mismatch of class for virtual memory space and task\n"); > } > } > spin_unlock(&mm->peertask_lock); > #endif 1182a1241,1388 > > #ifdef CONFIG_MEMORY_DIFF > > int memdiff_redefine(int clsid, int arg) > { > struct diff_mem_class* cls; > > spin_lock(&mem_class_lock); > cls=NULL; > list_for_each_entry(cls, &diff_mem_list, list) { > if (cls->classid==clsid) > goto found_cls_4;; > } > spin_unlock(&mem_class_lock); > return -EINVAL; > > found_cls_4: > spin_unlock(&mem_class_lock); > if (arg<=0) > return -EINVAL; > #ifdef CONFIG_MDIFF_CLASS_RECLAIM > cls->shrink_threshold = arg;; > #endif > return 0; > } > /* > * Because I have no way to build modules in UML, I hardcode the new > * system call here > */ > asmlinkage int sys_memdiffctrl(int type, int arg) > { > int totalpages; > struct diff_mem_class* cls; > unsigned long active, inactive, free; > int* ret; > > printk("systemcall %d, %d\n", type, arg); > switch (type) { > case 0: /* reserve memory for class */ > case 3: > if (type==0) { > if (arg<=0) > return -EINVAL; > if (arg+mem_reserved>100) { > return -EINVAL; > } > mem_reserved += arg; > totalpages = max_mapnr; > arg = totalpages * arg /100; > } > if (arg<=0) > return -EINVAL; > > spin_lock(&idx_cls_lock); > cls = kmalloc(sizeof(struct diff_mem_class), GFP_KERNEL); > if (!cls) { > spin_unlock(&idx_cls_lock); > return -ENOMEM; > } > memset(cls, 0, sizeof(struct diff_mem_class)); > > cls->classid = idx_cls; > idx_cls++; > > spin_unlock(&idx_cls_lock); > > atomic_set(&(def_mem_class.count),1); > > /* > * because some pages are not counted in our page-classes, > * the actual threshold should be lower, > * Here, we simply assume that 10% of the pages must be for > * other resources like slab, socket etcs. > */ > #ifdef CONFIG_MDIFF_CLASS_RECLAIM > cls->shrink_threshold = arg;; > #endif > > spin_lock(&mem_class_lock); > list_add(&cls->list, &diff_mem_list); > spin_unlock(&mem_class_lock); > return cls->classid; > case 1: /* set class for task */ > if (arg<0 || arg>=idx_cls) > return -EINVAL; > spin_lock(&mem_class_lock); > cls=NULL; > list_for_each_entry(cls, &diff_mem_list, list) { > if (cls->classid==arg) > goto found_cls_1; > } > spin_unlock(&mem_class_lock); > return -EINVAL; > found_cls_1: > spin_unlock(&mem_class_lock); > if (cls==current->class) > return 0; > > if (current->class) > mem_class_put(current->class); > spin_lock(¤t->active_mm->peertask_lock); > > mem_class_get(cls); > current->class = cls; > > if (current->active_mm->class!=cls) { > mem_class_put(current->active_mm->class); > mem_class_get(cls); > current->active_mm->class=cls; > } > spin_unlock(&(current->active_mm->peertask_lock)); > return 0; > case 2: > /* > * Retrieve class info, assume the buffer is enough to > * to hold the data. No buffer boundary check at this moment. > */ > ret = (int*)arg; > > get_zone_counts(&active, &inactive,&free); > put_user(active, ret); > ret++; > put_user(inactive, ret); > ret++; > put_user(free, ret); > ret++; > > spin_lock(&mem_class_lock); > cls=NULL; > list_for_each_entry(cls, &diff_mem_list, list) { > put_user(cls->classid,ret); > ret++; > put_user(atomic_read(&cls->nr_total),ret); > ret++; > put_user(atomic_read(&cls->nr_active),ret); > ret++; > put_user(atomic_read(&cls->nr_inactive),ret); > ret++; > } > spin_unlock(&mem_class_lock); > return (ret-(int*)arg); > default: > return -EINVAL; > } > return 0; > } > > #endif diff -Naur a/mm/memory.c b/mm/memory.c --- a/mm/memory.c Tue Jul 15 12:42:44 EDT 2003 +++ b/mm/memory.c Tue Jul 15 12:42:44 EDT 2003 diff -Naur a/mm/page_alloc.c b/mm/page_alloc.c --- a/mm/page_alloc.c Tue Jul 15 12:42:45 EDT 2003 +++ b/mm/page_alloc.c Tue Jul 15 12:42:45 EDT 2003 447a448,464 > #ifdef CONFIG_MEMORY_DIFF > /* > * At this moment, the page is not in any list so we can > * safely remove its class info. > * We cannot do this job at the moment of page_remove_rmap > * or remove_from_page_cache since the page may still be in > * LRU list at that moment. > */ > page_class_lock(page); > if (page->class) { > atomic_dec(&page->class->nr_total); > mem_class_put(page->class); > } > page->class=NULL; > page_class_unlock(page); > #endif > diff -Naur a/mm/rmap.c b/mm/rmap.c --- a/mm/rmap.c Tue Jul 15 12:42:45 EDT 2003 +++ b/mm/rmap.c Tue Jul 15 12:42:45 EDT 2003 181a182,248 > #ifdef CONFIG_MEMORY_DIFF > do{ > struct mm_struct* mm =ptep_to_mm(ptep); > /* > * At the beginning, I think that mm must be associated with a > * task at this moment, but it is not! > * I have not investigated the reason. > * if (list_empty(&mm->tasklist)) > * printk("mm has no task associated with it mm=%p\n",mm); > */ > > /* > * If the task terminates, the exit_mm will remove it from > * the mm->tasklist. We can reset page->task only at the time of > * page_remove_rmap. But it is possible that the task is not > * in the list but the page_remove_rmap is not called yet. > * (because multiple tasks share mm_struct) > * That's the reason we can associate mm_struct instead of > * task_struct with stryct page. (Currently not provided yet) > */ > > BUG_ON(!mm->class); > > /* > * Notice we borrow the pte_chain_lock bit to protect the page's > * class, so we should not call page_class_lock here. > */ > if (page->class != mm->class) { > if (!page->class) { > atomic_inc(&mm->class->nr_total); > /* Here , we have not checked the Zone'lru lock, so we can still miss or overact */ > if (PageActive(page)) { > atomic_inc(&mm->class->nr_active); > //printk("rmap: repair active page\n"); > } > else if(PageLRU(page)) { > atomic_inc(&mm->class->nr_inactive); > //printk("rmap: repair inactive page\n"); > } > > } > else { > atomic_dec(&page->class->nr_total); > atomic_inc(&mm->class->nr_total); > if (PageActive(page)) { > atomic_dec(&page->class->nr_active); > atomic_inc(&mm->class->nr_active); > } > else if(PageLRU(page)) { > atomic_dec(&page->class->nr_inactive); > atomic_inc(&mm->class->nr_inactive); > } > mem_class_put(page->class); > } > page->class = mm->class; > spin_lock(&mm->peertask_lock); > if (!list_empty(&mm->tasklist)) { > struct task_struct* tsk = list_entry(mm->tasklist.next,struct task_struct, peertask_list); > page->pid = tsk->pid; > } > else > page->pid = -1; > spin_unlock(&mm->peertask_lock); > mem_class_get(page->class); > } > }while(0); > #endif 268a336,399 > #ifdef CONFIG_MEMORY_DIFF > /* > * All ptep for one page are organized as a list of "pte_chain". > * each pte_chain includes #NRPTE entries. Entries are > * filled from the end to the beginning so simply checking > * the first entry can show whether there is still space > * in this pte_chain. > * Our algorithm try to make sure that the page->mm always > * corresponding to the last entry of the last item of the > * pte_chain list (or pte.direct. notes that when pte.direct > * is convert to chain list, it will be the last entry of the > * only pte_chain) > * Notice we borrow the pte_chain_lock bit to protect the page's > * class, so we should not call page_class_lock here. > */ > if ( page->pte.chain /* there are still some mm maps this page */ > /* last entry of last item */ > && (pc!=start && !pte_chain_next(pc)) && i==NRPTE-1 ){ > pte_t * ptep; > struct mm_struct* mm; > > BUG_ON(!pc->ptes[i]); > ptep = rmap_ptep_map(pc->ptes[i]); > mm =ptep_to_mm(ptep); > BUG_ON(!mm->class); > if (page->class != mm->class) { > if (!page->class) { > atomic_inc(&mm->class->nr_total); > if (PageActive(page)) { > atomic_inc(&mm->class->nr_active); > //printk("rmap: repair inactive page\n"); > } > else if(PageLRU(page)) { > atomic_inc(&mm->class->nr_inactive); > //printk("rmap: repair active page\n"); > } > } > else { > atomic_dec(&page->class->nr_total); > atomic_inc(&mm->class->nr_total); > if (PageActive(page)) { > atomic_dec(&page->class->nr_active); > atomic_inc(&mm->class->nr_active); > } > else if(PageLRU(page)) { > atomic_dec(&page->class->nr_inactive); > atomic_inc(&mm->class->nr_inactive); > } > mem_class_put(page->class); > } > page->class = mm->class; > spin_lock(&mm->peertask_lock); > if (!list_empty(&mm->tasklist)) { > struct task_struct* tsk = list_entry(mm->tasklist.next,struct task_struct, peertask_list); > page->pid = tsk->pid; > } > else > page->pid = -1; > spin_unlock(&mm->peertask_lock); > mem_class_get(page->class); > } > rmap_ptep_unmap(ptep); > } > #endif diff -Naur a/mm/vmscan.c b/mm/vmscan.c --- a/mm/vmscan.c Tue Jul 15 12:42:45 EDT 2003 +++ b/mm/vmscan.c Tue Jul 15 12:42:45 EDT 2003 262a263,270 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > if (!MCLS_readyshrink(page->class)) { > pte_chain_unlock(page); > /* should we throw it back to the active list?*/ > goto keep_locked; > } > #endif > 455a464 > LIST_HEAD(hold); 458a468,470 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > int nr_pass; > #endif 476a489,494 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > nr_pass = zone->nr_inactive; > while (nr_pass>0 && nr_scan<nr_to_process && > !list_empty(&zone->inactive_list)) { > nr_pass--; > #else 478a497 > #endif 487a507,519 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > if (page->class && !MCLS_readyscan(page->class) && !MCLS_readyshrink(page->class)) { > /* > * instead of add back to inactive list, which add it to the head, we may leave it here at the tail > * > * SetPageLRU(page); > * list_add(&page->lru, &zone->inactive_list); > */ > list_add(&page->lru, &hold); > continue; > } > nr_scan++; > #endif 496a529,537 > #ifdef CONFIG_MEMORY_DIFF > if (page->class) { > atomic_dec(&page->class->nr_inactive); > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missinactsub); > #endif > #endif 499a541,549 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > while (!list_empty(&hold)) { > page = list_entry(hold.next, struct page, lru); > if (TestSetPageLRU(page)) > BUG(); > list_del(&page->lru); > list_add_tail(&page->lru, &zone->inactive_list); > } > #endif 501c551 < --- > 525a576 > 571a623,625 > #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM) > int nr_pass; > #endif 575a630,648 > #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM) > /* > *It seems that the pass number here will cause gread number of > * pages of underutilzied class be moved while at the same time, > * not enough pages of overutilzed class refill > */ > /* > nr_pass = zone->nr_active >> priority; > if (nr_pass < nr_pages) > nr_pass = nr_pages; > */ > nr_pass = zone->nr_active; > /* > * Because nr_pass <= listlength of zone->active_list, there > * is no need to check list_empty. Note nr_pass is assigned after > * the lru lock hold. > */ > while (nr_pages && nr_pass>0 && !list_empty(&zone->active_list)) { > #else 576a650 > #endif 589a664,672 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) { > atomic_dec(&page->class->nr_active); > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missactsub); > #endif > #endif 590a674,685 > #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM) > /* > * If we still only use nr_pages and the list emptiness as indicators > * for while loop, then if the page_count of some page !=0 => list > * will never empty, and nr_pages may never reach zero. > * So we need other mechanisms which is the nr_pass. > */ > nr_pass--; > if (MCLS_readyrefill(page->class)) { > nr_pages--; > } > #else 591a687 > #endif 666a763,771 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) { > atomic_inc(&page->class->nr_inactive); > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missinact); > #endif > #endif 694a800,808 > #ifdef CONFIG_MEMORY_DIFF > if(page->class) { > atomic_inc(&page->class->nr_active); > } > #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING > else > atomic_inc(&missinact); > #endif > #endif 720a835,845 > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > /* > * The purpose of this code is to set the shrink/refill bits for > * each memory class > */ > int nr_active = 0; > int nr_inactive=0; > int nr_candidates=0; > int adjustratio; > struct diff_mem_class* cls; > #endif 734a860,901 > > #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) > /* > * Go through all classes to determine which class's pages are > * candidate for refill/reclaim > */ > spin_lock(&mem_class_lock); > > list_for_each_entry( cls, &diff_mem_list, list) { > if (atomic_read(&cls->nr_total)>cls->shrink_threshold ) { > /* there is a bug which causes the cls->nr_inactive is negative */ > if (atomic_read(&cls->nr_active)>0) > nr_active += atomic_read(&cls->nr_active); > if ( atomic_read(&cls->nr_inactive)>0) > nr_inactive += atomic_read(&cls->nr_inactive); > nr_candidates=1; > MCLS_set_readyrefill(cls); > MCLS_set_readyshrink(cls); > MCLS_set_readyscan(cls); > } > else { > MCLS_reset_readyrefill(cls); > MCLS_reset_readyshrink(cls); > MCLS_reset_readyscan(cls); > } > } > /* If nobody exceeds threshold and nobody negative enough for shrink */ > if (!nr_candidates) { > list_for_each_entry( cls, &diff_mem_list, list) { > MCLS_set_readyrefill(cls); > MCLS_set_readyshrink(cls); > MCLS_set_readyscan(cls); > } > } > else { > adjustratio = (unsigned long)nr_pages * nr_active / > ((nr_inactive | 1) * 2); > atomic_add(adjustratio-ratio-1, &zone->refill_counter); > } > spin_unlock(&mem_class_lock); > #endif >