[interfacekit] Re: [Fwd: Message submitted to 'interfacekit']
- From: "Ingo Weinhold" <bonefish@xxxxxxxxxxxxxxx>
- To: interfacekit@xxxxxxxxxxxxx
- Date: Sat, 12 Oct 2002 01:07:47 CEST (+0200)
> Ingo Weinhold wrote:
> >>If we are -really- concerned about performance, we can inline the
> >>'stubby' functions in the header.
> >
> > We should be very careful with inlining functions. Unless the
> > functions's tasks are trival (as BString::Length()/String() are for
> > example), the function call overhead to function execution ratio
> > should
> > be insignificantly small. And inlining may introduce serious binary
> > compatibility traps.
>
> Excellent point. I think we should *not* inline anything that isn't
> already inlined. Again, if later testing shows a performance issue,
> we'll revisit the issue. In the meantime, the conservative approach
> is
> best.
I don't know what you consider a performance issue (and actually not
even what the conservative approach -- literally it would be to leave
the implementation as it is). In the case of basic and often used
classes like BString or BList I would label any implementation that is
measurably slower unacceptable. Especially in this very case of
BString, where an improvement is known, obvious and implemented.
That an additional strlen() will make BString::Prepend(const BString &)
slower becomes clear when having a look at the involved operations.
strlen() is a slow O(n) operation (n being the length of the prepended
string), whereas memcpy() is a fast one. With increasing n the impact
of strlen() grows relatively to the more or less O(1) realloc() and
O(m) memmove() (m being the length of `this' string). I couldn't resist
writing a little test simulating the situation. Although the test
string is malloc()ed and free()d in the test loop, the result is
impressively unambigious. Even with a prepended string as short as 10
characters the `optimized' functions is more than 15% faster. For a
length of 1000 it is more than twice as fast (with optimization < -O2
even more). The impact of realloc() is of course significantly greater,
when it is unable to grow the memory region -- sometimes a test run
suffers from that. However, for very long strings (100000 chars and
more) I get +50% again.
To conclude: I think, it is a total waste of time to reimplement the
concerned methods to make them slower. But that's just my humble
opinion.
CU, Ingo
// string-test.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <OS.h>
// prepend with strlen()
static
void
prepend1(char *str, char *prependString, int size1, int /*size2*/)
{
int size2 = strlen(prependString) + 1;
str = (char*)realloc(str, size1 + size2);
memmove(str + size2, str, size1);
memcpy(str, prependString, size2);
}
// prepend without strlen()
static
void
prepend2(char *str, char *prependString, int size1, int size2)
{
str = (char*)realloc(str, size1 + size2);
memmove(str + size2, str, size1);
memcpy(str, prependString, size2);
}
typedef void prependFunction(char *, char*, int, int);
static
bigtime_t
run_test(prependFunction *prepend, int iterations, int size1, int
size2)
{
char *prependString = (char*)malloc(size2);
memset(prependString, 'a', size2 - 1);
prependString[size2 - 1] = '\0';
bigtime_t startTime = system_time();
for (int i = 0; i < iterations; i++) {
char *str = (char*)malloc(size1);
(*prepend)(str, prependString, size1, size2);
free(str);
}
bigtime_t resultTime = system_time() - startTime;
free(prependString);
return resultTime;
}
int
main()
{
enum { ITERATIONS = 100000 };
int tests[] = { 1, 10, 100, 1000 };
int testCount = sizeof(tests) / sizeof(int);
for (int i = 0; i < testCount; i++) {
int prependSize = tests[i];
printf("\nTEST: size: %d\n", prependSize);
bigtime_t testTime1 = run_test(prepend1, ITERATIONS, 10,
prependSize);
bigtime_t testTime2 = run_test(prepend2, ITERATIONS, 10,
prependSize);
printf(" prepend with strlen(): %lld us\n", testTime1);
printf(" prepend without strlen(): %lld us\n", testTime2);
double speedup = double(testTime1 - testTime2) / testTime2;
double savedTime = double(testTime1 - testTime2) / testTime1;
printf(" speedup: %.2f %%\n", speedup * 100);
printf(" saved time: %.2f %%\n", savedTime *
100);
}
return 0;
}
Other related posts: