212 lines
6.4 KiB
C++
212 lines
6.4 KiB
C++
// Filename: adaptiveLru.h
|
|
// Created by: drose (03Sep08)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef ADAPTIVELRU_H
|
|
#define ADAPTIVELRU_H
|
|
|
|
#include "pandabase.h"
|
|
#include "linkedListNode.h"
|
|
#include "namable.h"
|
|
#include "lightMutex.h"
|
|
#include "lightMutexHolder.h"
|
|
|
|
class AdaptiveLruPage;
|
|
|
|
// See the comment in the head of AdaptiveLruPage, below, for an
|
|
// explanation of these two silly little classes.
|
|
class EXPCL_PANDA_GOBJ AdaptiveLruPageDynamicList : public LinkedListNode {
|
|
public:
|
|
friend class AdaptiveLru;
|
|
};
|
|
|
|
class EXPCL_PANDA_GOBJ AdaptiveLruPageStaticList : public LinkedListNode {
|
|
public:
|
|
friend class AdaptiveLru;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Class : AdaptiveLru
|
|
// Description : A basic LRU-type algorithm, except that it is
|
|
// adaptive and attempts to avoid evicting pages that
|
|
// have been used more frequently (even if less
|
|
// recently) than other pages.
|
|
//
|
|
// The interface is designed to be identical to that for
|
|
// SimpleLru, so that it may be used as a drop-in
|
|
// replacement.
|
|
////////////////////////////////////////////////////////////////////
|
|
class EXPCL_PANDA_GOBJ AdaptiveLru : public Namable {
|
|
PUBLISHED:
|
|
AdaptiveLru(const string &name, size_t max_size);
|
|
~AdaptiveLru();
|
|
|
|
INLINE size_t get_total_size() const;
|
|
INLINE size_t get_max_size() const;
|
|
INLINE void set_max_size(size_t max_size);
|
|
size_t count_active_size() const;
|
|
|
|
INLINE void consider_evict();
|
|
INLINE void evict_to(size_t target_size);
|
|
void begin_epoch();
|
|
|
|
INLINE bool validate();
|
|
|
|
void output(ostream &out) const;
|
|
void write(ostream &out, int indent_level) const;
|
|
|
|
// The following methods are specific to AdaptiveLru, and do not
|
|
// exist in the SimpleLru implementation. In most cases, the
|
|
// defaults will be sufficient, so you do not need to mess with
|
|
// them.
|
|
INLINE void set_weight(float weight);
|
|
INLINE float get_weight() const;
|
|
|
|
INLINE void set_max_updates_per_frame(int max_updates_per_frame);
|
|
INLINE int get_max_updates_per_frame() const;
|
|
|
|
private:
|
|
public: // temp hack
|
|
enum LruPagePriority {
|
|
LPP_Highest = 0,
|
|
LPP_High = 10,
|
|
LPP_New = 20,
|
|
LPP_Normal = 25,
|
|
LPP_Intermediate = 30,
|
|
LPP_Low = 40,
|
|
LPP_TotalPriorities = 50,
|
|
};
|
|
|
|
INLINE float calculate_exponential_moving_average(float value, float average) const;
|
|
|
|
void do_partial_lru_update(int num_updates);
|
|
void update_page(AdaptiveLruPage *page);
|
|
|
|
void do_add_page(AdaptiveLruPage *page);
|
|
void do_remove_page(AdaptiveLruPage *page);
|
|
void do_access_page(AdaptiveLruPage *page);
|
|
|
|
void do_evict_to(size_t target_size, bool hard_evict);
|
|
bool do_validate();
|
|
|
|
LightMutex _lock;
|
|
|
|
size_t _total_size;
|
|
size_t _max_size;
|
|
|
|
unsigned int _current_frame_identifier;
|
|
double _weight;
|
|
int _max_updates_per_frame;
|
|
|
|
// This array of linked lists keeps all of the active pages, grouped
|
|
// by priority. We reshuffle pages among these lists as they are
|
|
// accessed and as they change priority in update_page().
|
|
AdaptiveLruPageDynamicList _page_array[LPP_TotalPriorities];
|
|
|
|
// This linked list keeps all of the active pages, in arbitrary
|
|
// order. This list exists solely to allow us to incrementally
|
|
// update pages without having to iterate through the complex lists
|
|
// above and worry about losing our place. New pages are added to
|
|
// the tail. We also move pages from the head to the tail of this
|
|
// list in do_partial_lru_update() as we process each page with
|
|
// update_page(). Pages do not move within this list other that
|
|
// that.
|
|
AdaptiveLruPageStaticList _static_list;
|
|
|
|
friend class AdaptiveLruPage;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Class : AdaptiveLruPage
|
|
// Description : One atomic piece that may be managed by a AdaptiveLru
|
|
// chain. To use this class, inherit from it and
|
|
// override evict_lru().
|
|
//
|
|
// This class multiply inherits from two classes which
|
|
// in turn both inherit from LinkedListNode. This is
|
|
// just a sneaky C++ trick to allow this class to
|
|
// inherit from LinkedListNode twice, so that pages can
|
|
// be stored on two different linked lists
|
|
// simultaneously. The AdaptiveLru class depends on
|
|
// this; it maintains its pages in two different lists,
|
|
// one grouped by priority, and one in order by next
|
|
// partial update needs.
|
|
////////////////////////////////////////////////////////////////////
|
|
class EXPCL_PANDA_GOBJ AdaptiveLruPage : public AdaptiveLruPageDynamicList, public AdaptiveLruPageStaticList {
|
|
PUBLISHED:
|
|
AdaptiveLruPage(size_t lru_size);
|
|
AdaptiveLruPage(const AdaptiveLruPage ©);
|
|
void operator = (const AdaptiveLruPage ©);
|
|
|
|
virtual ~AdaptiveLruPage();
|
|
|
|
INLINE AdaptiveLru *get_lru() const;
|
|
|
|
void enqueue_lru(AdaptiveLru *lru);
|
|
INLINE void dequeue_lru();
|
|
|
|
INLINE void mark_used_lru() const;
|
|
INLINE void mark_used_lru(AdaptiveLru *lru);
|
|
|
|
INLINE size_t get_lru_size() const;
|
|
INLINE void set_lru_size(size_t lru_size);
|
|
|
|
virtual void evict_lru();
|
|
|
|
virtual void output(ostream &out) const;
|
|
virtual void write(ostream &out, int indent_level) const;
|
|
|
|
// Not defined in SimpleLruPage.
|
|
unsigned int get_num_frames() const;
|
|
unsigned int get_num_inactive_frames() const;
|
|
|
|
private:
|
|
AdaptiveLru *_lru;
|
|
|
|
size_t _lru_size;
|
|
int _priority;
|
|
|
|
unsigned int _first_frame_identifier; // Frame first added.
|
|
unsigned int _current_frame_identifier; // Frame last accessed.
|
|
unsigned int _update_frame_identifier; // Frame last updated.
|
|
|
|
int _current_frame_usage;
|
|
int _last_frame_usage;
|
|
int _total_usage;
|
|
int _update_total_usage;
|
|
|
|
float _average_frame_utilization;
|
|
|
|
friend class AdaptiveLru;
|
|
};
|
|
|
|
inline ostream &operator << (ostream &out, const AdaptiveLru &lru) {
|
|
lru.output(out);
|
|
return out;
|
|
}
|
|
|
|
inline ostream &operator << (ostream &out, const AdaptiveLruPage &page) {
|
|
page.output(out);
|
|
return out;
|
|
}
|
|
|
|
#if 0
|
|
BEGIN_PUBLISH
|
|
void test_adaptive_lru();
|
|
END_PUBLISH
|
|
#endif
|
|
|
|
#include "adaptiveLru.I"
|
|
|
|
#endif
|