surprising template size and speed

C

charles.lobo

Ian said:
For that to be true, the exception condition would have to occur once
every 1000 calls or less. In which case, is it truly an exception
condition?


And if it can't? It passes another error condition back to its caller.
May as well let the run time take care of this, which is what
exceptions do.

You have to differentiate between errors and exception conditions. If
there is a reasonable probability an operation will fail, return an
error. If not, throw and exception.
I think I agree with you. Ideally the way to go would be a to use
errors generally and exceptions for truly exceptional conditions.
What would then qualify as an exceptional condition? I can think of
running out of memory as one, but can't really think of any other.
"File not found" and "Null pointer" exceptions which are common in java
are definitly not exceptional conditions - file not found is common and
"null pointer" should be handled as an error.
 
A

Andre Kostur

(e-mail address removed) wrote in 16g2000cwy.googlegroups.com:
Berkely DB has a C++ version. I just re-checked and the do provide
support (optional) for exceptions, though they do not use templates.
The exception support also can be "turned off".
Could you point me (genuinely) to a powerful project that does use
modern C++? I have been looking but haven't been too successful yet.
Adobe uses the boost library somewhere, but adobe is *so* slow to load
it's a bad example for me. So I'm still looking.

The Adaptive Communications Environment (ACE).

http://www.cs.wustl.edu/~schmidt/ACE.html
 
A

ajalkane

Berkely DB has a C++ version. I just re-checked and the do provide
support (optional) for exceptions, though they do not use templates.
The exception support also can be "turned off".
Could you point me (genuinely) to a powerful project that does use
modern C++? I have been looking but haven't been too successful yet.
Adobe uses the boost library somewhere, but adobe is *so* slow to load
it's a bad example for me. So I'm still looking.

If I've understood correctly, Berkeley DB is implemented in C and only
wrappers for C++ are provided.

Another poster recommended ACE. It is an excellent library that I've
used quite a bit, but since it is quite an old library and has to
support a large selection of compilers it is a bit conservative in its
use of modern features so that all platforms are supported.

One library I've often seen mentioned regarding modern C++ usage is
Blitz++. I haven't used it myself but you might want to take a look at
it also:

"Blitz++ is a C++ class library for scientific computing which provides
performance on par with Fortran 77/90. It uses template techniques to
achieve high performance. Blitz++ provides dense arrays and vectors,
random number generators, and small vectors"

http://sourceforge.net/project/showfiles.php?group_id=63961

Maybe also Crypto++ might be interesting for you:

http://www.cryptopp.com/
 
M

Michael DOUBEZ

(e-mail address removed) a écrit :
Victor said:
[..]
What I am trying to do is to check if we can use template-based lists
in our company code. We are currently using lists similar to the
non-template version (with derived classes) and the mandate is that
the template list should have a clear advantage if we've to adopt it.
Then stop screwing around and use 'std::list'. And get a book on the
Standard library, preferrably a copy for every programmer on your team
so that nobody is left out trying to figure it out by themselves. I
recommend "Effective" series by Meyers, *all of them*.

V

Sadly I have no chance of selling the usage of std::list without first
proving that templates are not evil. Plus we do not use exceptions in
our code and the overhead of exception usage is not acceptable to our
company. I did try the std::vector (which was bigger but faster).

In any case I'm still not clear why the timing results are different.
Another intersting point is when I changed your code to use "MyClass"
instead of "double" the template list became slower again!

cheers,
/Charles

Well, you really must use std::vector instead of std::list, "Effective
STL" might help you more:

When you used std::vector, did you reserved the memory beforehand ?
std::vector<MyClass> myVector(100000);
or
myVector.reserve(100000);

Otherwise, there is performances degradation due to reallocation.
This wouldn't happen with std::list.

Michael
 
P

peter koch

(e-mail address removed) skrev:
[snip]
Exception handling does have *significant* peformance overhead.
<quote>Compared to a normal function return, returning from a function
by throwing an exception may be as much as three orders of magnitude
(!) slower</quote>. Even though you may incur this cost rarely
(depending on how you use exceptions), there is still potential code
bloat and a performance hit.

Right. I never argued about the time spent when an exception was
thrown. If timing in that case is interesting and crucial to your
program, I do understand that this is one place to avoid exception
handling.
What I had in mind was performance of the normal execution path. Here,
using exception handling will in the optimal case improve performance,
both in terms of size and speed. Some compilers will have a slight
overhead in some cases (doing some simple housekeeping on entry to some
functions), but that overhead is comparable in size and speed to
norrmal "if-then-else" error-handling.
We use assertions quite generously (which reduces the number of error
returns drastically) and that works very well.
I like using assertions myself, but if you claim that assertions are
related to exception handling it demonstrates that you haven't
understood either one or both of these topics.
We have no
memory/resource leaks (in our codebase of 3500 files - not nearly as
large as yours) and we do check for return codes everywhere.

This is very dandy. I must add that our software runs "forever" on the
systems they are installed on so they do not leak like a pig, But to
claim that your software behaves well irrespective of any path through
your code and irrespective of any possible faliure, begs the question
how you can be so sure. It either requires loads of resources or some
intelligent form of resource-management, that simply can't be achieved
without using generic code and thus templates.
IMHO exceptions aren't that great anyway (also see
http://www.joelonsoftware.com/items/2003/10/13.html) because they don't
mandate who deals with them (i.e. there is no ownership of errors).
There is no ownership of errors using return codes, certainly!
In
the return code world the caller *must* deal with the error conditions.

Why? In order to avoid errors, you mean? Well ;-)
In the exception world, he can ignore it to the peril of functions
higher up in the chain.

Surely, the normal handling of an exception should be to ignore it
(making sure you function is exception safe), letting the function that
knows how to deal with the exception handle it.
Having said that, exceptions could be useful for simple, or business
oriented programs where performance isn't a major factor (like much of
Java code). Or maybe we need to think up a different paradigm for error
handling altogether....
Wauh! You have a lot to learn.

/Peter
 
?

=?iso-8859-1?q?Kirit_S=E6lensminde?=

Kirit said:
peter koch wrote:
(e-mail address removed) skrev:
Victor Bazarov wrote:
(e-mail address removed) wrote:
[..]
What I am trying to do is to check if we can use template-based lists
in our company code. We are currently using lists similar to the
non-template version (with derived classes) and the mandate is that
the template list should have a clear advantage if we've to adopt it.

Then stop screwing around and use 'std::list'. And get a book on the
Standard library, preferrably a copy for every programmer on your team
so that nobody is left out trying to figure it out by themselves. I
recommend "Effective" series by Meyers, *all of them*.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Sadly I have no chance of selling the usage of std::list without first
proving that templates are not evil. Plus we do not use exceptions in
our code and the overhead of exception usage is not acceptable to our
company.

What overhead? Unless you write quite specialised code, the overhead of
exceptionhandling is certainly acceptable. As I assume that your
company does try to do some errorhandling, the overhead of
exception-handling is not just something you pay for. You do also get
something in return - namely no longer needing to continuously check
return codes.
This is not just a programmer convenience. It is also far less code,
far less clutter and faster programs, but most importantly it's
increased reliability since you are no longer as likely to overlook
missing return code checks. I can tell you, as I right now work for a
company with the same exception policy (no exceptions!) as in your
company, and our codebase does have places where errorcodes are not
checked (and potential resource leaks because the style and the age of
the code means that to many raw allocations are made and not always
freed after use). The problem with my company is not only that there is
a distrust in exceptions (probably for the same silly reasons that your
company has) and that our codebase is very large (20000 sourcefiles on
the project I am working on), so I can see some raison in not changing
policy. Unfortunately the same reasoning might very well result in
throwing C++ out the window. No new projects are - to my knowledge -
started in C++ today, and who can really blame that considering the
mess they have brought them self into.

/Peter

Exception handling does have *significant* peformance overhead.
<quote>Compared to a normal function return, returning from a function
by throwing an exception may be as much as three orders of magnitude
(!) slower</quote>. Even though you may incur this cost rarely
(depending on how you use exceptions), there is still potential code
bloat and a performance hit.
We use assertions quite generously (which reduces the number of error
returns drastically) and that works very well. We have no
memory/resource leaks (in our codebase of 3500 files - not nearly as
large as yours) and we do check for return codes everywhere.
IMHO exceptions aren't that great anyway (also see
http://www.joelonsoftware.com/items/2003/10/13.html) because they don't
mandate who deals with them (i.e. there is no ownership of errors). In
the return code world the caller *must* deal with the error conditions.
In the exception world, he can ignore it to the peril of functions
higher up in the chain.
Having said that, exceptions could be useful for simple, or business
oriented programs where performance isn't a major factor (like much of
Java code). Or maybe we need to think up a different paradigm for error
handling altogether....

Joel is right about all sorts of things, but he isn't right about
everything. There are contexts within which exceptions are a pain and
places where their use makes no sense or complicates code. But that
isn't the same as saying that they are never the best way of dealing
with a situations.

His two arguments are easily put in perspective though:

"They are invisible in the source code": For the first take a look at
http://www.kirit.com/Handling COM errors in C++ on my site
which explores this issue in the context of COM error handling. The
sample code that Microsoft used is buggy precisely because they nest if
statements to handle error conditions. Yes the error checking
statements are clearly visible and that is exactly the problem - they
obscure the flow to such an extent that they themselves become a source
of problems.

"They create too many possible exit points": Joel's second point is
true if you are manually handling resources (i.e. you have to manually
free the resources). Then the extra exit points are an important
consideration. If you're using RIAA then this is a non-issue. And if
you're not using RIAA then you're not really using C++ IMHO.


K
[OFF TOPIC]
Nice article btw - I liked the fonts and layout. Just curious - do you
hand code your site it or is use some program?
[/OFF TOPIC]

It uses our web application and O/RM framework FOST.3. It runs the wiki
and bulletin board modules.

It's about 99% C++ (a few ASP pages, but they're being phased out) and
uses Boost and exceptions. There are around 14 occurances of the delete
keyword most of which seem to be for handling the buffers in the TCP/IP
stream implementations. I consider it a fairly good example of good
modern C++, but then I'm very biased :)

To bring this on topic, I don't see how the framework could have been
written to be as reliable as it is without the use of templates and
exceptions. The introspection used to generate the SQL and COM access
points makes very heavy use of templates. Without exceptions the design
of the system would be so convulated it'd be impossible to work with.

As it is it's faster to work in C++ to build new features than it is
using scripting languages.


K
 
C

charles.lobo

If I've understood correctly, Berkeley DB is implemented in C and only
wrappers for C++ are provided.

Another poster recommended ACE. It is an excellent library that I've
used quite a bit, but since it is quite an old library and has to
support a large selection of compilers it is a bit conservative in its
use of modern features so that all platforms are supported.

One library I've often seen mentioned regarding modern C++ usage is
Blitz++. I haven't used it myself but you might want to take a look at
it also:

"Blitz++ is a C++ class library for scientific computing which provides
performance on par with Fortran 77/90. It uses template techniques to
achieve high performance. Blitz++ provides dense arrays and vectors,
random number generators, and small vectors"

http://sourceforge.net/project/showfiles.php?group_id=63961

Maybe also Crypto++ might be interesting for you:

http://www.cryptopp.com/
Neat - thanks!
These are all libraries though, are there any products that use modern
C++? It seems to me (maybe wrongly) that there are very few products
using modern C++ (compared to C and vanilla-C++).
I'm guessing this could be because the latest features don't (didn't?)
have widespread compiler support but I could be wrong.
I just checked firefox and it is using templates (yay) - any other
products out there?
 
C

charles.lobo

Kirit said:
Kirit said:
(e-mail address removed) wrote:

peter koch wrote:
(e-mail address removed) skrev:
Victor Bazarov wrote:
(e-mail address removed) wrote:
[..]
What I am trying to do is to check if we can use template-based lists
in our company code. We are currently using lists similar to the
non-template version (with derived classes) and the mandate is that
the template list should have a clear advantage if we've to adopt it.

Then stop screwing around and use 'std::list'. And get a book on the
Standard library, preferrably a copy for every programmer on your team
so that nobody is left out trying to figure it out by themselves. I
recommend "Effective" series by Meyers, *all of them*.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Sadly I have no chance of selling the usage of std::list without first
proving that templates are not evil. Plus we do not use exceptions in
our code and the overhead of exception usage is not acceptable to our
company.

What overhead? Unless you write quite specialised code, the overhead of
exceptionhandling is certainly acceptable. As I assume that your
company does try to do some errorhandling, the overhead of
exception-handling is not just something you pay for. You do also get
something in return - namely no longer needing to continuously check
return codes.
This is not just a programmer convenience. It is also far less code,
far less clutter and faster programs, but most importantly it's
increased reliability since you are no longer as likely to overlook
missing return code checks. I can tell you, as I right now work for a
company with the same exception policy (no exceptions!) as in your
company, and our codebase does have places where errorcodes are not
checked (and potential resource leaks because the style and the age of
the code means that to many raw allocations are made and not always
freed after use). The problem with my company is not only that there is
a distrust in exceptions (probably for the same silly reasons that your
company has) and that our codebase is very large (20000 sourcefiles on
the project I am working on), so I can see some raison in not changing
policy. Unfortunately the same reasoning might very well result in
throwing C++ out the window. No new projects are - to my knowledge -
started in C++ today, and who can really blame that considering the
mess they have brought them self into.

/Peter

Exception handling does have *significant* peformance overhead.
<quote>Compared to a normal function return, returning from a function
by throwing an exception may be as much as three orders of magnitude
(!) slower</quote>. Even though you may incur this cost rarely
(depending on how you use exceptions), there is still potential code
bloat and a performance hit.
We use assertions quite generously (which reduces the number of error
returns drastically) and that works very well. We have no
memory/resource leaks (in our codebase of 3500 files - not nearly as
large as yours) and we do check for return codes everywhere.
IMHO exceptions aren't that great anyway (also see
http://www.joelonsoftware.com/items/2003/10/13.html) because they don't
mandate who deals with them (i.e. there is no ownership of errors). In
the return code world the caller *must* deal with the error conditions.
In the exception world, he can ignore it to the peril of functions
higher up in the chain.
Having said that, exceptions could be useful for simple, or business
oriented programs where performance isn't a major factor (like much of
Java code). Or maybe we need to think up a different paradigm for error
handling altogether....

Joel is right about all sorts of things, but he isn't right about
everything. There are contexts within which exceptions are a pain and
places where their use makes no sense or complicates code. But that
isn't the same as saying that they are never the best way of dealing
with a situations.

His two arguments are easily put in perspective though:

"They are invisible in the source code": For the first take a look at
http://www.kirit.com/Handling COM errors in C++ on my site
which explores this issue in the context of COM error handling. The
sample code that Microsoft used is buggy precisely because they nest if
statements to handle error conditions. Yes the error checking
statements are clearly visible and that is exactly the problem - they
obscure the flow to such an extent that they themselves become a source
of problems.

"They create too many possible exit points": Joel's second point is
true if you are manually handling resources (i.e. you have to manually
free the resources). Then the extra exit points are an important
consideration. If you're using RIAA then this is a non-issue. And if
you're not using RIAA then you're not really using C++ IMHO.


K
[OFF TOPIC]
Nice article btw - I liked the fonts and layout. Just curious - do you
hand code your site it or is use some program?
[/OFF TOPIC]

It uses our web application and O/RM framework FOST.3. It runs the wiki
and bulletin board modules.

It's about 99% C++ (a few ASP pages, but they're being phased out) and
uses Boost and exceptions. There are around 14 occurances of the delete
keyword most of which seem to be for handling the buffers in the TCP/IP
stream implementations. I consider it a fairly good example of good
modern C++, but then I'm very biased :)

To bring this on topic, I don't see how the framework could have been
written to be as reliable as it is without the use of templates and
exceptions. The introspection used to generate the SQL and COM access
points makes very heavy use of templates. Without exceptions the design
of the system would be so convulated it'd be impossible to work with.

As it is it's faster to work in C++ to build new features than it is
using scripting languages.


K
Cool :)
 
C

charles.lobo

Michael said:
(e-mail address removed) a écrit :
Victor said:
(e-mail address removed) wrote:
[..]
What I am trying to do is to check if we can use template-based lists
in our company code. We are currently using lists similar to the
non-template version (with derived classes) and the mandate is that
the template list should have a clear advantage if we've to adopt it.
Then stop screwing around and use 'std::list'. And get a book on the
Standard library, preferrably a copy for every programmer on your team
so that nobody is left out trying to figure it out by themselves. I
recommend "Effective" series by Meyers, *all of them*.

V

Sadly I have no chance of selling the usage of std::list without first
proving that templates are not evil. Plus we do not use exceptions in
our code and the overhead of exception usage is not acceptable to our
company. I did try the std::vector (which was bigger but faster).

In any case I'm still not clear why the timing results are different.
Another intersting point is when I changed your code to use "MyClass"
instead of "double" the template list became slower again!

cheers,
/Charles

Well, you really must use std::vector instead of std::list, "Effective
STL" might help you more:

When you used std::vector, did you reserved the memory beforehand ?
std::vector<MyClass> myVector(100000);
or
myVector.reserve(100000);

Otherwise, there is performances degradation due to reallocation.
This wouldn't happen with std::list.

Michael
I tried initializing the vector as suggested and it made no difference.
I think it's not doing enough re-allocs to make any perceptible
difference.
I also tried using the std::list - and it became 3 times slower! The
vector seems to be the fastest for my current usage.

cheers,
/Charles
 
P

peter koch

(e-mail address removed) skrev:
[snip]
These are all libraries though, are there any products that use modern
C++? It seems to me (maybe wrongly) that there are very few products
using modern C++ (compared to C and vanilla-C++).
I'm guessing this could be because the latest features don't (didn't?)
have widespread compiler support but I could be wrong.
I just checked firefox and it is using templates (yay) - any other
products out there?
You could visit boost: they have a section "who's using boost). Lots of
companies probably do not show up there. All my projects except for
the current one have used "modern" C++ such as templates and boost
libraries and of course the standard library. I believe that using
these modern techniques is the rule rather than the exception, at least
until you go to libraries that are old and/or supposed to support lots
of possibly old and nonconforming compilers (such as gcc 2.95 or VC
6.0).

/Peter
 
C

charles.lobo

peter said:
(e-mail address removed) skrev:
[snip]
These are all libraries though, are there any products that use modern
C++? It seems to me (maybe wrongly) that there are very few products
using modern C++ (compared to C and vanilla-C++).
I'm guessing this could be because the latest features don't (didn't?)
have widespread compiler support but I could be wrong.
I just checked firefox and it is using templates (yay) - any other
products out there?
You could visit boost: they have a section "who's using boost). Lots of
companies probably do not show up there. All my projects except for
the current one have used "modern" C++ such as templates and boost
libraries and of course the standard library. I believe that using
these modern techniques is the rule rather than the exception, at least
until you go to libraries that are old and/or supposed to support lots
of possibly old and nonconforming compilers (such as gcc 2.95 or VC
6.0).

/Peter
Thanks.

This discussion was really good for me. I learnt a lot!
 
N

Noah Roberts

Exception handling does have *significant* peformance overhead.
<quote>Compared to a normal function return, returning from a function
by throwing an exception may be as much as three orders of magnitude
(!) slower</quote>.

"may be" is the key sequence there. Implementations have vastly
improved since the early 90's.
Even though you may incur this cost rarely
(depending on how you use exceptions), there is still potential code
bloat and a performance hit.

When examining the costs of exceptions you need to compare it to
alternative methods of error handling, not to simple function
returning. There are two viable alternatives:

1) error code returns.
These must be checked and can be ignored leaving the program in an
unkowingly erroneous state.
2) error code globals
lots of problems there.

Either one must have error checking in the form of ifs all over the
place; often times several levels of them because you catch an error,
need to stop, and return that error up the call stack. Exceptions
handle this kind of thing quite well. The question is, are the ifs
that much less of a performance hit?

We use assertions quite generously (which reduces the number of error
returns drastically) and that works very well. We have no
memory/resource leaks (in our codebase of 3500 files - not nearly as
large as yours) and we do check for return codes everywhere.

memory/resource leaks have nothing to do with exceptions. Have you
compared the cleanliness of exceptions vs return codes and have you
compared the performance of exceptions to error code checking
"everywhere"?
IMHO exceptions aren't that great anyway (also see
http://www.joelonsoftware.com/items/2003/10/13.html) because they don't
mandate who deals with them (i.e. there is no ownership of errors).

That is an illogical mandate. The callee can't know who best can
handle the errors it generates. Obviously it returns an error because
for some reason it can't deal with it on its own...why attempt to
enforce a relationship that is possibly not valid?
In
the return code world the caller *must* deal with the error conditions.

Not true...the caller can just ignore them. Exceptions cannot be
ignored.
In the exception world, he can ignore it to the peril of functions
higher up in the chain.

As can error codes except that once ignored there is no way to know
that an error occured. Exceptions will pull up the stack until handled
and cannot be ignored.
Having said that, exceptions could be useful for simple, or business
oriented programs where performance isn't a major factor (like much of
Java code).

That assumes that exceptions cause a performance penalty such that
error handling using them is too much penalty for high performance
systems. There is no indication that you have measured this penalty
and seem to be simply making miles and miles of assumptions based on no
data whatsoever.

There are two things to consider: Do exceptions really cause a penalty
that so outweighs error code handling that one is better than the other
performance wise; this is highly questionable. Second, is your system
such that it needs to be able to deal with erroneous conditions as
quickly as the mainline, which has to be very fast; this is extreemly
rare.

Another thing to consider...do the mainline and error path have equal
performance requirements? If not, could the mainline be made faster by
not having error handling code in it? If so, even if exceptions are
slower maybe they are the better alternative.
 
N

Noah Roberts

Sadly I have no chance of selling the usage of std::list without first
proving that templates are not evil. Plus we do not use exceptions in
our code and the overhead of exception usage is not acceptable to our
company. I did try the std::vector (which was bigger but faster).

Interesting. Sounds very familiar. It's funny how many managers
mandate this kind of crap without even looking into real costs. The
last manager we had mandated the same things. Took forever to convince
him that the STL was faster even with *real measured data*. Thick
heads just don't move I guess.

What was really interesting is that we use visual studio 7, and now 8.
Mandate said we would not use exceptions but we had them enabled
because of course nothing compiles without them (not if you use ANY of
the standard lib except the C part). This meant we where paying all
the costs of using them but getting none of the benefits.

The things people do based on assumptions...

And there you go...if you use the STL you will have to enable
exceptions (if you're even turning them off) and thus will have all the
costs associated with them. Any size increase for tables, any call
overhead for functions...etc...will all be paid if you use the STL.
 
N

Noah Roberts

Sadly I have no chance of selling the usage of std::list without first
proving that templates are not evil. Plus we do not use exceptions in
our code and the overhead of exception usage is not acceptable to our
company. I did try the std::vector (which was bigger but faster).

BTW, who do you work for? I want to make sure I don't ever apply there
:p
 
N

Noah Roberts

Neat - thanks!
These are all libraries though, are there any products that use modern
C++? It seems to me (maybe wrongly) that there are very few products
using modern C++ (compared to C and vanilla-C++).

We used to be in the same position you are in with a manager mandating
all sorts of silly and ill concieved policies such as never use
exceptions and stay away from STL. Eventually we showed him that the
STL was definately not a problem and started using it....never sold
exceptions.

But he is gone now and things have changed. We now use boost and the
STL all over the place. Exceptions will be moving in as soon as some
training takes place (these guys never learned RAII for example). The
more square wheels we replace with STL and boost the cleaner, more
secure, and faster the code gets...and yes, these effects are
measurable.

No, you can't see our code...it's proprietery (I won't even talk about
who we are)...but our product is a complex engineering product that
must have good performance for it to sell. Performance is a big deal
for us and we have no problem using the STL because it is just plain
faster than the alternatives.

I think most of the time these managers are just avoiding STL and
exceptions because they are clueless when it comes to them; this
coincides with my experience. Instead of learning new things that
could make them better they prefer to stay where they are. It is
amazing how strongly they fight change.

That said...you're wasting time. You'll spend hours on this and never
get anywhere with them...or you'll get just far enough to make it
worse. Find a different job where you can work with people who know
more and have more open minds about things...prefering to look at
measurable data rather than base wide sweeping decisions on assumptions.
 
F

frame

This discussion was really good for me. I learnt a lot!

Oh! you posted here too (apart from comp.lang.c++.moderated). I have
posted upon this a while ago at comp.lang.c++.moderated (don't know
whether it would appear or not), but here is an **approximate** copy of
that (look there for my exact posting)!


/*------------ HISTORY of this topic at 'comp.lang.c++.moderated'
-------------------*/
Hi,

I have recently begun using templates in C++ and have found it to be
quite useful. However, hearing stories of code bloat and assorted
problems I decided to write a couple of small programs to check. What I
expected was that there would be minor code bloat and some speed
improvement when using templates. However...

I wrote a basic list container (using templates), and a list container
(using virtual derived classes). I also tried with the std lib vector
class. I ran 1000000 inserts and accesses to all these lists and got
the following results (compiling on windows with microsoft compiler):

Size:
22,528 mytpl.exe
36,864 nonstd.exe
40,960 std.exe

The first is my template list, the second my non-template list, and the
third is using the std vector.

The first surprise was that my template list was actually *smaller*
than the non-template version! Very surprising. However, it's not all
good news. I then ran some timing tests.

Time:
875: running std.exe
1484: running nonstd.exe
1563: running mytpl.exe

As expected, the std vector is the fastest. However my template list
class is the *slowest*!!! This was definitly not expected.

Does anyone have any inputs on what's going on?

cheers,
/Charles


--


It's hard to comment without actually taking a look at what/how you
programmed!!

However, the above results are not so surprising (to me) due to the
following reasons/assumptions:

mytpl.exe: (basic list container using templates) you would have used
a single class with few basic operations to attain the functionality
you intended for.
nonstd.exe: (using virtual derived classes) you would have used many
classes to attain the same functionality.
std.exe: (using std::vector) vector comes with a quite a bit of
baggage (allocators, iterators ...). However, it's interesting to know
that you implemented a "list" using "vector" in spite of "std::list"
availability!

Question: Is the 'list' you implemented a "linked list" kind of thing
or an "array" kind?

Very surprising. However, it's not all

Again, it's hard to say why, without actually analyzing your programs
(for time and space complexities of the algorithms you applied). A
language (C++ or anything else) wouldn't be able to come to rescue us
from our programming inefficiencies and definitely it would be worth
spending more time on improving our algorithm efficiencies rather than
niggling over the way we use a language.

Yes I see that :). I've pasted my code below. This is the first time
I've posted to a usenet group. I've also made the mistake of

You are basically right about the way I've written the classes.
However, my understanding was that the compiler would generate the
classes in the template version which I hand coded in the virtual
derived class version. So the net result would have been a slight
increase in the template version (as the compiler would have copied the
entire class for every new type).
I used std::vector simply because I read somewhere that it was the
fastest container available and I wanted to use it as a benchmark for
the "best possible" performance :)

It's a "linked list" kind. Have pasted the code below.

Actually what I'm looking at is the *cost* of template usage (if any)
in terms of speed and size. I'm not really looking for the best
implementation of a list. From what I read, templates should have given
me larger code that may have been faster. Instead it gave me smaller
code that's slower which is what I found surprising.
Programs follow:
----------------------- Template List ----------------------------
template <class T>
class ListNode
{
public:
ListNode (T * pVal) {uVal = pVal;}
T * uVal;
ListNode<T>* uNext;
ListNode<T>* uPrev;
};
template <class T>
class MyTList
{
public:
MyTList () { vFirst = NULL; }

void Insert (T * e) {
ListNode<T> * ln;
ln = new ListNode<T> (e);
ln->uNext = vFirst;
ln->uPrev = NULL;
if (vFirst != NULL)
vFirst->uPrev = ln;
vFirst = ln;
}
ListNode<T> * GetNodes () { return vFirst;}
private:
ListNode<T> * vFirst;
};
--------------------------------- Template List ends
----------------------------
--------------------------------- Non Template List
-----------------------------
class ListElem
{
public:
virtual ~ListElem (void) {}
ListElem * uNext;
ListElem * uPrev;


};
class MyList
{
public:
MyList () { vFirst = NULL;}
void Insert (ListElem * e) {
e->uNext = vFirst;
e->uPrev = NULL;
if (vFirst != NULL)
vFirst->uPrev = e;
vFirst = e;
}
ListElem * GetNodes () { return vFirst; }
private:
ListElem * vFirst;

};
------------------------------ Non template list ends
--------------------------

Note that the code is *very* similar for the template and non-template
version. I had to derive a ListElem for the non-template class:
class MyClassElem : public ListElem
{
public:
MyClassElem (MyClass * c) { uMyClass = c; }
MyClass * uMyClass;
};

But didn't have to do anything for the template version.

The cpp test code basically just runs two loops (inserting and
get-ting 1000000 elements).

cheers,
/Charles

/*------------ HISTORY Ends -------------------*/



Yes I see that :). I've pasted my code below. This is the first time
I've posted to a usenet group.

Welcome to the board!
You are basically right about the way I've written the classes.
However, my understanding was that the compiler would generate the
classes in the template version which I hand coded in the virtual
derived class version. So the net result would have been a slight
increase in the template version (as the compiler would have copied the
entire class for every new type).
I used std::vector simply because I read somewhere that it was the
fastest container available and I wanted to use it as a benchmark for
the "best possible" performance :)

That's unfair!! I guess you aren't completely aware of the cost of
allocating memory dynamically using 'new' operator (see down below for
the results I got, which might be of interest to you).
It's a "linked list" kind. Have pasted the code below.

Okay, I have gone through and found that you are actually trying to
implement "a LIFO doubly linked list". (LIFO: Last In First Out i.e. on
traversing the list starting with MyTList::GetNodes(), the last element
inserted into the list would be the first element that would be
visited).

Actually what I'm looking at is the *cost* of template usage (if any)
in terms of speed and size.

Usually, the "language implementers" strive their best to enforce a
near "zero-cost" overhead (either in terms of time or space) on usage
of any language feature and that too "C++" would be at the forefront in
matters like this. As a "language user", one should not worry about
things like this.
I'm not really looking for the best
implementation of a list. From what I read, templates should have given
me larger code that may have been faster. Instead it gave me smaller
code that's slower which is what I found surprising.

No, I think you are mistaken. "Algorithm Implementations" (but not
"Language Implementations") matter a lot!!! When you are trying to
compare/compete the performance of your code with some of the best
implementation's (i.e. library writer's), everything matters!
Programs follow:
----------------------- Template List ----------------------------
template <class T>
class ListNode
{
public:
ListNode (T * pVal) {uVal = pVal;}
T * uVal;
ListNode<T>* uNext;
ListNode<T>* uPrev;
};
template <class T>
class MyTList
{
public:
MyTList () { vFirst = NULL; }

void Insert (T * e) {
ListNode<T> * ln;
ln = new ListNode<T> (e);
ln->uNext = vFirst;
ln->uPrev = NULL;
if (vFirst != NULL)
vFirst->uPrev = ln;
vFirst = ln;
}
ListNode<T> * GetNodes () { return vFirst;}
private:
ListNode<T> * vFirst;
};
--------------------------------- Template List ends

Question: Why are you trying to insert "a pointer to a ListNode, that
inturn holds a pointer to an object" into the list, rather than
inserting "a pointer to a ListNode, that 'contains' an object"? The
latter would cut down one-half of the calls to "new" operator!

//////////////////////////////////////////////////////////////////////
Vulnerable fragments of the code you presented:
==================================
template <class T>
class ListNode
{
public:
ListNode (T * pVal) {uVal = pVal;}
T * uVal;
....
};
template <class T>
class MyTList
{
public:
...
void Insert (T * e) {
ListNode<T> * ln;
ln = new ListNode<T> (e);
...
}
...
};

Probable "driver" should have been:
========================
int main(){
....
MyTList<double> aMyTList;

for (int i = 0;i < 1000000;i++)
aMyTList.Insert (new double(i));
....
}
//////////////////////////////////////////////////////////////////////

Instead, why not the following can be??

//////////////////////////////////////////////////////////////////////
Suggested change:
==============
template <class T>
class ListNode
{
public:
ListNode (T pVal) {uVal = pVal;}
T uVal; //Hold "OBJECT" rather than a pointer to it!
...
};
template <class T>
class MyTList
{
public:
...
void Insert (T e) {
ListNode<T> * ln;
ln = new ListNode<T> (e);
...
}
...
};

Probable "driver" can be:
=================
int main(){
....
MyTList<double> aMyTList;

for (int i = 0;i < 1000000;i++)
aMyTList.Insert (i);
....
}
//////////////////////////////////////////////////////////////////////

I tried the above approach and following are the results on my machine
using 'GNU's gcc' compiler:

Run Time with the code you presented to 'insert' 1000000 doubles: 650
seconds

=========
Run Time with my suggested change: 360 seconds
=========

If you are ready to consider a bit more advanced version of mine that
would do the memory allocation in "chunks" rather than one by one on
demand, then the results would be more interesting. Here is my quick
and dirty "bit more advanced version" (this should be compilable and
executable with 'GNU's gcc'):

//////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <vector>

using namespace std;

template <class T>
class ListNode
{
public:
T uVal;
ListNode<T>* uNext;
ListNode<T>* uPrev;
};

template <class T>
class MyTList
{
public:
MyTList (size_t myPoolSize = 1000000) {
vFirst = NULL;

// Extra baggage initialization
_myPoolSize = myPoolSize;
_myMemoryPool = new ListNode<T>[_myPoolSize];
_myNext = _myPoolSize - 1;
}

void Insert (T e) {
ListNode<T>* ln;

if(_myNext<0){
// memory pool exhausted; so, let's refill it!
_myMemoryPool = new ListNode<T>[_myPoolSize];
_myNext = _myPoolSize - 1;
}
ln = &(_myMemoryPool[_myNext--]);

ln->uVal = e; //Default assignment operator of "ListNode"
suffices in this case.

ln->uNext = vFirst;
ln->uPrev = NULL;
if (vFirst != NULL)
vFirst->uPrev = ln;
vFirst = ln;
}
ListNode<T> * GetNodes () { return vFirst;}

private:
ListNode<T> * vFirst;

// Extra baggage for memory management and for extra performance!!
ListNode<T>* _myMemoryPool;
size_t _myPoolSize;
int _myNext;
};

int main()
{
clock_t t1 = clock();

MyTList<double> aMyTList;
for (int i = 0; i < 1000000; ++i)
aMyTList.Insert(i);

clock_t t2 = clock();

std::vector<double> aVec(1000000);
for (int i = 0; i < 1000000; ++i)
aVec.push_back(i);

clock_t t3 = clock();

cout << "MyTList: " << t2 - t1 << endl;
cout << "std::vector: " << t3 - t2 << endl;

return 0;
}

//////////////////////////////////////////////////////////////////////

And the ouput was this:

MyTList: 30
std::vector: 50

(We can beat them, Charles!!)
Note that the code is *very* similar for the template and non-template version.

Hence, I don't want to comment upon your "non-template" version!! But,
I would like to repeat what I had said in my earlier posting:-

-srikar vedantam
 
O

Old Wolf

for (int i = 0;i < 1000000;i++) {
one.Insert (new MyClass (i));
}

Here you do 1000000 memory allocations
for (int i = 0;i < 1000000;i++) {
one.Insert (new MyClassElem (new MyClass (i)));
}

And here you do 2000000 memory allocations.

In the std::vector version there will only be a handful of allocations.
This could explain the differences you are seeing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,147
Latest member
CarenSchni
Top