|
|
@@ -1,1344 +0,0 @@
|
|
|
-// Filename: lru.cxx
|
|
|
-// Created by: aignacio (12Dec05)
|
|
|
-//
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-//
|
|
|
-// PANDA 3D SOFTWARE
|
|
|
-// Copyright (c) 2001 - 2006, Disney Enterprises, Inc. All rights
|
|
|
-// reserved.
|
|
|
-// All use of this software is subject to the terms of the Panda 3d
|
|
|
-// Software license. You should have received a copy of this license
|
|
|
-// along with this source code; you will also find a current copy of
|
|
|
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
|
-//
|
|
|
-// To contact the maintainers of this program write to
|
|
|
-// [email protected] .
|
|
|
-//
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-//#include "stdafx.h"
|
|
|
-
|
|
|
-#define LRU_UNIT_TEST 0
|
|
|
-
|
|
|
-#include <stdio.h>
|
|
|
-#include <stdlib.h>
|
|
|
-#include <windows.h>
|
|
|
-
|
|
|
-#include "lru.h"
|
|
|
-
|
|
|
-
|
|
|
-static const int HIGH_PRIORITY_SCALE = 4;
|
|
|
-static const int LOW_PRIORITY_RANGE = 25;
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::Constructor
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-Lru::Lru (int maximum_memory, int maximum_pages, int maximum_page_types)
|
|
|
-{
|
|
|
- if(this) {
|
|
|
- int index;
|
|
|
-
|
|
|
- memset(&this->_m, 0, sizeof (LruVariables));
|
|
|
-
|
|
|
- this->_m.maximum_memory = maximum_memory;
|
|
|
- this->_m.maximum_pages = maximum_pages;
|
|
|
- this->_m.maximum_page_types = maximum_page_types;
|
|
|
- this->_m.available_memory = maximum_memory;
|
|
|
- this->_m.current_frame_identifier = 1;
|
|
|
- this->_m.weight = 0.20f;
|
|
|
-
|
|
|
- this->set_maximum_frame_bandwidth_utilization(2000000.0f);
|
|
|
-
|
|
|
- for(index = 0; index < MAXIMUM_LRU_PAGE_TYPES; index++) {
|
|
|
- this->_m.page_in_function_array[index] = default_page_in_function;
|
|
|
- this->_m.page_out_function_array[index] = default_page_out_function;
|
|
|
- }
|
|
|
-
|
|
|
- if(maximum_pages > 0) {
|
|
|
- this -> _m.lru_page_pool = new LruPage * [maximum_pages];
|
|
|
- this -> _m.lru_page_free_pool = new LruPage * [maximum_pages];
|
|
|
- for(index = 0; index < maximum_pages; index++) {
|
|
|
- LruPage * lru_page;
|
|
|
-
|
|
|
- lru_page = new LruPage ( );
|
|
|
- if(lru_page) {
|
|
|
- lru_page->_m.pre_allocated = true;
|
|
|
- this->_m.lru_page_pool[index] = lru_page;
|
|
|
- }
|
|
|
- else {
|
|
|
-// ERROR
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(maximum_page_types > 0) {
|
|
|
- this -> _m.page_type_statistics_array =
|
|
|
- new PageTypeStatistics [maximum_page_types];
|
|
|
- }
|
|
|
-
|
|
|
-#if ENABLE_MUTEX
|
|
|
- this -> _m.mutex = new Mutex ( );
|
|
|
-#endif
|
|
|
-
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::Destructor
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-Lru::~Lru ( )
|
|
|
-{
|
|
|
- int index;
|
|
|
- LruPage * lru_page;
|
|
|
-
|
|
|
- // free pre-allocated LruPages
|
|
|
- if(this->_m.maximum_pages > 0) {
|
|
|
- if(this->_m.lru_page_free_pool) {
|
|
|
- for(index = 0; index < this->_m.maximum_pages; index++) {
|
|
|
- lru_page = this->_m.lru_page_pool[index];
|
|
|
- if(lru_page->_m.in_lru) {
|
|
|
- this->remove_page(lru_page);
|
|
|
- }
|
|
|
-
|
|
|
- delete lru_page;
|
|
|
- }
|
|
|
-
|
|
|
- delete this -> _m.lru_page_free_pool;
|
|
|
- }
|
|
|
- if(this->_m.lru_page_pool) {
|
|
|
- delete this -> _m.lru_page_pool;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // free dynamically allocated LruPages
|
|
|
- for(index = 0; index < LPP_TotalPriorities; index++) {
|
|
|
- LruPage * next_lru_page;
|
|
|
-
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- while(lru_page) {
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- delete lru_page;
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(this->_m.page_type_statistics_array) {
|
|
|
- delete this -> _m.page_type_statistics_array;
|
|
|
- }
|
|
|
-
|
|
|
-#if ENABLE_MUTEX
|
|
|
- if(this->_m.mutex) {
|
|
|
- delete this -> _m.mutex;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: LruPage::Constructor
|
|
|
-// Access: Protected
|
|
|
-// Description: Internal function only.
|
|
|
-// Call Lru::allocate_page instead.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-LruPage::LruPage ( )
|
|
|
-{
|
|
|
- if(this) {
|
|
|
- memset(&this->_m, 0, sizeof (LruPageVariables));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: LruPage::Destructor
|
|
|
-// Access: Protected
|
|
|
-// Description: Internal function only.
|
|
|
-// Call Lru::free_page instead.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-LruPage::~LruPage ( )
|
|
|
-{
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: LruPage::change_priority
|
|
|
-// Access: Protected
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void LruPage::change_priority (int delta)
|
|
|
-{
|
|
|
- this->_m.priority_change += delta;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::register_lru_page_type
|
|
|
-// Access: Public
|
|
|
-// Description: Registers a specific type of page and its
|
|
|
-// required page in and out functions.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-bool Lru::register_lru_page_type (int index,
|
|
|
- LruPageTypeFunction page_in_function,
|
|
|
- LruPageTypeFunction page_out_function)
|
|
|
-{
|
|
|
- bool state;
|
|
|
-
|
|
|
- state = false;
|
|
|
- if(index >= 0 && index < MAXIMUM_LRU_PAGE_TYPES) {
|
|
|
- this->_m.page_in_function_array[index] = page_in_function;
|
|
|
- this->_m.page_out_function_array[index] = page_out_function;
|
|
|
- state = true;
|
|
|
- }
|
|
|
-
|
|
|
- return state;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::allocate_page
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-LruPage *Lru::allocate_page (int size)
|
|
|
-{
|
|
|
- LruPage * lru_page;
|
|
|
-
|
|
|
- lru_page = 0;
|
|
|
- if(size <= this->_m.maximum_memory) {
|
|
|
- if(this->_m.maximum_pages) {
|
|
|
- if(this->_m.total_lru_pages_in_free_pool > 0) {
|
|
|
- lru_page =
|
|
|
- this->_m.lru_page_free_pool [this->_m.total_lru_pages_in_free_pool - 1];
|
|
|
- this->_m.total_lru_pages_in_free_pool--;
|
|
|
-
|
|
|
- memset (&lru_page -> _m, 0, sizeof (LruPage::LruPageVariables));
|
|
|
- lru_page->_m.pre_allocated = true;
|
|
|
- }
|
|
|
- else {
|
|
|
- if(this->_m.total_lru_pages_in_pool < this->_m.maximum_pages) {
|
|
|
- lru_page = this->_m.lru_page_pool[this->_m.total_lru_pages_in_pool];
|
|
|
- this->_m.total_lru_pages_in_pool++;
|
|
|
- }
|
|
|
- else {
|
|
|
- // out of pre-allocated LruPages so dynamically allocate a page
|
|
|
- lru_page = new LruPage ( );
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- lru_page = new LruPage;
|
|
|
- }
|
|
|
- if(lru_page) {
|
|
|
- lru_page->_m.lru = this;
|
|
|
- lru_page->_m.size = size;
|
|
|
- lru_page->_m.first_frame_identifier = this->_m.current_frame_identifier;
|
|
|
- lru_page->_m.last_frame_identifier = this->_m.current_frame_identifier;
|
|
|
-
|
|
|
- lru_page->_m.allocated = true;
|
|
|
- lru_page->_m.identifier = this->_m.identifier;
|
|
|
-
|
|
|
- lru_page->_m.average_frame_utilization = 1.0f;
|
|
|
-
|
|
|
- this->_m.total_pages++;
|
|
|
- this->_m.identifier++;
|
|
|
- }
|
|
|
- else {
|
|
|
-
|
|
|
-// ERROR: could not allocate LruPage
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
-
|
|
|
-// ERROR: requested page size is larger than maximum memory size
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return lru_page;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::update_start_update_lru_page
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::update_start_update_lru_page (LruPage *lru_page)
|
|
|
-{
|
|
|
- if(lru_page) {
|
|
|
- if(this->_m.start_update_lru_page == lru_page) {
|
|
|
- if(lru_page->_m.next) {
|
|
|
- this->_m.start_update_lru_page = lru_page->_m.next;
|
|
|
- }
|
|
|
- else {
|
|
|
- if((this->_m.start_priority_index + 1) >= LPP_TotalPriorities) {
|
|
|
- this->_m.start_priority_index = 0;
|
|
|
- }
|
|
|
- else {
|
|
|
- this->_m.start_priority_index = this->_m.start_priority_index + 1;
|
|
|
- }
|
|
|
-
|
|
|
- this->_m.start_update_lru_page = 0;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::free_page
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::free_page (LruPage *lru_page)
|
|
|
-{
|
|
|
- if(this->_m.total_pages > 0) {
|
|
|
- if(lru_page) {
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- this->update_start_update_lru_page(lru_page);
|
|
|
-
|
|
|
- if(lru_page->_m.in_cache) {
|
|
|
- this->_m.available_memory += lru_page->_m.size;
|
|
|
- }
|
|
|
-
|
|
|
- if(lru_page->_m.pre_allocated) {
|
|
|
- if(this->_m.maximum_pages) {
|
|
|
- lru_page->_m.allocated = false;
|
|
|
- this->_m.lru_page_free_pool [this->_m.total_lru_pages_in_free_pool] =
|
|
|
- lru_page;
|
|
|
- this->_m.total_lru_pages_in_free_pool++;
|
|
|
- }
|
|
|
- else {
|
|
|
-// ERROR: this case should not happen
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- delete lru_page;
|
|
|
- }
|
|
|
-
|
|
|
- this->_m.total_pages--;
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
-
|
|
|
-// ERROR: tried to free a page when 0 pages allocated
|
|
|
-
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::add_page
|
|
|
-// Access: Public
|
|
|
-// Description: Adds a page to the LRU based on the given priority.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::add_page (LruPagePriority priority, LruPage *lru_page)
|
|
|
-{
|
|
|
- if(lru_page) {
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- LruPage * first_lru_page;
|
|
|
-
|
|
|
- lru_page->_m.priority = priority;
|
|
|
-
|
|
|
- first_lru_page = this->_m.lru_page_array[lru_page->_m.priority];
|
|
|
- if(first_lru_page) {
|
|
|
- first_lru_page->_m.previous = lru_page;
|
|
|
- lru_page->_m.next = first_lru_page;
|
|
|
- }
|
|
|
-
|
|
|
- this->_m.lru_page_array[lru_page->_m.priority] = lru_page;
|
|
|
-
|
|
|
- lru_page->_m.in_lru = true;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::add_cached_page
|
|
|
-// Access: Public
|
|
|
-// Description: Adds a page that is already paged in to the LRU
|
|
|
-// based on the given priority.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::add_cached_page (LruPagePriority priority, LruPage *lru_page)
|
|
|
-{
|
|
|
- if(lru_page) {
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- lru_page->_m.in_cache = true;
|
|
|
-
|
|
|
- if(lru_page->_m.size > this->_m.available_memory) {
|
|
|
- int memory_required;
|
|
|
-
|
|
|
- memory_required = lru_page->_m.size - this->_m.available_memory;
|
|
|
-
|
|
|
- // unload page(s)
|
|
|
- this->page_out_lru(memory_required);
|
|
|
- }
|
|
|
-
|
|
|
- this->_m.available_memory -= lru_page->_m.size;
|
|
|
-
|
|
|
- this->add_page(priority, lru_page);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::remove_page
|
|
|
-// Access: Public
|
|
|
-// Description: Removes a page from the LRU.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::remove_page (LruPage *lru_page)
|
|
|
-{
|
|
|
- if(this) {
|
|
|
- if(this->_m.total_pages > 0) {
|
|
|
- if(lru_page) {
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- this->update_start_update_lru_page(lru_page);
|
|
|
-
|
|
|
- if(lru_page->_m.previous) {
|
|
|
- lru_page->_m.previous->_m.next = lru_page->_m.next;
|
|
|
- if(lru_page->_m.next) {
|
|
|
- lru_page->_m.next->_m.previous = lru_page->_m.previous;
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- this->_m.lru_page_array[lru_page->_m.priority] =
|
|
|
- lru_page->_m.next;
|
|
|
- if(lru_page->_m.next) {
|
|
|
- lru_page->_m.next->_m.previous = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- lru_page->_m.next = 0;
|
|
|
- lru_page->_m.previous = 0;
|
|
|
-
|
|
|
- lru_page->_m.in_lru = false;
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
-
|
|
|
-// ERROR: tried to remove a page when 0 pages are allocated
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
-
|
|
|
-// ERROR: Lru == 0, this should not happen
|
|
|
-
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::lock_page
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::lock_page (LruPage *lru_page)
|
|
|
-{
|
|
|
- lru_page->_m.lock = true;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::unlock_page
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::unlock_page (LruPage *lru_page)
|
|
|
-{
|
|
|
- lru_page->_m.lock = false;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::access_page
|
|
|
-// Access: Public
|
|
|
-// Description: This must always be called before accessing or
|
|
|
-// using a page's memory since it pages in the page
|
|
|
-// if it is currently paged out.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::access_page (LruPage *lru_page)
|
|
|
-{
|
|
|
- if(lru_page) {
|
|
|
- if(lru_page->_m.current_frame_identifier
|
|
|
- == this->_m.current_frame_identifier) {
|
|
|
- lru_page->_m.current_frame_usage++;
|
|
|
- this->_m.total_page_all_access_size += lru_page->_m.size;
|
|
|
- }
|
|
|
- else {
|
|
|
- // first update this frame
|
|
|
- lru_page->_m.last_frame_identifier = lru_page->_m.current_frame_identifier;
|
|
|
- lru_page->_m.current_frame_identifier = this->_m.current_frame_identifier;
|
|
|
- lru_page->_m.last_frame_usage = lru_page->_m.current_frame_usage;
|
|
|
- lru_page->_m.current_frame_usage = 1;
|
|
|
- lru_page->_m.total_frame_page_faults = 0;
|
|
|
-
|
|
|
- this->_m.total_page_access_size += lru_page->_m.size;
|
|
|
- }
|
|
|
-
|
|
|
- // check if the page is out
|
|
|
- if(lru_page->_m.in_cache == false) {
|
|
|
- bool state;
|
|
|
-
|
|
|
- state = true;
|
|
|
-
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- // check memory usage
|
|
|
- if(lru_page->_m.size > this->_m.available_memory) {
|
|
|
- int memory_required;
|
|
|
-
|
|
|
- memory_required = lru_page->_m.size - this->_m.available_memory;
|
|
|
-
|
|
|
- // unload page(s)
|
|
|
- state = this->page_out_lru(memory_required);
|
|
|
- }
|
|
|
-
|
|
|
- // load the page in
|
|
|
- if(state) {
|
|
|
- // PAGE IN CALLBACK
|
|
|
- if(this->_m.page_in_function_array[lru_page->_m.type](lru_page)) {
|
|
|
- this->_m.available_memory -= lru_page->_m.size;
|
|
|
- lru_page->_m.in_cache = true;
|
|
|
-
|
|
|
- // CHANGE THE PAGE PRIORITY FROM LPP_PageOut TO LPP_New
|
|
|
- this->remove_page(lru_page);
|
|
|
- this->add_page(LPP_New, lru_page);
|
|
|
-
|
|
|
- this->_m.total_lifetime_page_ins++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- lru_page->_m.total_frame_page_faults++;
|
|
|
- lru_page->_m.total_page_faults++;
|
|
|
- }
|
|
|
-
|
|
|
- lru_page->_m.total_usage++;
|
|
|
- lru_page->_m.update_total_usage++;
|
|
|
-
|
|
|
- this->_m.total_page_access++;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::set_maximum_frame_bandwidth_utilization
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::set_maximum_frame_bandwidth_utilization
|
|
|
- (float maximum_frame_bandwidth_utilization)
|
|
|
-{
|
|
|
- this->_m.maximum_frame_bandwidth_utilization =
|
|
|
- maximum_frame_bandwidth_utilization;
|
|
|
-
|
|
|
- this->_m.frame_bandwidth_factor = (float) LPP_TotalPriorities
|
|
|
- / this->_m.maximum_frame_bandwidth_utilization;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::begin_frame
|
|
|
-// Access: Public
|
|
|
-// Description: This must be called before each frame.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::begin_frame ( )
|
|
|
-{
|
|
|
- this->_m.current_frame_identifier++;
|
|
|
-
|
|
|
- this->_m.total_page_ins_last_frame = this->_m.total_page_ins;
|
|
|
- this->_m.total_page_outs = this->_m.total_page_outs;
|
|
|
-
|
|
|
- this->_m.total_page_ins = 0;
|
|
|
- this->_m.total_page_outs = 0;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::update_page_priorities
|
|
|
-// Access: Public
|
|
|
-// Description: This updates the priority of a page that has a
|
|
|
-// change in priority.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::update_page_priorities (void)
|
|
|
-{
|
|
|
- int index;
|
|
|
- LruPage *lru_page;
|
|
|
-
|
|
|
- for(index = 0; index < this->_m.total_lru_page_priority_changes; index++) {
|
|
|
- int priority;
|
|
|
-
|
|
|
- lru_page = this->_m.lru_page_priority_change_array[index];
|
|
|
-
|
|
|
- this->remove_page(lru_page);
|
|
|
-
|
|
|
- priority = (( int ) lru_page->_m.priority + lru_page->_m.priority_change);
|
|
|
- if(priority < 0) {
|
|
|
- priority = 0;
|
|
|
- }
|
|
|
- if(priority >= LPP_TotalPriorities) {
|
|
|
- priority = LPP_TotalPriorities - 1;
|
|
|
- }
|
|
|
-
|
|
|
- this->add_page((LruPagePriority) priority, lru_page);
|
|
|
- lru_page->_m.priority_change = 0;
|
|
|
- }
|
|
|
- this->_m.total_lru_page_priority_changes = 0;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::update_lru_page
|
|
|
-// Access: Public
|
|
|
-// Description: This updates the page's average utilization.
|
|
|
-// Priority LPP_New is considered to be average usage
|
|
|
-// of 1.0 (which means the page is used once per frame
|
|
|
-// on average). Priorities < LPP_New are for pages
|
|
|
-// used more than once per frame and Priorities >
|
|
|
-// LPP_New are for pages used less than once per frame.
|
|
|
-// If there was a change in priority, then adds it to
|
|
|
-// the array of lru pages with changed priorities
|
|
|
-// which will be updated later.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::update_lru_page (LruPage *lru_page)
|
|
|
-{
|
|
|
-
|
|
|
-#if LRU_UNIT_TEST
|
|
|
- if(false) {
|
|
|
- char string[256];
|
|
|
-
|
|
|
- sprintf(string, " UPDATE %d\n", lru_page->_m.identifier);
|
|
|
- OutputDebugString(string);
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- if(lru_page->_m.lock == false && lru_page->_m.in_cache) {
|
|
|
- int delta_priority;
|
|
|
- int lifetime_frames;
|
|
|
-
|
|
|
- delta_priority = 0;
|
|
|
-
|
|
|
- lifetime_frames = this->_m.current_frame_identifier -
|
|
|
- lru_page->_m.first_frame_identifier;
|
|
|
- if(lifetime_frames >= 1) {
|
|
|
- if(lru_page->_m.update_frame_identifier) {
|
|
|
- int target_priority;
|
|
|
- int integer_update_frames;
|
|
|
- float update_frames;
|
|
|
- float one_over_update_frames;
|
|
|
- float update_average_frame_utilization;
|
|
|
-
|
|
|
- integer_update_frames = (this->_m.current_frame_identifier -
|
|
|
- lru_page->_m.update_frame_identifier);
|
|
|
- if(integer_update_frames > 0) {
|
|
|
- update_frames = ( float ) integer_update_frames;
|
|
|
- one_over_update_frames = 1.0f / update_frames;
|
|
|
-
|
|
|
- update_average_frame_utilization =
|
|
|
- (float) (lru_page->_m.update_total_usage)* one_over_update_frames;
|
|
|
-
|
|
|
- lru_page->_m.average_frame_utilization =
|
|
|
- calculate_exponential_moving_average(
|
|
|
- update_average_frame_utilization, this->_m.weight,
|
|
|
- lru_page->_m.average_frame_utilization);
|
|
|
-
|
|
|
- target_priority = lru_page->_m.priority;
|
|
|
- if(lru_page->_m.average_frame_utilization >= 1.0f) {
|
|
|
- int integer_average_frame_utilization;
|
|
|
-
|
|
|
- integer_average_frame_utilization =
|
|
|
- (int) ((lru_page->_m.average_frame_utilization - 1.0f) *
|
|
|
- (float) HIGH_PRIORITY_SCALE);
|
|
|
- if(integer_average_frame_utilization >= LPP_New) {
|
|
|
- integer_average_frame_utilization = LPP_New;
|
|
|
- }
|
|
|
- integer_average_frame_utilization = LPP_New -
|
|
|
- integer_average_frame_utilization;
|
|
|
- target_priority = integer_average_frame_utilization;
|
|
|
- }
|
|
|
- else {
|
|
|
- int integer_average_frame_utilization;
|
|
|
-
|
|
|
- integer_average_frame_utilization = (int)
|
|
|
- (lru_page->_m.average_frame_utilization *
|
|
|
- (float) LOW_PRIORITY_RANGE);
|
|
|
- integer_average_frame_utilization = LOW_PRIORITY_RANGE -
|
|
|
- integer_average_frame_utilization;
|
|
|
- target_priority = LPP_New + integer_average_frame_utilization;
|
|
|
- }
|
|
|
-
|
|
|
- delta_priority = target_priority - lru_page->_m.priority;
|
|
|
- lru_page->change_priority(delta_priority);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- lru_page->_m.update_frame_identifier = this->_m.current_frame_identifier;
|
|
|
- lru_page->_m.update_total_usage = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if(lru_page->_m.priority_change) {
|
|
|
- if(this->_m.total_lru_page_priority_changes
|
|
|
- < FRAME_MAXIMUM_PRIORITY_CHANGES)
|
|
|
- {
|
|
|
- this->_m.lru_page_priority_change_array
|
|
|
- [this->_m.total_lru_page_priority_changes] = lru_page;
|
|
|
- this->_m.total_lru_page_priority_changes++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::update_lru_page_old
|
|
|
-// Access: Public
|
|
|
-// Description: This updates the page's average utilization and
|
|
|
-// adds it to the array of pages with changed
|
|
|
-// priorities if there was a change in priority.
|
|
|
-// Old method.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::update_lru_page_old (LruPage *lru_page)
|
|
|
-{
|
|
|
-
|
|
|
-#if LRU_UNIT_TEST
|
|
|
- if(false) {
|
|
|
- char string[256];
|
|
|
-
|
|
|
- sprintf(string, " UPDATE %d\n", lru_page->_m.identifier);
|
|
|
- OutputDebugString(string);
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- if(lru_page->_m.lock == false) {
|
|
|
- int delta_priority;
|
|
|
-
|
|
|
- delta_priority = 0;
|
|
|
- if(false && lru_page->_m.total_usage > 0) {
|
|
|
- int lifetime_frames;
|
|
|
-
|
|
|
- lifetime_frames = this->_m.current_frame_identifier -
|
|
|
- lru_page->_m.first_frame_identifier;
|
|
|
- if(lifetime_frames >= 10) {
|
|
|
- float one_over_update_frames;
|
|
|
-
|
|
|
- if(lru_page->_m.update_frame_identifier) {
|
|
|
- int target_priority;
|
|
|
- int integer_update_frames;
|
|
|
- float update_frames;
|
|
|
- float update_average_frame_utilization;
|
|
|
- float average_frame_bandwidth_utilization;
|
|
|
-
|
|
|
- integer_update_frames = (this->_m.current_frame_identifier -
|
|
|
- lru_page->_m.update_frame_identifier);
|
|
|
- if(integer_update_frames > 0) {
|
|
|
- update_frames = ( float ) integer_update_frames;
|
|
|
- one_over_update_frames = 1.0f / update_frames;
|
|
|
-
|
|
|
- update_average_frame_utilization =
|
|
|
- (float) (lru_page->_m.update_total_usage) *
|
|
|
- one_over_update_frames;
|
|
|
-
|
|
|
- lru_page->_m.average_frame_utilization =
|
|
|
- calculate_exponential_moving_average (
|
|
|
- update_average_frame_utilization, this->_m.weight,
|
|
|
- lru_page->_m.average_frame_utilization);
|
|
|
-
|
|
|
- average_frame_bandwidth_utilization =
|
|
|
- lru_page->_m.average_frame_utilization *
|
|
|
- lru_page->_m.size;
|
|
|
-
|
|
|
- target_priority = (int) (average_frame_bandwidth_utilization *
|
|
|
- this->_m.frame_bandwidth_factor);
|
|
|
-
|
|
|
- target_priority = (LPP_TotalPriorities - 1) - target_priority;
|
|
|
- if(target_priority < 0) {
|
|
|
- target_priority = 0;
|
|
|
- }
|
|
|
- if(target_priority >= LPP_TotalPriorities) {
|
|
|
- target_priority = LPP_TotalPriorities - 1;
|
|
|
- }
|
|
|
-
|
|
|
- delta_priority = target_priority - lru_page->_m.priority;
|
|
|
- lru_page->change_priority(delta_priority);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- lru_page->_m.update_frame_identifier =
|
|
|
- this->_m.current_frame_identifier;
|
|
|
-
|
|
|
- lru_page->_m.update_total_usage = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(delta_priority == 0) {
|
|
|
- if(this->_m.current_frame_identifier
|
|
|
- == lru_page->_m.current_frame_identifier) {
|
|
|
- // page used during this frame twice or more =>
|
|
|
- // increase priority
|
|
|
- if(lru_page->_m.current_frame_usage >= 2) {
|
|
|
- if(lru_page->_m.priority >= LPP_High) {
|
|
|
- lru_page->change_priority(-2);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(lru_page->_m.total_frame_page_faults >= 1) {
|
|
|
- // multiple page faults this frame => increase priority
|
|
|
- if(lru_page->_m.total_frame_page_faults >= 2) {
|
|
|
- if(lru_page->_m.priority >= LPP_High) {
|
|
|
- lru_page->change_priority(-2);
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- // single page faults this frame => increase priority
|
|
|
- if(lru_page->_m.priority >= LPP_High) {
|
|
|
- lru_page->change_priority(-1);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- // page not used this frame
|
|
|
- int last_access_delta;
|
|
|
-
|
|
|
- last_access_delta
|
|
|
- = this->_m.current_frame_identifier
|
|
|
- - lru_page->_m.current_frame_identifier;
|
|
|
- if(last_access_delta > 1) {
|
|
|
- if(lru_page->_m.priority < LPP_Low) {
|
|
|
- lru_page->change_priority(+1);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(lru_page->_m.priority_change) {
|
|
|
- if(this->_m.total_lru_page_priority_changes
|
|
|
- < FRAME_MAXIMUM_PRIORITY_CHANGES) {
|
|
|
- this->_m.lru_page_priority_change_array
|
|
|
- [this->_m.total_lru_page_priority_changes ]= lru_page;
|
|
|
- this->_m.total_lru_page_priority_changes++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::update_entire_lru
|
|
|
-// Access: Public
|
|
|
-// Description: This updates all the pages in the Lru.
|
|
|
-// Lru::partial_lru_update should be called instead
|
|
|
-// due to performance reasons.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::update_entire_lru ( )
|
|
|
-{
|
|
|
- if(this->_m.total_pages > 0) {
|
|
|
- int index;
|
|
|
- LruPage *lru_page;
|
|
|
-
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- for(index = 0; index < LPP_TotalPriorities; index++) {
|
|
|
-
|
|
|
- LruPage * next_lru_page;
|
|
|
-
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- while(lru_page) {
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- this->update_lru_page(lru_page);
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- this->update_page_priorities( );
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::partial_lru_update
|
|
|
-// Access: Public
|
|
|
-// Description: This only updates a number of pages up to the
|
|
|
-// specified maximum_updates.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::partial_lru_update (int maximum_updates)
|
|
|
-{
|
|
|
- int total_page_updates;
|
|
|
-
|
|
|
- if (maximum_updates <= 0) {
|
|
|
- // enforce a minimum number of updates
|
|
|
- maximum_updates = 1;
|
|
|
- }
|
|
|
-
|
|
|
- total_page_updates = 0;
|
|
|
- if(this->_m.total_pages > 0) {
|
|
|
- int index;
|
|
|
- int start_priority;
|
|
|
- LruPage *lru_page;
|
|
|
-
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- start_priority = this->_m.start_priority_index;
|
|
|
-
|
|
|
- {
|
|
|
- for(index = start_priority; index < LPP_TotalPriorities; index++) {
|
|
|
-
|
|
|
- LruPage *next_lru_page;
|
|
|
-
|
|
|
- if(index == start_priority) {
|
|
|
- if(this->_m.start_update_lru_page) {
|
|
|
- lru_page = this->_m.start_update_lru_page;
|
|
|
- }
|
|
|
- else {
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- }
|
|
|
- while(lru_page) {
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- this->update_lru_page(lru_page);
|
|
|
-
|
|
|
- total_page_updates++;
|
|
|
- if(total_page_updates >= maximum_updates) {
|
|
|
- if(next_lru_page) {
|
|
|
- this->_m.start_priority_index = index;
|
|
|
- this->_m.start_update_lru_page = next_lru_page;
|
|
|
- }
|
|
|
- else {
|
|
|
- if((index + 1) >= LPP_TotalPriorities) {
|
|
|
- this->_m.start_priority_index = 0;
|
|
|
- }
|
|
|
- else {
|
|
|
- this->_m.start_priority_index = index + 1;
|
|
|
- }
|
|
|
-
|
|
|
- this->_m.start_update_lru_page = 0;
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
-
|
|
|
- if(total_page_updates >= maximum_updates) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(total_page_updates < maximum_updates) {
|
|
|
- for(index = 0; index <= start_priority; index++) {
|
|
|
- LruPage *next_lru_page;
|
|
|
-
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- while(lru_page) {
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- this->update_lru_page(lru_page);
|
|
|
-
|
|
|
- total_page_updates++;
|
|
|
- if(total_page_updates >= maximum_updates) {
|
|
|
- if(next_lru_page) {
|
|
|
- this->_m.start_priority_index = index;
|
|
|
- this->_m.start_update_lru_page = next_lru_page;
|
|
|
- }
|
|
|
- else {
|
|
|
- if((index + 1) >= LPP_TotalPriorities) {
|
|
|
- this->_m.start_priority_index = 0;
|
|
|
- }
|
|
|
- else {
|
|
|
- this->_m.start_priority_index = index + 1;
|
|
|
- }
|
|
|
-
|
|
|
- this->_m.start_update_lru_page = 0;
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
-
|
|
|
- if(total_page_updates >= maximum_updates) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(total_page_updates < maximum_updates) {
|
|
|
- this->_m.start_priority_index = 0;
|
|
|
- this->_m.start_update_lru_page = 0;
|
|
|
- }
|
|
|
-
|
|
|
- this->update_page_priorities( );
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::unlock_all_pages
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::unlock_all_pages (void)
|
|
|
-{
|
|
|
- if(this->_m.total_pages > 0) {
|
|
|
- int index;
|
|
|
-
|
|
|
- for(index = 0; index < LPP_TotalPriorities; index++) {
|
|
|
- LruPage *lru_page;
|
|
|
- LruPage *next_lru_page;
|
|
|
-
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- while(lru_page) {
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- lru_page->_m.lock = false;
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::page_out_lru
|
|
|
-// Access: Public
|
|
|
-// Description: Pages out the lowest priority pages until the
|
|
|
-// memory_required is satisfied. This will unlock
|
|
|
-// all pages if needed.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-bool Lru::page_out_lru (int memory_required)
|
|
|
-{
|
|
|
- bool state;
|
|
|
- int attempts;
|
|
|
-
|
|
|
- state = false;
|
|
|
- attempts = 0;
|
|
|
- if(this->_m.total_pages > 0) {
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- do {
|
|
|
- int index;
|
|
|
-
|
|
|
- // page out lower priority pages first
|
|
|
- for(index = LPP_PageOut - 1; index >= 0; index--) {
|
|
|
- LruPage *lru_page;
|
|
|
- LruPage *next_lru_page;
|
|
|
-
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- while(lru_page) {
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- if(lru_page->_m.lock == false && lru_page->_m.in_cache) {
|
|
|
- memory_required -= lru_page->_m.size;
|
|
|
- this->_m.available_memory += lru_page->_m.size;
|
|
|
- lru_page->_m.in_cache = false;
|
|
|
-
|
|
|
- // PAGE OUT CALLBACK
|
|
|
- this->_m.page_out_function_array[lru_page->_m.type](lru_page);
|
|
|
- this->_m.total_lifetime_page_outs++;
|
|
|
-
|
|
|
- // MOVE THE PAGE TO THE LPP_PageOut PRIORITY
|
|
|
- this->remove_page(lru_page);
|
|
|
- this->add_page(LPP_PageOut, lru_page);
|
|
|
-
|
|
|
- if(memory_required <= 0) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
-
|
|
|
- if(memory_required <= 0) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(memory_required > 0) {
|
|
|
- // WARNING: pages could not be freed, all pages unlocked
|
|
|
- this->unlock_all_pages( );
|
|
|
- state = false;
|
|
|
- }
|
|
|
- else {
|
|
|
- state = true;
|
|
|
- }
|
|
|
-
|
|
|
- attempts++;
|
|
|
- } while(state == false && attempts < 2);
|
|
|
- }
|
|
|
-
|
|
|
- return state;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::count_priority_level_pages
|
|
|
-// Access: Public
|
|
|
-// Description: Debug function. Counts the number of pages for each
|
|
|
-// priority level.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::count_priority_level_pages (void)
|
|
|
-{
|
|
|
- int index;
|
|
|
-
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- for(index = 0; index < LPP_TotalPriorities; index++) {
|
|
|
- int total_pages;
|
|
|
- LruPage *lru_page;
|
|
|
- LruPage *next_lru_page;
|
|
|
-
|
|
|
- total_pages = 0;
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- while(lru_page) {
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- total_pages++;
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
-
|
|
|
- this->_m.lru_page_count_array[index] = total_pages;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Lru::calculate_lru_statistics
|
|
|
-// Access: Public
|
|
|
-// Description: Debug function.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void Lru::calculate_lru_statistics (void)
|
|
|
-{
|
|
|
- LruMutexHolder(this->_m.mutex);
|
|
|
-
|
|
|
- if(this->_m.maximum_page_types > 0) {
|
|
|
- int index;
|
|
|
-
|
|
|
- memset(this->_m.page_type_statistics_array, 0,
|
|
|
- sizeof (PageTypeStatistics) * this->_m.maximum_page_types);
|
|
|
- for(index = 0; index < LPP_TotalPriorities; index++) {
|
|
|
- LruPage *lru_page;
|
|
|
- LruPage *next_lru_page;
|
|
|
- PageTypeStatistics *page_type_statistics;
|
|
|
-
|
|
|
- lru_page = this->_m.lru_page_array[index];
|
|
|
- while(lru_page) {
|
|
|
- int type;
|
|
|
-
|
|
|
- next_lru_page = lru_page->_m.next;
|
|
|
-
|
|
|
- type = lru_page->_m.type;
|
|
|
- page_type_statistics = &this->_m.page_type_statistics_array[type];
|
|
|
- page_type_statistics->total_pages++;
|
|
|
-
|
|
|
- if(lru_page->_m.in_cache) {
|
|
|
- page_type_statistics->total_pages_in++;
|
|
|
- page_type_statistics->total_memory_in += lru_page->_m.size;
|
|
|
- }
|
|
|
- else {
|
|
|
- page_type_statistics->total_pages_out++;
|
|
|
- page_type_statistics->total_memory_out += lru_page->_m.size;
|
|
|
- }
|
|
|
-
|
|
|
- lru_page = next_lru_page;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: calculate_exponential_moving_average
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-float calculate_exponential_moving_average(float value,
|
|
|
- float weight, float average)
|
|
|
-{
|
|
|
- return ((value - average) * weight) + average;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: default_page_in_function
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-bool default_page_in_function(LruPage *lru_page)
|
|
|
-{
|
|
|
-
|
|
|
-#if LRU_UNIT_TEST
|
|
|
- char string[256];
|
|
|
-
|
|
|
- sprintf(string, " PAGE IN %d\n", lru_page->_m.identifier);
|
|
|
- OutputDebugString(string);
|
|
|
-#endif
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: default_page_out_function
|
|
|
-// Access: Public
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-bool default_page_out_function(LruPage *lru_page)
|
|
|
-{
|
|
|
-
|
|
|
-#if LRU_UNIT_TEST
|
|
|
- char string[256];
|
|
|
-
|
|
|
- sprintf(string, " PAGE OUT %d\n", lru_page->_m.identifier);
|
|
|
- OutputDebugString(string);
|
|
|
-#endif
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-#if LRU_UNIT_TEST
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: test_ema
|
|
|
-// Access:
|
|
|
-// Description: Unit test function for ema.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void test_ema(void)
|
|
|
-{
|
|
|
- int index;
|
|
|
- float usage;
|
|
|
- float weight;
|
|
|
- float average;
|
|
|
-
|
|
|
- weight = 0.2f;
|
|
|
- average = 1.0f;
|
|
|
- for(index = 0; index < 50; index++) {
|
|
|
- if(index < 25) {
|
|
|
- usage = (float) (index & 0x01);
|
|
|
- }
|
|
|
- else {
|
|
|
- usage = 0.0f;
|
|
|
- }
|
|
|
- average =
|
|
|
- calculate_exponential_moving_average(usage, weight, average);
|
|
|
-
|
|
|
- char string[256];
|
|
|
- sprintf(string, "%d %f\n", index, average);
|
|
|
- OutputDebugString(string);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: test_lru
|
|
|
-// Access:
|
|
|
-// Description: Unit test function for Lru.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void test_lru(void)
|
|
|
-{
|
|
|
- int maximum_memory;
|
|
|
- int maximum_pages;
|
|
|
- int maximum_page_types;
|
|
|
- Lru *lru;
|
|
|
-
|
|
|
- test_ema( );
|
|
|
-
|
|
|
- maximum_memory = 3000000;
|
|
|
- maximum_pages = 3;
|
|
|
- maximum_page_types = 4;
|
|
|
- lru = new Lru (maximum_memory, maximum_pages, maximum_page_types);
|
|
|
- if(lru) {
|
|
|
- lru->_m.minimum_memory = 1000000;
|
|
|
-
|
|
|
- LruPage *lru_page_0;
|
|
|
- LruPage *lru_page_1;
|
|
|
- LruPage *lru_page_2;
|
|
|
- LruPage *lru_page_3;
|
|
|
- LruPage *lru_page_4;
|
|
|
- LruPage *lru_page_5;
|
|
|
-
|
|
|
- lru_page_0 = lru->allocate_page(1000000);
|
|
|
- if(lru_page_0) {
|
|
|
- lru->add_page(LPP_PageOut, lru_page_0);
|
|
|
- }
|
|
|
-
|
|
|
- lru_page_1 = lru->allocate_page(1000000);
|
|
|
- if(lru_page_1) {
|
|
|
- lru->add_page(LPP_PageOut, lru_page_1);
|
|
|
- }
|
|
|
-
|
|
|
- lru_page_2 = lru->allocate_page(1000000);
|
|
|
- if(lru_page_2) {
|
|
|
- lru->add_page(LPP_PageOut, lru_page_2);
|
|
|
- }
|
|
|
-
|
|
|
- lru_page_3 = lru->allocate_page(1000000);
|
|
|
- if(lru_page_3) {
|
|
|
- lru->add_page(LPP_PageOut, lru_page_3);
|
|
|
- }
|
|
|
-
|
|
|
- lru_page_4 = lru->allocate_page(1000000);
|
|
|
- if(lru_page_4) {
|
|
|
- lru->add_page(LPP_PageOut, lru_page_4);
|
|
|
- }
|
|
|
-
|
|
|
- lru_page_5 = lru->allocate_page(1000000);
|
|
|
- if(lru_page_5) {
|
|
|
- lru->add_page(LPP_PageOut, lru_page_5);
|
|
|
- }
|
|
|
-
|
|
|
- int index;
|
|
|
- int total_frames;
|
|
|
-
|
|
|
- total_frames = 300;
|
|
|
- for(index = 0; index < total_frames; index++) {
|
|
|
- char string[256];
|
|
|
-
|
|
|
- sprintf(string, "FRAME %d\n", index);
|
|
|
- OutputDebugString(string);
|
|
|
-
|
|
|
- lru->begin_frame( );
|
|
|
-
|
|
|
- if(index <= 5) {
|
|
|
- lru->access_page(lru_page_0);
|
|
|
- }
|
|
|
-
|
|
|
- lru->access_page(lru_page_1);
|
|
|
- lru->access_page(lru_page_1);
|
|
|
-
|
|
|
- if(index & 0x01) {
|
|
|
- lru->access_page(lru_page_2);
|
|
|
- }
|
|
|
-
|
|
|
- if((index % 10) == 0) {
|
|
|
- lru->access_page(lru_page_3);
|
|
|
- }
|
|
|
-
|
|
|
- if(index >= 100) {
|
|
|
- lru->access_page(lru_page_4);
|
|
|
- }
|
|
|
-
|
|
|
- if(index >= 200) {
|
|
|
- lru->access_page(lru_page_5);
|
|
|
- }
|
|
|
-
|
|
|
- if(false) {
|
|
|
- lru->update_entire_lru( );
|
|
|
- }
|
|
|
- else {
|
|
|
- int maximum_updates;
|
|
|
-
|
|
|
- maximum_updates = 3;
|
|
|
- lru->partial_lru_update(maximum_updates);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(!true) {
|
|
|
- lru->remove_page(lru_page_2);
|
|
|
- lru->free_page(lru_page_2);
|
|
|
-
|
|
|
- lru->remove_page(lru_page_3);
|
|
|
- lru->free_page(lru_page_3);
|
|
|
-
|
|
|
- lru->remove_page(lru_page_1);
|
|
|
- lru->free_page(lru_page_1);
|
|
|
- }
|
|
|
-
|
|
|
- delete lru;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#endif
|