Browse Source

add some documentation
add more stats for lru

aignacio_sf 20 years ago
parent
commit
750bae7b34

+ 27 - 7
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -66,7 +66,7 @@
 
 
 
 
 #define DEBUG_LRU false
 #define DEBUG_LRU false
-#define DEFAULT_ENABLE_LRU !true
+#define DEFAULT_ENABLE_LRU true
 
 
 
 
 TypeHandle DXGraphicsStateGuardian9::_type_handle;
 TypeHandle DXGraphicsStateGuardian9::_type_handle;
@@ -123,9 +123,9 @@ DXGraphicsStateGuardian9(const FrameBufferProperties &properties) :
     Geom::GR_triangle_strip | Geom::GR_triangle_fan |
     Geom::GR_triangle_strip | Geom::GR_triangle_fan |
     Geom::GR_flat_first_vertex;
     Geom::GR_flat_first_vertex;
 
 
-  _gsg_managed_textures = !false;
-  _gsg_managed_vertex_buffers = !false;
-  _gsg_managed_index_buffers = !false;
+  _gsg_managed_textures = false;
+  _gsg_managed_vertex_buffers = false;
+  _gsg_managed_index_buffers = false;
 
 
   _enable_lru = DEFAULT_ENABLE_LRU;
   _enable_lru = DEFAULT_ENABLE_LRU;
 
 
@@ -819,8 +819,8 @@ end_frame() {
 
 
     if (false && dxgsg9_cat.is_debug())
     if (false && dxgsg9_cat.is_debug())
     {
     {
-        dxgsg9_cat.debug() << "*  start_priority_index " << _lru -> _m.start_priority_index << "\n";
-        dxgsg9_cat.debug() << "*  start_update_lru_page " << _lru -> _m.start_update_lru_page << "\n";
+      dxgsg9_cat.debug() << "*  start_priority_index " << _lru -> _m.start_priority_index << "\n";
+      dxgsg9_cat.debug() << "*  start_update_lru_page " << _lru -> _m.start_update_lru_page << "\n";
     }
     }
 
 
     frames = 256;
     frames = 256;
@@ -856,6 +856,24 @@ end_frame() {
             dxgsg9_cat.debug() << "*  priority " << index << " pages " << _lru -> _m.lru_page_count_array [index] << "\n";
             dxgsg9_cat.debug() << "*  priority " << index << " pages " << _lru -> _m.lru_page_count_array [index] << "\n";
           }
           }
         }
         }
+
+        _lru -> calculate_lru_statistics ( );
+
+        for (index = 0; index < _lru -> _m.maximum_page_types; index++)
+        {
+          PageTypeStatistics *page_type_statistics;
+
+          page_type_statistics = &_lru -> _m.page_type_statistics_array [index];
+          dxgsg9_cat.debug() << "\n" <<
+              " page type " << index <<
+              "  total pages " << page_type_statistics -> total_pages <<
+              "  in " << page_type_statistics -> total_pages_in <<
+              "  size " << page_type_statistics -> total_memory_in <<
+              "  out " << page_type_statistics -> total_pages_out <<
+              "  size " << page_type_statistics -> total_memory_out <<
+              "\n";
+
+        }
       }
       }
     }
     }
   }
   }
@@ -1970,6 +1988,7 @@ reset() {
   {
   {
     int maximum_memory;
     int maximum_memory;
     int maximum_pages;
     int maximum_pages;
+    int maximum_page_types;
     Lru *lru;
     Lru *lru;
 
 
 maximum_memory = available_texture_memory;
 maximum_memory = available_texture_memory;
@@ -1977,8 +1996,9 @@ maximum_memory = available_texture_memory;
 // TEST LRU *****
 // TEST LRU *****
 maximum_memory = 55000000;
 maximum_memory = 55000000;
 maximum_pages = 20000;
 maximum_pages = 20000;
+maximum_page_types = GPT_TotalPageTypes;
 
 
-    lru = new Lru (maximum_memory, maximum_pages);
+    lru = new Lru (maximum_memory, maximum_pages, maximum_page_types);
     if (lru)
     if (lru)
     {
     {
       lru -> _m.minimum_memory = 1000000;
       lru -> _m.minimum_memory = 1000000;

+ 2 - 1
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -37,10 +37,11 @@
 
 
 enum GsgPageType
 enum GsgPageType
 {
 {
-  GPT_Error,
   GPT_Texture,
   GPT_Texture,
   GPT_VertexBuffer,
   GPT_VertexBuffer,
   GPT_IndexBuffer,
   GPT_IndexBuffer,
+
+  GPT_TotalPageTypes
 };
 };
 
 
 class Light;
 class Light;

+ 318 - 39
panda/src/dxgsg9/lru.cxx

@@ -1,11 +1,25 @@
-
+// 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
 #define LRU_UNIT_TEST 0
 
 
-#if LRU_UNIT_TEST
-#include "stdafx.h"
-#endif
-
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <windows.h>
 #include <windows.h>
@@ -16,32 +30,35 @@
 #define HIGH_PRIORITY_SCALE 4
 #define HIGH_PRIORITY_SCALE 4
 #define LOW_PRIORITY_RANGE 25
 #define LOW_PRIORITY_RANGE 25
 
 
-float calculate_exponential_moving_average (float value, float weight, float average)
-{
-    return ((value - average) * weight) + average;
-}
 
 
-bool default_page_in_function (LruPage *lru_page)
-{
-  char string [256];
-
-  sprintf (string, "  PAGE IN %d\n", lru_page -> _m.identifier);
-  OutputDebugString (string);
-
-  return true;
-}
-bool default_page_out_function (LruPage *lru_page)
-{
-  char string [256];
-
-  sprintf (string, "  PAGE OUT %d\n", lru_page -> _m.identifier);
-  OutputDebugString (string);
-
-  return true;
-}
-
-
-Lru::Lru (int maximum_memory, int maximum_pages)
+////////////////////////////////////////////////////////////////////
+//       Class : Lru
+// Description : Least Recently Used algorithm implementation:
+// In the Lru, each "memory page" has an associated class LruPage.
+// The Lru has a range of priorities from LPP_Highest to
+// LPP_PagedOut. Each priority has a doubly linked list of LruPages.
+// The algorithim uses an adaptive method based on the average
+// utilization of each page per frame (or time slice). The
+// average utilization is calculated with an exponetial moving
+// average. This is superior to a standard average since a standard
+// average becomes less and less adaptive the longer a page exists.
+// The average utilization is used to set the priority of each page.
+// A higher average utilization automatically raises the priority
+// of a page and a lower average utilization automatically lowers
+// the priority of a page. Therefore, pages with a higher average
+// utilization have a higher chance of being kept in memory or
+// cached and pages with a lower average utilization have a higher
+// chance of being paged out.  When a page is paged in and there
+// is not enough memory available, then the lowest priority pages
+// will be paged out first until there is enough memory available.
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+Lru::Lru (int maximum_memory, int maximum_pages, int maximum_page_types)
 {
 {
   if (this)
   if (this)
   {
   {
@@ -51,6 +68,7 @@ Lru::Lru (int maximum_memory, int maximum_pages)
 
 
     this -> _m.maximum_memory = maximum_memory;
     this -> _m.maximum_memory = maximum_memory;
     this -> _m.maximum_pages = maximum_pages;
     this -> _m.maximum_pages = maximum_pages;
+    this -> _m.maximum_page_types = maximum_page_types;
     this -> _m.available_memory = maximum_memory;
     this -> _m.available_memory = maximum_memory;
     this -> _m.current_frame_identifier = 1;
     this -> _m.current_frame_identifier = 1;
     this -> _m.weight = 0.20f;
     this -> _m.weight = 0.20f;
@@ -83,9 +101,19 @@ Lru::Lru (int maximum_memory, int maximum_pages)
         }
         }
       }
       }
     }
     }
+
+    if (maximum_page_types > 0)
+    {
+      this -> _m.page_type_statistics_array = new PageTypeStatistics [maximum_page_types];
+    }
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 Lru::~Lru ( )
 Lru::~Lru ( )
 {
 {
   int index;
   int index;
@@ -130,8 +158,19 @@ Lru::~Lru ( )
       lru_page = next_lru_page;
       lru_page = next_lru_page;
     }
     }
   }
   }
+
+  if (this -> _m.page_type_statistics_array)
+  {
+    delete this -> _m.page_type_statistics_array;
+  }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: LruPage::Constructor
+//       Access: Protected
+//  Description: Internal function only.
+//               Call  Lru::allocate_page instead.
+////////////////////////////////////////////////////////////////////
 LruPage::LruPage ( )
 LruPage::LruPage ( )
 {
 {
   if (this)
   if (this)
@@ -140,11 +179,33 @@ LruPage::LruPage ( )
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: LruPage::Destructor
+//       Access: Protected
+//  Description: Internal function only.
+//               Call  Lru::free_page instead.
+////////////////////////////////////////////////////////////////////
 LruPage::~LruPage ( )
 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 Lru::register_lru_page_type (int index, LruPageTypeFunction page_in_function, LruPageTypeFunction page_out_function)
 {
 {
   bool state;
   bool state;
@@ -160,11 +221,11 @@ bool Lru::register_lru_page_type (int index, LruPageTypeFunction page_in_functio
   return state;
   return state;
 }
 }
 
 
-void LruPage::change_priority (int delta)
-{
-  this -> _m.priority_change += delta;
-}
-
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::allocate_page
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 LruPage * Lru::allocate_page (int size)
 LruPage * Lru::allocate_page (int size)
 {
 {
   LruPage *lru_page;
   LruPage *lru_page;
@@ -180,6 +241,7 @@ LruPage * Lru::allocate_page (int size)
         this -> _m.total_lru_pages_in_free_pool--;
         this -> _m.total_lru_pages_in_free_pool--;
 
 
         memset (&lru_page -> _m, 0, sizeof (LruPage::LruPageVariables));
         memset (&lru_page -> _m, 0, sizeof (LruPage::LruPageVariables));
+        lru_page -> _m.pre_allocated = true;
       }
       }
       else
       else
       {
       {
@@ -214,6 +276,12 @@ LruPage * Lru::allocate_page (int size)
       this -> _m.total_pages++;
       this -> _m.total_pages++;
       this -> _m.identifier++;
       this -> _m.identifier++;
     }
     }
+    else
+    {
+
+// ERROR: could not allocate LruPage
+
+    }
   }
   }
   else
   else
   {
   {
@@ -225,6 +293,11 @@ LruPage * Lru::allocate_page (int size)
   return lru_page;
   return lru_page;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::update_start_update_lru_page
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 void Lru::update_start_update_lru_page (LruPage *lru_page)
 void Lru::update_start_update_lru_page (LruPage *lru_page)
 {
 {
   if (lru_page)
   if (lru_page)
@@ -252,6 +325,11 @@ void Lru::update_start_update_lru_page (LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::free_page
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 void Lru::free_page (LruPage *lru_page)
 void Lru::free_page (LruPage *lru_page)
 {
 {
   if (this -> _m.total_pages > 0)
   if (this -> _m.total_pages > 0)
@@ -294,6 +372,11 @@ void Lru::free_page (LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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)
 void Lru::add_page (LruPagePriority priority, LruPage *lru_page)
 {
 {
   if (lru_page)
   if (lru_page)
@@ -315,6 +398,12 @@ void Lru::add_page (LruPagePriority priority, LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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)
 void Lru::add_cached_page (LruPagePriority priority, LruPage *lru_page)
 {
 {
   if (lru_page)
   if (lru_page)
@@ -337,6 +426,11 @@ void Lru::add_cached_page (LruPagePriority priority, LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::remove_page
+//       Access: Public
+//  Description: Removes a page from the LRU.
+////////////////////////////////////////////////////////////////////
 void Lru::remove_page (LruPage *lru_page)
 void Lru::remove_page (LruPage *lru_page)
 {
 {
   if (lru_page)
   if (lru_page)
@@ -379,16 +473,33 @@ void Lru::remove_page (LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::lock_page
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 void Lru::lock_page (LruPage *lru_page)
 void Lru::lock_page (LruPage *lru_page)
 {
 {
   lru_page -> _m.lock = true;
   lru_page -> _m.lock = true;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::unlock_page
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 void Lru::unlock_page (LruPage *lru_page)
 void Lru::unlock_page (LruPage *lru_page)
 {
 {
   lru_page -> _m.lock = false;
   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)
 void Lru::access_page (LruPage *lru_page)
 {
 {
   if (lru_page)
   if (lru_page)
@@ -453,12 +564,23 @@ void Lru::access_page (LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::set_maximum_frame_bandwidth_utilization
+//       Access: Public
+//  Description: This must be called before accessing or using a
+//               page since it pages in the page if it is paged out.
+////////////////////////////////////////////////////////////////////
 void Lru::set_maximum_frame_bandwidth_utilization (float maximum_frame_bandwidth_utilization)
 void Lru::set_maximum_frame_bandwidth_utilization (float maximum_frame_bandwidth_utilization)
 {
 {
   this -> _m.maximum_frame_bandwidth_utilization = 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;
   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 ( )
 void Lru::begin_frame ( )
 {
 {
   this -> _m.current_frame_identifier++;
   this -> _m.current_frame_identifier++;
@@ -470,6 +592,12 @@ void Lru::begin_frame ( )
   this -> _m.total_page_outs = 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)
 void Lru::update_page_priorities (void)
 {
 {
   int index;
   int index;
@@ -499,8 +627,17 @@ void Lru::update_page_priorities (void)
   this -> _m.total_lru_page_priority_changes = 0;
   this -> _m.total_lru_page_priority_changes = 0;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::update_lru_page
+//       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.
+////////////////////////////////////////////////////////////////////
 void Lru::update_lru_page (LruPage *lru_page)
 void Lru::update_lru_page (LruPage *lru_page)
 {
 {
+
+#if LRU_UNIT_TEST
   if (false)
   if (false)
   {
   {
     char string [256];
     char string [256];
@@ -508,6 +645,7 @@ void Lru::update_lru_page (LruPage *lru_page)
     sprintf (string, "  UPDATE %d\n", lru_page -> _m.identifier);
     sprintf (string, "  UPDATE %d\n", lru_page -> _m.identifier);
     OutputDebugString (string);
     OutputDebugString (string);
   }
   }
+#endif
 
 
   if (lru_page -> _m.lock == false && lru_page -> _m.in_cache)
   if (lru_page -> _m.lock == false && lru_page -> _m.in_cache)
   {
   {
@@ -582,8 +720,18 @@ void Lru::update_lru_page (LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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)
 void Lru::update_lru_page_old (LruPage *lru_page)
 {
 {
+
+#if LRU_UNIT_TEST
   if (false)
   if (false)
   {
   {
     char string [256];
     char string [256];
@@ -591,6 +739,7 @@ void Lru::update_lru_page_old (LruPage *lru_page)
     sprintf (string, "  UPDATE %d\n", lru_page -> _m.identifier);
     sprintf (string, "  UPDATE %d\n", lru_page -> _m.identifier);
     OutputDebugString (string);
     OutputDebugString (string);
   }
   }
+#endif
 
 
   if (lru_page -> _m.lock == false)
   if (lru_page -> _m.lock == false)
   {
   {
@@ -707,6 +856,13 @@ void Lru::update_lru_page_old (LruPage *lru_page)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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 ( )
 void Lru::update_entire_lru ( )
 {
 {
   if (this -> _m.total_pages > 0)
   if (this -> _m.total_pages > 0)
@@ -733,6 +889,12 @@ void Lru::update_entire_lru ( )
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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)
 void Lru::partial_lru_update (int maximum_updates)
 {
 {
   int total_page_updates;
   int total_page_updates;
@@ -865,6 +1027,11 @@ void Lru::partial_lru_update (int maximum_updates)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lru::unlock_all_pages
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
 void Lru::unlock_all_pages (void)
 void Lru::unlock_all_pages (void)
 {
 {
   if (this -> _m.total_pages > 0)
   if (this -> _m.total_pages > 0)
@@ -889,6 +1056,13 @@ void Lru::unlock_all_pages (void)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     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 Lru::page_out_lru (int memory_required)
 {
 {
   bool state;
   bool state;
@@ -962,6 +1136,12 @@ bool Lru::page_out_lru (int memory_required)
   return state;
   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)
 void Lru::count_priority_level_pages (void)
 {
 {
   int index;
   int index;
@@ -987,8 +1167,100 @@ void Lru::count_priority_level_pages (void)
   }
   }
 }
 }
 
 
+void Lru::calculate_lru_statistics (void)
+{
+  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)
+      {
+        volatile 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
 #if LRU_UNIT_TEST
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: test_ema
+//       Access:
+//  Description: Unit test function for ema.
+////////////////////////////////////////////////////////////////////
 void test_ema (void)
 void test_ema (void)
 {
 {
   int index;
   int index;
@@ -1016,17 +1288,24 @@ void test_ema (void)
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: test_lru
+//       Access:
+//  Description: Unit test function for Lru.
+////////////////////////////////////////////////////////////////////
 void test_lru (void)
 void test_lru (void)
 {
 {
   int maximum_memory;
   int maximum_memory;
   int maximum_pages;
   int maximum_pages;
+  int maximum_page_types;
   Lru *lru;
   Lru *lru;
 
 
   test_ema ( );
   test_ema ( );
 
 
   maximum_memory = 3000000;
   maximum_memory = 3000000;
   maximum_pages = 3;
   maximum_pages = 3;
-  lru = new Lru (maximum_memory, maximum_pages);
+  maximum_page_types = 4;
+  lru = new Lru (maximum_memory, maximum_pages, maximum_page_types);
   if (lru)
   if (lru)
   {
   {
     lru -> _m.minimum_memory = 1000000;
     lru -> _m.minimum_memory = 1000000;
@@ -1121,10 +1400,10 @@ void test_lru (void)
       }
       }
       else
       else
       {
       {
-        int approximate_maximum_updates;
+        int maximum_updates;
 
 
-        approximate_maximum_updates = 3;
-        lru -> partial_lru_update (approximate_maximum_updates);
+        maximum_updates = 3;
+        lru -> partial_lru_update (maximum_updates);
       }
       }
     }
     }
 
 

+ 38 - 8
panda/src/dxgsg9/lru.h

@@ -1,3 +1,20 @@
+// Filename: lru.h
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
 
 
 #ifndef LRU_H
 #ifndef LRU_H
 #define LRU_H
 #define LRU_H
@@ -30,6 +47,16 @@ typedef union _LruPageType
 }
 }
 LruPageType;
 LruPageType;
 
 
+typedef struct
+{
+  int total_pages;
+  int total_pages_in;
+  int total_pages_out;
+  int total_memory_in;
+  int total_memory_out;
+}
+PageTypeStatistics;
+
 typedef bool (*LruPageTypeFunction) (LruPage *lru_page);
 typedef bool (*LruPageTypeFunction) (LruPage *lru_page);
 
 
 class LruPage
 class LruPage
@@ -45,7 +72,7 @@ public:
 
 
   typedef struct _LruPageVariables
   typedef struct _LruPageVariables
   {
   {
-    LruPageType lru_page_type;
+    LruPageType lru_page_type;  // pointer to memory type
 
 
     int size;
     int size;
     LruPagePriority priority;
     LruPagePriority priority;
@@ -53,7 +80,7 @@ public:
 
 
     struct
     struct
     {
     {
-      unsigned int type : 4;
+      unsigned int type : 8;
       unsigned int lock : 1;
       unsigned int lock : 1;
       unsigned int in_cache : 1;
       unsigned int in_cache : 1;
       unsigned int in_memory : 1;
       unsigned int in_memory : 1;
@@ -77,7 +104,7 @@ public:
     int total_usage;
     int total_usage;
     int update_total_usage;
     int update_total_usage;
 
 
-    int identifier; // this is also the number of pages created during the lifetime of the LRU
+    int identifier;
 
 
     float average_frame_utilization;
     float average_frame_utilization;
 
 
@@ -97,7 +124,7 @@ class Lru
 {
 {
 public:
 public:
 
 
-  Lru (int maximum_memory, int maximum_pages);
+  Lru (int maximum_memory, int maximum_pages, int maximum_page_types);
   ~Lru ( );
   ~Lru ( );
 
 
   bool register_lru_page_type (int index, LruPageTypeFunction page_in_function, LruPageTypeFunction page_out_function);
   bool register_lru_page_type (int index, LruPageTypeFunction page_in_function, LruPageTypeFunction page_out_function);
@@ -130,6 +157,8 @@ public:
 
 
   void count_priority_level_pages (void);
   void count_priority_level_pages (void);
 
 
+  void calculate_lru_statistics (void);
+
 private:
 private:
   bool page_out_lru (int memory_required);
   bool page_out_lru (int memory_required);
   void update_page_priorities (void);
   void update_page_priorities (void);
@@ -148,6 +177,7 @@ public:
 
 
     int maximum_memory;
     int maximum_memory;
     int minimum_memory;    // target amount of memory to keep free if possible
     int minimum_memory;    // target amount of memory to keep free if possible
+    int maximum_page_types;
 
 
     int total_lifetime_page_ins;
     int total_lifetime_page_ins;
     int total_lifetime_page_outs;
     int total_lifetime_page_outs;
@@ -164,12 +194,11 @@ public:
     int maximum_page_updates_per_frame;    // unused pages
     int maximum_page_updates_per_frame;    // unused pages
 
 
     int start_priority_index;
     int start_priority_index;
-    int update_overflow;
     LruPage *start_update_lru_page;
     LruPage *start_update_lru_page;
 
 
-    int identifier;
+    int identifier;  // this is also the number of pages created during the lifetime of the LRU
 
 
-    float weight;
+    float weight;  // used for exponential moving average
     float maximum_frame_bandwidth_utilization;
     float maximum_frame_bandwidth_utilization;
 
 
     float frame_bandwidth_factor;
     float frame_bandwidth_factor;
@@ -189,6 +218,8 @@ public:
     int total_lru_pages_in_free_pool;
     int total_lru_pages_in_free_pool;
     LruPage **lru_page_pool;
     LruPage **lru_page_pool;
     LruPage **lru_page_free_pool;
     LruPage **lru_page_free_pool;
+
+    PageTypeStatistics *page_type_statistics_array;
   }
   }
   LruVariables;
   LruVariables;
 
 
@@ -204,5 +235,4 @@ bool default_page_out_function (LruPage *lru_page);
 void test_ema (void);
 void test_ema (void);
 void test_lru (void);
 void test_lru (void);
 
 
-
 #endif
 #endif