473,786 Members | 2,344 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

std::map efficiency

Hi,

I have a routine where I'm using a std::map from a pair of ints to double
for caching evaluation results.
The cache depth could be upto say 1000 in depth.
However, my application needs to clear and replenish the cache repeatedly
and profiling seems to suggests
the performance is handicated by repeated calls to new.
Can anybody advice me on how to improve the performance or suggests
alternatives please.

Thanks in advance.


Jul 22 '05 #1
8 3890
In article <bv**********@h ercules.btinter net.com>,
"Kin Pang" <Ki******@canta b.net> wrote:
Hi,

I have a routine where I'm using a std::map from a pair of ints to double
for caching evaluation results.
The cache depth could be upto say 1000 in depth.
However, my application needs to clear and replenish the cache repeatedly
and profiling seems to suggests
the performance is handicated by repeated calls to new.
Can anybody advice me on how to improve the performance or suggests
alternatives please.


Sounds like an ideal application for a "pooling allocator". Create an
allocator that only expects 1 object to be allocated at a time, but
grabs a handful of them from the system (say 1000), and hands them out
as they are needed. You can then specify that allocator in your map,
and it will use it.

Issues you will have to answer:

1. Should the allocator serve only one map, or many?

2. If serving many, are you operating in a multi-threaded environment?

If you don't want to write your own pool allocator, you might check out
Steve Cleary's pool at boost (www.boost.org).

-Howard
Jul 22 '05 #2
"Kin Pang" <Ki******@canta b.net> wrote in message
news:bv******** **@hercules.bti nternet.com...
Hi,

I have a routine where I'm using a std::map from a pair of ints to double
for caching evaluation results.
The cache depth could be upto say 1000 in depth.
However, my application needs to clear and replenish the cache repeatedly
and profiling seems to suggests
the performance is handicated by repeated calls to new.
Can anybody advice me on how to improve the performance or suggests
alternatives please.

Thanks in advance.

You should probably be looking for a hash table. Binary trees have to be
rebalanced a lot as you are constructing them and that can be expensive.

--
Cy
http://home.rochester.rr.com/cyhome/
Jul 22 '05 #3
"Kin Pang" <Ki******@canta b.net> wrote:
I have a routine where I'm using a std::map from a pair of ints to double
for caching evaluation results.
The cache depth could be upto say 1000 in depth.
However, my application needs to clear and replenish the cache repeatedly
and profiling seems to suggests
the performance is handicated by repeated calls to new.
Can anybody advice me on how to improve the performance or suggests
alternatives please.


Use a vector< pair< int, int > >. Create a function like:

bool compare(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.first < rhs.first;
}

Check out
<http://ecell.sourcefor ge.net/doc/refman/html/AssocVector_8h-source.html>
For a class that implements the map interface using a vector as I
describe above. Use it, instead of std::map, in your program and see if
performance improves.
Jul 22 '05 #4
"Daniel T." <po********@eat hlink.net> wrote in message news:postmaster-
"Kin Pang" <Ki******@canta b.net> wrote:
I have a routine where I'm using a std::map from a pair of ints to double for caching evaluation results.
Use a vector< pair< int, int > >. Create a function like:


Do you mean vector<pair<pai r<int,int>,doub le>? That's usually faster than
map for lookup, so it's a good choice when you want to construct a sorted
array once, then use over and over again for lookup and lower bound. In
this case try to insert all the elements in any order at once and call sort.
But inserting one element into the array is expensive because you have to
keep the array in sorted order, and takes O(N). But who knows, it still
might give better performance for this problem.

--
+++++++++++
Siemel Naran
Jul 22 '05 #5
"Siemel Naran" <Si*********@RE MOVE.att.net> wrote:
"Daniel T." <po********@eat hlink.net> wrote in message news:postmaster-
"Kin Pang" <Ki******@canta b.net> wrote:
I have a routine where I'm using a std::map from a pair of ints to double for caching evaluation results.
Use a vector< pair< int, int > >. Create a function like:


Do you mean vector<pair<pai r<int,int>,doub le>?


I thought the OP was using map< int, int >, what would the double be for?

That's usually faster than
map for lookup, so it's a good choice when you want to construct a sorted
array once, then use over and over again for lookup and lower bound. In
this case try to insert all the elements in any order at once and call sort.
But inserting one element into the array is expensive because you have to
keep the array in sorted order, and takes O(N). But who knows, it still
might give better performance for this problem.


He said that profiling suggested that the slow down was in memory
allocations because the map was constantly being made larger then
smaller. Using the sorted vector would help that particular problem.
With a class that implements the map interface with a sorted vector and
can lazy sort the vector, the OP can easily switch between the two and
see which is better for any particular problem.
Jul 22 '05 #6
"Kin Pang" <Ki******@canta b.net> wrote in message
news:bv******** **@hercules.bti nternet.com...
| I have a routine where I'm using a std::map from a pair of ints to double
| for caching evaluation results.
| The cache depth could be upto say 1000 in depth.
| However, my application needs to clear and replenish the cache repeatedly
| and profiling seems to suggests
| the performance is handicated by repeated calls to new.
| Can anybody advice me on how to improve the performance or suggests
| alternatives please.

As others suggested, some type of hash table is likely to provide
the best results.

Here's a basic example:

double expensiveComput e(int a, int b); // the expensive function

class CachedCompute
{
struct Entry {
Entry(int a_, int b_)
: a(a_), b(b_), result(::expens iveCompute(a_,b _)) {}
int a, b;
double result;
};
enum { kCacheSize = 1024 };
std::vector<Ent ry> cache_;

static int getHashedIndex( int a, int b)
{ // A LOT OF ROOM FOR IMPROVEMENT HERE
return (17*a + 0x193*b) % kCacheSize;
}

public:
CachedCompute()
: cache_( kCacheSize, Entry(0,0) ) // init cache with dummy contents
{ }

double compute(int a, int b)
{
Entry& entry = cache_[ getHashedIndex( a,b) ];
if( entry.a!=a || entry.b!=b )
entry = Entry(a,b); //overwrite the non-matching entry
return entry.result;
}
};

Create an instance of CachedCompute and use its compute()
member function instead of the global expensiveComput e()
to benefit from the caching.

The getHashedIndex( ) function should be optimized to avoid
collisions (different values of a&b used repeatedly that
lead to the same index).
An application-specific optimization is sometimes possible.
Alternatively, consider a proven hashing approach such as the
FNV hash: http://www.isthe.com/chongo/tech/comp/fnv/index.html

The table size (kCacheSize) can also be improved (the std::vector
is anyway more memory-efficient than std::map, the saving is
probably about 50%).

Another improvement might be to look at multiple hash table
entries when calling compute (e.g. the 4 following ones).
There are various ways to handle table refreshes in this case...
Anyway, I would expect the snippet above to provide much better
performance than an approach based on std::map ...
But please let me know of your results.

I hope this helps,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form
Jul 22 '05 #7
Hi,

This is a distilled version of what I'm trying to do (code snipet guaranteed
to compile). I have a Fn which has an operator that I want to cache.
Fn is used as basis for a functional algebra for more complex function
expressions.
The benchmark for the caching performance is EvalCache defined below.
I'm comparing performance of EvalCacheWithVe c with EvalCache using ideas
suggested kindly by Ivan Vecerina.
For my application, I'm finding that EvalCache outperforms EvalCacheWithVe c
by a factor of close to two.
In fact EvalCacheWithVe c runs quicker with smaller cache sizes.
I don't really want to move the cache outside of the class Fn.
Any suggestions on how I can improve the performance of EvalCacheWithVe c
further?
Thanks in advance.

class Fn
{
private:
typedef EvalCache<int,i nt,double> CACHE;
// typedef EvalCacheWithVe c<int,int,doubl e> CACHE;
SharedPtr<CACHE > _fnCache;

SharedPtr<blah> _rep;
public:
double operator()( int date_, int evalDate_ ) const
{
//! check to see whether cached value is valid and use if so.
std::pair<int,i nt> args=std::make_ pair(date_, evalDate_);
const double* cached=_fnCache->lookup(args) ;
if (cached==0)//! ie invalid
{
double res=(*_rep)(dat e_, evalDate_);
_fnCache->add(args, res);
return res;
}
else
{
return *cached;
}
}
};

template< typename T1, typename T2, typename R >
class EvalCache
{
private:
typedef std::pair<T1,T2 > FNARGS;
FNARGS _args;
R _cached;
bool _valid;

public:
~EvalCache(){}
EvalCache():_va lid(false){}

//! return value of 0 indicates that the cached value cannot be used.
inline const R* lookup(const FNARGS& args_)
{
if (_valid==false) return 0;
if (_args==args_) return &_cached;
else return 0;
}

inline void add(const FNARGS& args_, const R& res_)
{
_args = args_;
_cached= res_;
_valid = true;
}

inline void clear(){ _valid=false; }
};

template<typena me T1, typename T2, typename R>
class EvalCacheWithVe c{
private:
typedef std::pair<T1,T2 > FNARGS;
typedef std::pair<FNARG S,R> ENTRY;
std::vector<ENT RY> _cached;
R _cachedVal;

enum{kCacheSize =64};
std::bitset<kCa cheSize> _valid;
bool _noneValid;

size_t getHashedIndex( T1 a, T2 b)
{ // A LOT OF ROOM FOR IMPROVEMENT HERE
return (17*a + 0x193*b) % kCacheSize;
}

public:
~EvalCacheWithV ec(){}
EvalCacheWithVe c()
:
_cached(kCacheS ize),
_valid(),
_noneValid(true )
{}

//! return value of 0 indicates that the cached value cannot be used.
const R* lookup(const FNARGS& args_)
{
if (_noneValid==tr ue) return 0;

T1 arg1(args_.firs t);
T2 arg2(args_.seco nd);
size_t idx = getHashedIndex( arg1, arg2);
if (_valid[idx]==false) return 0;

const ENTRY& entry = _cached[idx];
if (entry.first!=a rgs_) return 0;

_cachedVal=entr y.second;
return &_cachedVal;
}

void add(const FNARGS& args_, const R& res_)
{
T1 arg1(args_.firs t);
T2 arg2(args_.seco nd);
size_t idx = getHashedIndex( arg1, arg2);
_cached[idx]=std::make_pair (args_,res_);
_valid[idx]=true;
_noneValid=fals e;
}

void clear()
{
_noneValid=true ;
_valid.reset();
}

};

"Ivan Vecerina" <se*********@ve cerina.com> wrote in message
news:c0******** **@newshispeed. ch...
"Kin Pang" <Ki******@canta b.net> wrote in message
news:bv******** **@hercules.bti nternet.com...
| I have a routine where I'm using a std::map from a pair of ints to double | for caching evaluation results.
| The cache depth could be upto say 1000 in depth.
| However, my application needs to clear and replenish the cache repeatedly | and profiling seems to suggests
| the performance is handicated by repeated calls to new.
| Can anybody advice me on how to improve the performance or suggests
| alternatives please.

As others suggested, some type of hash table is likely to provide
the best results.

Here's a basic example:

double expensiveComput e(int a, int b); // the expensive function

class CachedCompute
{
struct Entry {
Entry(int a_, int b_)
: a(a_), b(b_), result(::expens iveCompute(a_,b _)) {}
int a, b;
double result;
};
enum { kCacheSize = 1024 };
std::vector<Ent ry> cache_;

static int getHashedIndex( int a, int b)
{ // A LOT OF ROOM FOR IMPROVEMENT HERE
return (17*a + 0x193*b) % kCacheSize;
}

public:
CachedCompute()
: cache_( kCacheSize, Entry(0,0) ) // init cache with dummy contents
{ }

double compute(int a, int b)
{
Entry& entry = cache_[ getHashedIndex( a,b) ];
if( entry.a!=a || entry.b!=b )
entry = Entry(a,b); //overwrite the non-matching entry
return entry.result;
}
};

Create an instance of CachedCompute and use its compute()
member function instead of the global expensiveComput e()
to benefit from the caching.

The getHashedIndex( ) function should be optimized to avoid
collisions (different values of a&b used repeatedly that
lead to the same index).
An application-specific optimization is sometimes possible.
Alternatively, consider a proven hashing approach such as the
FNV hash: http://www.isthe.com/chongo/tech/comp/fnv/index.html

The table size (kCacheSize) can also be improved (the std::vector
is anyway more memory-efficient than std::map, the saving is
probably about 50%).

Another improvement might be to look at multiple hash table
entries when calling compute (e.g. the 4 following ones).
There are various ways to handle table refreshes in this case...
Anyway, I would expect the snippet above to provide much better
performance than an approach based on std::map ...
But please let me know of your results.

I hope this helps,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form

Jul 22 '05 #8
"Kin Pang" <Ki******@canta b.net> wrote in message
news:c0******** **@titan.btinte rnet.com...
Hi Kin,
This is a distilled version of what I'm trying to do (code snipet guaranteed to compile).
Actually it won't compile since Fn needs to be defined after EvalCache.
It would also be nice to have a complete program with #include directives
and a main() function - if you would like anyone to actually benchmark it.
Please also keep in mind that the solution that provides optimal
execution speed will depend on both the sequence of call inputs,
and on the computation function that is being cached.
I have a Fn which has an operator that I want to cache.
Fn is used as basis for a functional algebra for more complex function
expressions.
The benchmark for the caching performance is EvalCache defined below.
I'm comparing performance of EvalCacheWithVe c with EvalCache using ideas
suggested kindly by Ivan Vecerina.
For my application, I'm finding that EvalCache outperforms EvalCacheWithVe c by a factor of close to two.
EvalCache only caches the single last result that has been computed,
and therefore does less work than EvalCacheWithVe c.
This hints at the following problems:
- the function being cached executes quickly, and there is
no benefit in caching.
- the calling code is repeating the evaluation of the same input
parameters several times, then moving on to the next.
- your input sequence creates many collisions with the
current hasing function.
In fact EvalCacheWithVe c runs quicker with smaller cache sizes.
This could be a sign that memory access (cache misses) are
limiting performance. It hints again at a cached function
that is executing quickly, and might not need to be cached
(unless input values strongly conflict with the hash function).

Could you provide a more complete code example, and performance
metrics (including a comparison with no use of caching) ?
I don't really want to move the cache outside of the class Fn.
Any suggestions on how I can improve the performance
of EvalCacheWithVe c further?

Compared to the code I had posted, two redundancies have
been added in EvalCacheWithVe c:
- A flag is being kept (in std::bitset) to indicate wheter
a cache entry is valid or not. Under intensive cache use,
this will slow things down compared to the original approach:
filling the whole cache with a valid input-output entry.
- When a cache entry is updated, the hashed cache index
is being computed twice.

Further performance tuning is very dependent on what you
application specifically does.

Warm regards,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- e-mail contact form

Jul 22 '05 #9

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

Similar topics

3
30085
by: Woodster | last post by:
I have declared the following std::map<std::string, std::string> myMap; to pass myMap to functions should I be declaring functions as: void function(std::map<std::string, std::string>); or is there a preferred/better method of doing this?
14
4063
by: Flzw | last post by:
Well I have a map like this : std::map <string, CObject> ObjectList; I have a function like this : CObject* NewObject( char* Name, CArg* Arg) { std::string key = Name; ObjectList = CObject( Name, Arg);
1
3554
by: Saeed Amrollahi | last post by:
Dear All C++ Programmers Hello I am Saeed Amrollahi. I am a software engineer in Tehran Sewerage Company. I try to use std::map and map::find member function. I use Visual Studio .NET. my program uses two MFC classes: CRect and CPoint which represents Rectangle and Point concepts (as usual) and a user
19
6165
by: Erik Wikström | last post by:
First of all, forgive me if this is the wrong place to ask this question, if it's a stupid question (it's my second week with C++), or if this is answered some place else (I've searched but not found anything). Here's the problem, I have two sets of files, the name of a file contains a number which is unique for each set but it's possible (even probable) that two files in different sets have the same numbers. I want to store these...
3
3716
by: Dan Trowbridge | last post by:
Hi everyone, In my attempt to port code from VS 6.0 to VS.NET I had some code break along the way, mostly due to not adhereing closely to the C++ standard. This may be another instance but I can't think of a good fix, or even why it broke. The problem In one of my CFormView derived classes I have a member variable of the type...
1
6479
by: Avery Fong | last post by:
The following program will result in a compile error when building under Debug but will compile under Release. Why does is work under Release mode but not under Debug This program is developed under Visual Studio .NET 2003 in a Win32 Console Project // VectorInsert.cpp : Defines the entry point for the console application / #include "stdafx.h #include "VectorInsert.h #ifdef _DEBU
13
9678
by: kamaraj80 | last post by:
Hi I am using the std:: map as following. typedef struct _SeatRowCols { long nSeatRow; unsigned char ucSeatLetter; }SeatRowCols; typedef struct _NetData
7
5843
by: Matthias Pfeifer | last post by:
Hi there, a std::map is build from std::pair elements where for a pair p p.first is called the key and p.second the value. Is there a way to keep the map sorted by the values? Ie is there a std::key_compare in the stl that offeres this functionality? It's ok if this would make finding a key more expensive. Writing my own would be possible, but why do it if it's already there... matthias
8
4077
by: mveygman | last post by:
Hi, I am writing code that is using std::map and having a bit of an issue with its performance. It appears that the std::map is significantly slower searching for an element then a sequential search in a vector. Has anyone run into this before?
0
9491
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10357
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10163
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8988
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7510
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6744
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5397
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5532
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3668
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.