/* Called in page_alloc ONLY at the moment. * This method will page available IF NEEDED - i.e. if there are less than 10 free * pages on the system, we'll start swapping. If not, we simply return. */ static void make_page_available() { //KASSERT(spinlock_do_i_hold(&stealmem_lock)); // DEBUG(DB_SWAP, "Free Pages: %d\n",free_pages); if(free_pages <= 10) { struct thread *cur = curthread; (void)cur; // DEBUG(DB_SWAP, "Making page available\n"); //DEBUG(DB_SWAP, "Start Swap: %d\n",free_pages); //DEBUG(DB_SWAP, "\nStart Swapping\n"); int rr_page = get_a_dirty_page_index(0); if(rr_page == -1) { return; } //KASSERT(spinlock_do_i_hold(&stealmem_lock)); KASSERT(core_map[rr_page].state == SWAPPINGOUT); // DEBUG(DB_SWAP, "SWOs%d\n",rr_page); swapout_page(&core_map[rr_page]); // KASSERT(spinlock_do_i_hold(&stealmem_lock)); // DEBUG(DB_SWAP, "Starting Eviction...%d\n",rr_page); evict_page(&core_map[rr_page]); // KASSERT(spinlock_do_i_hold(&stealmem_lock)); //DEBUG(DB_SWAP, "Evicted %d\n",rr_page); } // KASSERT(spinlock_do_i_hold(&stealmem_lock)); }
/* Tries to allocate and lock a frame for PAGE. Returns the frame if successful, false on failure. */ struct frame * frame_alloc_and_lock(struct page *page) { struct frame *new_frame; uint8_t *kpage; while (true) { kpage = palloc_get_page(PAL_USER); if (kpage != NULL) { lock_acquire(&ftable_lock); new_frame = (struct frame *) malloc(sizeof(struct frame)); if (page->swap_flag != 1) page->swap_flag = 0; page->frame_holder_thread = thread_current(); new_frame->page = page; new_frame->base = kpage; list_insert(list_end(&frame_list), &new_frame->frame_list_elem); // new_frame->page->swap_flag = 0; lock_release(&ftable_lock); break; } else { // lock_release(&ftable_lock); // PANIC("No free page available"); // page eviction comes here // printf("\nEntered EVICT PAGE section"); evict_page(); // page->swap_flag = 1; // printf("\nExited EVICT PAGE section"); } } return new_frame; }
// creates a new entry in the page table // If RAM is full. an entry is evicted to // make room for the current. vAddr create_page(void){ if(printing == 2){ printf("Creating new page\n"); } // Get the address of the next available empty non-locked page // Once a page is found, it is returned in the locked state vAddr new_vAddr = get_new_page_address(); // If the page table is full, return an error if(new_vAddr == -1){ if(printing){ printf("Page Table full\n"); } return -1; } // Initialize the new page init_page(&(page_table[new_vAddr])); // Find a pageframe in ram to give to it int temp = evict_page(ram); // Add the new page to this location // add_to_lowest(&(page_table[new_vAddr]),ram); page_table[new_vAddr].location = temp; page_table[new_vAddr].memlev = ram; page_table[new_vAddr].empty = 0; if(printing == 2){ printf("Successfully created new page at %i\n", new_vAddr); printf("\n"); } // Unlock page pthread_mutex_unlock(&(page_table[new_vAddr].lock)); return new_vAddr; }
int swap_out_page(void) { if (!swap_initialized) { int err = swap_init(); if (err) return err; } struct page* p = find_swapout(); if (p==NULL) panic("Could not find a page to swap out"); spinlock_acquire(&p->pg_lock); if (p->is_dirty) write_out_page(p); evict_page(p); p->status = IN_SWAP; p->ram_addr = 31; spinlock_release(&p->pg_lock); return 0; }
// Evict Page returns the location of the lowest open slot in the provided memory level // If there are no open spots, it uses the paging algorithm to evict one page from the memlev // and move it to the next one. int evict_page(Memlev memlev) { // printf("Trying to evict a page.\n"); // Interate through the entire page table // If there is still room available in ram // find the lowest available location and return the data int i; int max_elements = 0; // This switch case determines the memory level the eviction is on // if the provided memlevel is "nul" or "hdd", not page can be // evicted and an error value of -2 is returned. switch(memlev){ case ram: // printf("Trying to evict page from ram\n"); max_elements = MAXRAM; break; case ssd: // printf("Trying to evict page from ssd\n"); max_elements = MAXSSD; break; case hdd: // printf("Trying to evict page from hdd\n"); max_elements = MAXHDD; break; default: printf("Trying to evict page from the 'nul' level\n"); return -2; break; break; } // This is the list of all the available pageframes in a memlev // 1 = taken, 0 = available int slots[max_elements]; // Iterate through the entire page table, marking all the taken pageframes for(int i = 0; i < max_elements; i++){ slots[i] = 0; } // Iterate through the entire page table, marking all the taken pageframes for(i = 0; i < MAXADDR; i++){ if(page_table[i].memlev == memlev && page_table[i].empty == 0){ slots[page_table[i].location] = 1; } } // Once all the take page frames are marked, see if any are still available for(i = 0; i < max_elements; i++){ // If there is a pageframe available // update the location with the ram information and return it. if(slots[i] == 0){ switch(memlev){ case ram: // printf("Trying to lock ram slot %i\n", i); if(pthread_mutex_trylock(&(lock_ram[i])) == 0){ // printf("Successfully locked ram slot %i\n", i); return i; } // printf("Failed to lock ram slot %i\n", i); break; case ssd: if(pthread_mutex_trylock(&(lock_ssd[i])) == 0){ return i; } break; case hdd: if(pthread_mutex_trylock(&(lock_hdd[i])) == 0){ return i; } break; break; } } } // If there are no spots in this memory level, // then we will have to move a page out // and into the higher memory level // Here we call evict on the next memory level // to find a place to move the evicted page // printf("'We need to go deeper'\n"); int new_slot = evict_page(memlev + 1); if(new_slot < 0){ printf("There is a serious problem\n"); } // We call our custom algorithm to find a page to evict vAddr temp_page = page_to_remove(memlev, type_r); // finally we move the content to the higher memory level switch(memlev) { case ram: write_to_memory(ssd, new_slot, read_from_memory(ram, page_table[temp_page].location)); break; case ssd: write_to_memory(hdd, new_slot, read_from_memory(ssd, page_table[temp_page].location)); break; break; } // update it's paging information to reflect the new position page_table[temp_page].memlev = memlev + 1; int result = page_table[temp_page].location; page_table[temp_page].location = new_slot; // Unlock the modified page pthread_mutex_unlock(&(page_table[temp_page].lock)); // And return the newly opened pageframe return result; }
// This method takes in a page address and content // and tries to put the content in the desired page // If the page is not in RAM, a page fault is generated and the page is moved into ram // Error = 0, success // Error = 1, desired page is outside page table range // Error = 2, Requested page is empty int store_value(vAddr address, content c) { if(printing == 2){ printf("Storing value %i in page %i\n", c, address); } if((address > MAXADDR) || (address < 0)){ if(printing == 2){ printf("Page Fault: Tried to access an page outside range: %d\n",address); } return 1; } // return the result if(page_table[address].empty) { if(printing == 2){ printf("Page Fault: Requested page is empty: %d\n",address); } return 2; } // Lock this page to prevent other threads from manipulating it pthread_mutex_lock(&(page_table[address].lock)); // check if the desired page is in RAM if(page_table[address].memlev != ram) { if(printing == 2){ printf("Page Fault: requested page not in RAM\n"); } int new_location = evict_page(ram); write_to_memory(ram, new_location, read_from_memory(page_table[address].memlev, page_table[address].location)); // Unlock the now free pageframe in the previous memory level switch(page_table[address].memlev){ case ssd: pthread_mutex_unlock(&(lock_ssd[page_table[address].location])); break; case hdd: pthread_mutex_unlock(&(lock_hdd[page_table[address].location])); break; break; } // update the information for the page page_table[address].memlev = ram; page_table[address].location = new_location; page_table[address].referenced++; if(printing == 2){ printf("Recovered from Page Fault: requested page not in RAM\n"); } } // write the information to the ram location write_to_memory(ram, page_table[address].location, c); if(printing == 2){ printf("\n"); } // Unlock the page pthread_mutex_unlock(&(page_table[address].lock)); return 0; }
/* Called in page_nalloc ONLY at the moment. * This method will page available IF NEEDED - i.e. if there are less than 10 free * pages on the system, we'll start swapping. If not, we simply return. */ static void make_pages_available(int npages, bool retry) { /* //KASSERT(spinlock_do_i_hold(&stealmem_lock)); // bool lock = get_coremap_lock(); // DEBUG(DB_SWAP,"MPA:%d\n",npages); if(free_pages <= 10) { //Disable interrupts until we find the right number of pages. ->should be disabled in page_alloc() //int spl = splhigh(); size_t rr_page = current_n_index; if(retry) { rr_page = 0; } bool blockStarted = false; int pagesFound = 0; int startingPage = 0; // DEBUG(DB_SWAP, "NPages:%d\n",npages); // DEBUG(DB_SWAP, "Page Count:%d\n",page_count); for(size_t i = rr_page;i < (size_t) page_count;i++) { // DEBUG(DB_SWAP, "Page: %d State: %d\n",i,core_map[i].state); page_state_t curState = core_map[i].state; if(!blockStarted && (curState == DIRTY || curState == FREE)) { blockStarted = true; pagesFound = 1; startingPage = i; } else if(blockStarted && (curState != DIRTY && curState != FREE)) { blockStarted = false; pagesFound = 0; } else if(blockStarted && (curState == DIRTY || curState == FREE)) { pagesFound++; } if(pagesFound == npages) { //Mark the pages as SWAPPING OUT. for(int j = startingPage; j<startingPage + npages; j++) { KASSERT(core_map[j].state == DIRTY || core_map[j].state == FREE); if(core_map[j].state == DIRTY) { core_map[j].state = SWAPPINGOUT; //Update PTE to state PTE_SWAPPING struct page_table *pt = pgdir_walk(core_map[j].as,core_map[j].va,false); int pt_index = VA_TO_PT_INDEX(core_map[j].va); pt->table[pt_index] |= PTE_SWAPPING; // DEBUG(DB_SWAP, "%d\n",pt->table[pt_index]); ////////////////////////////////// } } current_index = startingPage + npages + 1; //splx(spl); //Swap out the block of pages, now for(int j = startingPage; j<startingPage + npages; j++) { KASSERT(core_map[j].state == FREE || core_map[j].state == SWAPPINGOUT); // DEBUG(DB_SWAP,"SWOn%d-%d\n",j,npages); if(core_map[j].state == SWAPPINGOUT) { //KASSERT(spinlock_do_i_hold(&stealmem_lock)); swapout_page(&core_map[j]); evict_page(&core_map[j]); } } // release_coremap_lock(lock); return; } } //If we get here, we reached the end of memory. Try again ONCE. if(retry == 2) { DEBUG(DB_SWAP,"\n"); for(size_t i = 0;i<page_count;i++) { //int spl = splhigh(); DEBUG(DB_SWAP,"I:%d S:%d\n",i,core_map[i].state); //splx(spl); } panic("Couldn't swap a big enough chunk for npages!"); } else { //splx(spl); make_pages_available(npages,1); } } */ // release_coremap_lock(lock); (void)npages; (void)retry; // Since we probably need a lot of pages, due to forking and such, // why not just flush all of memory? if(free_pages > 10) { return; } bool lock; lock = get_coremap_lock(); for (int i = 0; i < (int)page_count; i++) { int spl = splhigh(); if(core_map[i].state == DIRTY) { KASSERT(core_map[i].state != SWAPPINGOUT); core_map[i].state = SWAPPINGOUT; //Update PTE to state PTE_SWAPPING struct page_table *pt = pgdir_walk(core_map[i].as,core_map[i].va,false); int pt_index = VA_TO_PT_INDEX(core_map[i].va); pt->table[pt_index] |= PTE_SWAPPING; splx(spl); // KASSERT(core_map[i].state != SWAPPINGOUT); swapout_page(&core_map[i]); evict_page(&core_map[i]); } else { splx(spl); } } release_coremap_lock(lock); }
int main(int argc, char *argv[]){ FILE *fp; // stimulus file handle char filename[50] = "stim.txt"; // stimulus file name, can be overwritten on cmdline // if filename given on commandline use it otherwise use default filename if (argc == 2) {strcpy(filename, argv[1]);} else {strcpy(filename, "stim.txt");} int opt = 0; // parse the cmdline while ((opt = getopt(argc, argv, "i:p:")) != -1) { switch(opt) { case 'i': strcpy(filename, optarg); break; case 'p': available_pf = (u32) strtol(optarg,NULL,10); validate_pf_number(available_pf); break; case '?': if (optopt == 'i'){ printf("USAGE: -i <filename>\n\n"); return -1; } else if (optopt == 'p') { printf("USAGE: -p <numpages>\n\n"); return -1; } else { printf("Valid switches are:\n"); printf("\t -i <input_filename>\n\t -p <numpages>\n\n"); return -1; break; } } } // open the input file fp = fopen (filename,"r"); if (NULL == fp){ fprintf (stderr, "Failed to open input file. This is fatal!\n"); exit(0); } //call function to allocate memory to PD init_PD(); // loop through input file an feed commands to sim do { get_command(fp); if (strcmp(cmd, "-v") == MATCH) { printf("VMM Simulator Ver 0.1\n"); exit(-1); } else if (strcmp(cmd, "w") == MATCH || strcmp(cmd, "r") == MATCH ) { // update read/wrote/access statistics num_accesses ++; if (strcmp(cmd, "w") == MATCH) {num_writes ++;} else {num_reads ++;} parse_addr(addr); if ( t_flag == 1 ){ printf(" %s 0x%08X\n", cmd, addr); } if (is_PT_present(working_addr.PD_index) == 1) { //check the user page present if(is_UP_present(working_addr.PD_index, working_addr.PT_index) == 1) { total_cycles += 20; //if the address exist, it considers memory access //printf("get here few time\n"); } else //the PT exists but not the user page { if (available_pf == used_pf) // no pf avail then evict one page evict_page(); create_user_page(working_addr.PD_index, working_addr.PT_index,cmd); } } else // new PT and UP need to created { while (available_pf < (used_pf + 2)) // create 2 avail pf evict_page(); create_page_table(working_addr.PD_index, cmd); create_user_page(working_addr.PD_index, working_addr.PT_index, cmd); } } if (d_flag == 1){dump_vmm();} } while (strcmp (cmd, "EOF")); num_physical_frames = 1 + num_PT + num_UP; print_outputs(); }