473,394 Members | 1,734 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

STL based LRU cache, any suggestions for improvements?

Hi Guys, I've written a templated lru cache based on the SGI version
of STL. To use the class, simply write:
lru_cache<key_type, data_type, cache_length, custom_containercache;
cache.insert( key, value );
cache[key2] = value2;

data_type* pvalue3 = cache.get(key3);
if ( pvalue3 == NULL )
{} // cache missing
else
{} // cache hit

data_type must be a class supporting the function dispose(), this is
because for smart pointers, the cache calls this function on the least
recently used data when it's full. for example:

struct myDataType
{
int value;
myDataType( int v = 0 ) : value(v) {}
void dispose() {} // empty functions will be ignored by most
compilers
};
struct mySmartPointerType
{
int* parray;
mySmartPointerType( int* a = 0 ) : parray(a) {}
void dispose() { delete[] parray; }
}

It is important that delete[] parray does not occur in the destructor,
otherwise this type cannot be copied.

my problem: I feel this cache is rather slow. Is there any suggestions
to improve its performance?
I've written a test program:

struct point2d
{
short x;
short y;
point2d( short _x, short _y ) : x(_x), y(_y){}
bool operator ==( const point2d & rhs ) const
{
return (x == rhs.x) && (y == rhs.y);
}
bool operator != ( const point2d& rhs ) const
{
return ( x!=rhs.x ) || ( y!=rhs.y );
}
bool operator < (const point2d & rhs ) const
{
return ( x < rhs.x ) || ( x==rhs.x && y < rhs.y ) ;
}
};

struct basetile
{
short id;
char z;
basetile( int _id = 0, int _z = 0 ) : id(_id), z(_z) {}

bool operator == ( const basetile& rhs ) const
{
return id == rhs.id && z == rhs.z;
}
bool operator != ( const basetile& rhs ) const
{
return id != rhs.id || z != rhs.z;
}
void dispose() {}
} __attribute__((packed)) ;

void cacheTest_perf()
{
lru_cache<point2d, basetilecache;
int count=0;

srand( 3456789 );
for ( int i = 0; i < 100000; ++i )
{
point2d p(rand()%200, rand()%200);
basetile& t = cache[p];

if ( t.id != 0 )
{
count++;
}
else
{
t.id = i % 1024 + 1;
t.z = 10;
}
}

cout << "total hit " << count << " out of 100000 requests" <<
endl;
}

the test program uses a point2d structure as index, and a 3 byte
packed structure as data type. the result is:

$ time ./testapp
total hit 23574 out of 100000 requests

real 0m0.066s
user 0m0.055s
sys 0m0.002s

i'm pretty sure that's a bad performance for a cache. soo...any
suggestions to speed up the process is welcome!
the source code is included below:

#ifndef LRUCACHE_H_INCLUDED
#define LRUCACHE_H_INCLUDED

#include <iostream>
#include <list>
// #include <map>

#ifdef __GNUC__
#include <ext/hash_map>
using namespace __gnu_cxx;
#else
#include <hash_map>
#endif
using namespace std;

template<class T>
struct GenericHashAdapter
{
size_t operator()(const T& x) const
{
unsigned char* p = (unsigned char*)(&x);
unsigned int h = 0;
for ( unsigned int i = 0; i < sizeof(T); ++i )
{
h += p[i];
h += h << 10;
h ^= h >6;
}
h += ( h << 3 );
h ^= ( h >11 );
h += ( h << 15 );
return(h);
}
};

template<class T>
struct GenericEqualAdapter
{
size_t operator() (const T&a, const T&b) const
{
return a == b;
}
};

/*
* lru cache
* TElm must support the "dispose()" call
* the cache will call dispose() on the least recently used element
* when the cache is full
*/
template <class TKey,
class TElm,
int Capacity = 10000,
// - to use RB Tree instead of hash table: uncomment next
line and comment out the following line.
// class Container = map<TKey, pair<TElm, typename
list<TKey>::iterator
// - hashtable container:
class Container = hash_map<TKey, pair<TElm, typename
list<TKey>::iterator>, GenericHashAdapter<TKey>,
GenericEqualAdapter<TKey
>
class lru_cache
{
typedef TKey key_type;
typedef TElm data_type;
typedef TElm& reference;
typedef TElm* pointer;

public:
typedef list<TKey> key_list;
typedef typename key_list::iterator key_iterator;
typedef typename Container::iterator item_iterator;
typedef pair<TElm, key_iteratormapped_type;
typedef pair<TKey, mapped_typevalue_type;

lru_cache() : _list(), _map()
{
}
virtual ~lru_cache()
{
}

item_iterator find( const key_type& key )
{
return _map.find(key);
}

reference insert( const key_type& key, const data_type& data )
{
// 1. push key to list
_list.push_front(key);
// 2. insert element to map
pair<item_iterator, boolret = _map.insert(
value_type(key, mapped_type(data, _list.begin()))
);
if ( !ret.second )
{
// key already exist
// remove the old key from the list
// old key is at ret.first->second.second
_list.erase( ret.first->second.second );
// also need to update the key iterator reference in the
note
ret.first->second.second = _list.begin();
}
else
{
// insert successful
// is map full?
if ( _map.size() >= Capacity )
{
// get the least recently used key
item_iterator itr = _map.find(_list.back());
// dispose data
itr->second.first.dispose();
// erase from table
_map.erase( itr );
// remove last key from list
_list.pop_back();
}
}
return ret.first->second.first;
}
void update_key( item_iterator& itr )
{
_list.erase( itr->second.second );
_list.push_front( itr->first );
itr->second.second = _list.begin();
}

pointer get( const key_type& key )
{
item_iterator itr = _map.find(key);
if ( itr != _map.end() )
{
update_key( itr );
return &(itr->second.first);
}
else
return NULL;
}
pointer look( const key_type& key )
{
item_iterator itr = _map.find(key);
if ( itr != _map.end() )
{
return &(itr->second.first);
}
else
return NULL;
}

reference operator[](const key_type& key )
{
// algorithm:
// try insert the key
// if it already exist, then the correct element will be returned
// otherwise, a new note with default element will be created
and returned
return insert( key, data_type() );
}

pointer operator()(const key_type&key)
{
return get(key);
}

key_iterator beginkey()
{
return _list.begin();
}
key_iterator endkey()
{
return _list.end();
}

private:
key_list _list;
Container _map;
};

#endif
Regards,

PQ

May 1 '07 #1
0 6235

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
by: Philip Mette | last post by:
I am begginner at best so I hope someone that is better can help. I have a stored procedure that updates a view that I wrote using 2 cursors.(Kind of a Inner Loop) I wrote it this way Because I...
1
by: Jiho Han | last post by:
I am thinking of embedding my schemas as embedded resources instead of reading it using URI at run-time. I came across some snags while trying to do just that such as, previously unknown to me,...
4
by: Guadala Harry | last post by:
I want to create a STATIC method that removes all items from the Cache. Questions: 1. Is a safe thing to do (any threading issues?) 2. Is the following code a good way to get the job done -...
3
by: Mike Logan | last post by:
Questions about Role Based Security in ASP.Net: I have a few questions about role based security in an ASP.Net application. Below are some points about our system: - We have a hierarchical...
1
by: WebMatrix | last post by:
Hello! I am working on a web application with Windows Authentication. In WindowsAuthentication_Authenticate event of Global.asax file a user is Authenticated and User/Roles Array is loaded into...
12
by: Mats Lycken | last post by:
Hi, I'm creating a CMS that I would like to be plug-in based with different plugins handling different kinds of content. What I really want is to be able to load/unload plugins on the fly without...
45
by: Gregory Petrosyan | last post by:
1) From 2.4.2 documentation: There are two new valid (semantic) forms for the raise statement: raise Class, instance raise instance 2) In python: >>> raise NameError Traceback (most recent...
1
by: JohnC | last post by:
I'm in the concept stage of putting together a web application. Certain featues will be available only if the person has been given access. This is based on their particular subscription. I can...
7
by: Mark B | last post by:
How do I have a SiteMap based on the output of a stored procedure? (I want to pass a @LanguageCode parameter to it so it will display the top Menu in the appropriate language).
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.