 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Frank Astier Guest
|
Posted: Thu Dec 16, 2004 1:35 pm Post subject: Completely inlining sort for small arrays |
|
|
Still working on this problem where I need to sort a small array (<16
elements), billions of times, so I want to use templates to completely
inline the code...
More about the problem: the data structure to sort is a
vector
Contract1 price < Contract2 price, where price is a random double.
I tried to tweak the code contributed by David Abrahams, but I'm
running into compilation issues... I thought it would be efficient to
xorswap the pointers inline instead of relying on std::swap, but I get:
Compiling with Intel(R) C++ 8.1 ...(Intel C++ Environment)
std::vector::iterator,
Pred=CheapestFirst]" at line 56
instantiation of "void quicksort_impl<N, while_>::go(T,
const Pred &) [with N=8U, while_=true, T=std::vector<Contract *,
std::allocator::iterator, Pred=CheapestFirst]" at line 72
instantiation of "void quicksort(T, const Pred &) [with
T=std::vector<Contract *, std::allocator::iterator,
Pred=CheapestFirst]"
..MyQuicksort.cpp(14): error: no operator "^=" matches these operands
operand types are: std::vector<Contract *,
std::allocator::iterator ^= std::vector<Contract *,
std::allocator::iterator
inline void xorswap(T x1, T x2) { x1 ^= x2; x2 ^= x1; x1 ^= x2; }
^
detected during:
instantiation of "void xorswap(T, T) [with
T=std::vector<Contract *, std::allocator::iterator]" at
line 26
instantiation of "void QSpartition<N, last, i,
while_>::go(T, T, const Pred &) [with N=8U, last=0U, i=1U, while_=true,
T=std::vector<Contract *, std::allocator::iterator,
Pred=CheapestFirst]" at line 56
instantiation of "void quicksort_impl<N, while_>::go(T,
const Pred &) [with N=8U, while_=true, T=std::vector<Contract *,
std::allocator::iterator, Pred=CheapestFirst]" at line 72
instantiation of "void quicksort(T, const Pred &) [with
T=std::vector<Contract *, std::allocator::iterator,
Pred=CheapestFirst]"
How can I tell him that the vector<Contract*>::iterator *IS* a
Contract* that he can merrily xor??
My tweaked code below:
template <typename T>
inline void xorswap(T x1, T x2) { x1 ^= x2; x2 ^= x1; x1 ^= x2; }
template <size_t N, bool while_ = (N > 1)> struct quicksort_impl;
template <size_t N, size_t last = 0, size_t i = 1, bool while_ = (i <
N)>
struct QSpartition
{
template <typename T, typename Pred>
inline static void go(T a, T pivot, const Pred& p) {
if (p(a+i, pivot)) {
xorswap(a+last+1, a+i);
QSpartition<N, last+1, i+1, (i+1 < N)>::go(a, pivot, p);
} else
QSpartition<N, last, i+1, (i + 1 < N)>::go(a, pivot, p);
}
};
template <size_t N, size_t last, size_t i>
struct QSpartition<N, last, i, false>
{
template <typename T, typename Pred>
inline static void go(T a, T, const Pred& p)
{
xorswap(a, a+last);
size_t const pivotpos = last;
// Done partitioning; now recursively quicksort
quicksort_impl<pivotpos>::go(a, p);
size_t const start2 = pivotpos + 1;
quicksort_impl<N - start2>::go(a + start2, p);
}
};
template <size_t N, bool while_>
struct quicksort_impl
{
template <typename T, typename Pred>
inline static void go(T a, const Pred& p)
{
QSpartition<N>::go(a, a, p);
}
};
// Terminating case for the outer sort
template <size_t N>
struct quicksort_impl<N, false>
{
template <typename T, typename Pred>
inline static void go(T, const Pred&) {}
};
// A convenient wrapper for quicksort_impl
template <typename T, typename Pred>
inline void quicksort(T begin, const Pred& p)
{
quicksort_impl<8>::go(begin, p);
}
struct Contract {
double price;
Contract() : price(rand()) {}
};
struct Portfolio : vector<Contract*> {
Portfolio(size_t n) : vector<Contract*>(n) {
fill(begin(), end(), new Contract);
}
~Portfolio() { for (iterator i = begin(); i != end(); ++i) delete *i;
}
};
struct CheapestFirst {
bool inline operator()(Contract* c1, Contract* c2) {
return c1->price < c2->price;
}
};
int main(int argc, char** argv)
{
for (size_t i = 0; i < 100; ++i) {
Portfolio p( ;
quicksort(p.begin(), CheapestFirst());
}
char c; cin >> c;
return 0;
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Andrew Koenig Guest
|
Posted: Fri Dec 17, 2004 4:45 am Post subject: Re: Completely inlining sort for small arrays |
|
|
"Frank Astier" <fastier (AT) yahoo (DOT) com> wrote
| Quote: | I tried to tweak the code contributed by David Abrahams, but I'm
running into compilation issues... I thought it would be efficient to
xorswap the pointers inline instead of relying on std::swap
|
Possible but unlikely, even if you could get it to work.
A plain old swap requires four memory references (fetch each object once,
store each object once); an xorswap requires nine (fetch each object once,
store one object, repeat everything three times), plus three xor operations.
It is hard to imagine how an optimizing compiler would make it faster than
simply moving data around, because any such optimizer would probably do its
magic on the simple version as well.
MOreover, you can't xor pointers, which means that to make it work, you have
to do some type cheating.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Andrei Alexandrescu (See Guest
|
Posted: Fri Dec 17, 2004 4:46 am Post subject: Re: Completely inlining sort for small arrays |
|
|
"Frank Astier" <fastier (AT) yahoo (DOT) com> wrote
| Quote: | I thought it would be efficient to
xorswap the pointers inline instead of relying on std::swap, but I get:
|
You may want to test this assumption. A while ago I thought the same, and
wrote a little test program. I could not make XOR-based swap to outperform
simple-minded swap on any machine and any compiler I could get my hands on.
Andrei
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
David Abrahams Guest
|
Posted: Fri Dec 17, 2004 1:58 pm Post subject: Re: Completely inlining sort for small arrays |
|
|
Frank Astier wrote:
| Quote: | Still working on this problem where I need to sort a small array (<16
elements), billions of times, so I want to use templates to completely
inline the code...
More about the problem: the data structure to sort is a
vector
Contract1 price < Contract2 price, where price is a random double.
I tried to tweak the code contributed by David Abrahams, but I'm
running into compilation issues... I thought it would be efficient to
xorswap the pointers inline instead of relying on std::swap, but I get:
Compiling with Intel(R) C++ 8.1 ...(Intel C++ Environment)
std::vector::iterator,
Pred=CheapestFirst]" at line 56
instantiation of "void quicksort_impl<N, while_>::go(T,
const Pred &) [with N=8U, while_=true, T=std::vector<Contract *,
std::allocator::iterator, Pred=CheapestFirst]" at line 72
instantiation of "void quicksort(T, const Pred &) [with
T=std::vector<Contract *, std::allocator::iterator,
Pred=CheapestFirst]"
|
Why are you using quicksort? Did you miss my post that declared
insertion sort to be the winner on arrays of 16 elements or fewer?
--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Dec 17, 2004 5:33 pm Post subject: Re: Completely inlining sort for small arrays |
|
|
David Abrahams wrote:
| Quote: | Frank Astier wrote:
Still working on this problem where I need to sort a small
array (<16 elements), billions of times, so I want to use
templates to completely inline the code...
More about the problem: the data structure to sort is a
vector
ordering is Contract1 price < Contract2 price, where price
is a random double.
I tried to tweak the code contributed by David Abrahams, but
I'm running into compilation issues... I thought it would be
efficient to xorswap the pointers inline instead of relying
on std::swap, but I get:
Compiling with Intel(R) C++ 8.1 ...(Intel C++ Environment)
std::vector::iterator,
Pred=CheapestFirst]" at line 56
instantiation of "void quicksort_impl<N, while_>::go(T,
const Pred &) [with N=8U, while_=true, T=std::vector<Contract *,
std::allocator::iterator, Pred=CheapestFirst]" at line
72
instantiation of "void quicksort(T, const Pred &) [with
T=std::vector<Contract *, std::allocator::iterator,
Pred=CheapestFirst]"
Why are you using quicksort? Did you miss my post that
declared insertion sort to be the winner on arrays of 16
elements or fewer?
|
I'm sure you know it, but it's worth pointing out that the
breakoff point will depend on the architecture. I did some
tests a long, long time ago on a Sun -- I forget whether it was
still a Motorola based Sun 3 or and early Sparc, and found a
breakoff of around 5 or 6. Earlier, a collegue at Siemens found
a breakoff of around 60 or 70 (!) on a BS 2000 mainframe.
A couple of other points worth mentioning :
- He complains about not being able to convince the compiler
that vector<>::iterator was a pointer. Maybe that's because
it isn't. (It isn't with g++, for example.)
- Others have already pointed out that the xor is typically
slower than the swap. I'm surprised that no one pointed out
that it doesn't work, either, if the two references refer to
the same element. Something which occasionally happens in
some sorting algorithms.
- Finally, an insertion sort can normally be made more rapid
by using a selection sort for the first element. Once you
know that you've got the smallest element at the begining,
you can skip that part of the test in the innermost loop.
I've found that when sorting very simple to compare types,
like ints and doubles, this can save up to 30%.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Frank Astier Guest
|
Posted: Sat Dec 18, 2004 12:22 pm Post subject: Re: Completely inlining sort for small arrays |
|
|
David -
I'll switch over to insertion sort. What I am trying to do though, is
pass in a predicate that would take 2 pointers to objects and somehow
provide the strict weak ordering. I am also trying to tweak your code
to take in a range as 2 iterators for beginning and end of the range,
instead of specifying the container.
But specifying a predicate instance as we do in the STL sort would be a
runtime thing, therefore not "inline-able". Specifying a range is also
a runtime notion, rather than a compile time notion.
Is there any way the predicate itself can be inlined in the sorting
code? After all, the compiler just has to look up the definition of the
predicate and inline it?
Frank
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
David Abrahams Guest
|
Posted: Sun Dec 19, 2004 1:51 am Post subject: Re: Completely inlining sort for small arrays |
|
|
Frank Astier wrote:
| Quote: | David -
I'll switch over to insertion sort. What I am trying to do though, is
pass in a predicate that would take 2 pointers to objects and somehow
provide the strict weak ordering. I am also trying to tweak your code
to take in a range as 2 iterators for beginning and end of the range,
instead of specifying the container.
But specifying a predicate instance as we do in the STL sort would be a
runtime thing, therefore not "inline-able".
|
Does it have to be? It's possible to capture everything that's
important in most predicates using just a type. Just pass a stateless
function object.
| Quote: | Specifying a range is also
a runtime notion, rather than a compile time notion.
|
Right. If you want it to be efficient using a range you need to test
the length of the range once at the outside of the sort and dispatch to
the appropriate instantiation of sort<>
| Quote: | Is there any way the predicate itself can be inlined in the sorting
code? After all, the compiler just has to look up the definition of the
predicate and inline it?
|
See above.
--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|