Article View: comp.sys.mac.programmer.codewarrior
Article #644Limited move semantics available in Pro 9
From: Howard Hinnant
Date: Fri, 07 Nov 2003 23:13
Date: Fri, 07 Nov 2003 23:13
209 lines
8615 bytes
8615 bytes
Move semantics has been proposed for C++0X:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm
In a nutshell, this proposal is about performance. Move semantics is
just an organized way of doing a shallow copy of heavy weight types when
you don't care what happens to the source (i.e. you only need a cheap
move, not an expensive copy).
The full move semantics proposal requires some (backwards compatible)
language changes, and is not available in Pro 9. However, a limited
version of move has been coded into the Pro 9 std::vector.
Specifically, when you have a std::vector<any other std or
Metrowerks::container>, then the vector will internally move its
elements instead of copy them during insert and erase. There is no
change in interface. Your vector will simply be higher performance.
There is nothing you need to do to achieve this performance gain except
recompile your code against Pro 9.
For example, consider the vector vs set debate. Sometimes an ordered
vector can be higher performance than the equivalent set. This can be
especially true if the elements to be ordered are light weight and/or if
the application is mostly concerned with lookup instead of inserting new
elements (inserting into a vector can be slow).
While the above statement remains true, exactly when and where set is
superior to an ordered vector has radically changed with Pro 9. To
demonstrate, below is a test that pits vector vs set, using what used to
be a relatively heavy weight element: std::string, and it does so for
vector's weakest point: ordered insertion.
The test below creates a randomized vector<string>, where each string is
fairly long (a path/file is used in this example). The file used in
this test can be found at:
http://home.twcny.rr.com/hinnant/tip_archive/keys.txt
The set test merely times the construction of the set from the
randomized vector of keys.
The vector test times the effort required to insert each key into the
vector, keeping it ordered at each step. Naturally it would be much
faster to just build the vector in random order, and then sort it. But
this test is investigating the cost of inserting a string into a sorted
vector, and how that relates to inserting a string into a set.
Here is the full source of the test:
#include <vector>
#include <string>
#include <time.h>
#include <stddef.h>
#include <numeric>
template <class F>
float test(F f)
{
std::vector<float> t;
int i;
for (i = 0; i < 10; ++i)
t.push_back(f());
while (i < 1000 && std::accumulate(t.begin(), t.end(), 0.0) < 1.0)
{
t.push_back(f());
++i;
}
std::sort(t.begin(), t.end());
return (float)
(
std::accumulate(t.begin(),
t.end()-(ptrdiff_t)(t.size()/10),
0.0
)
/ (t.size()-(t.size()/10))
);
}
#include <set>
#include <iostream>
#include <fstream>
std::vector<std::string> keys;
float test_vector_insert_string()
{
typedef std::vector<std::string>::const_iterator ci;
clock_t t = clock();
std::vector<std::string> v;
for (ci i = keys.begin(), e = keys.end(); i != e; ++i)
v.insert(std::lower_bound(v.begin(), v.end(), *i), *i);
t = clock() - t;
return (float)(t/(double)CLOCKS_PER_SEC);
}
float test_set_insert_string()
{
clock_t t = clock();
std::set<std::string> s(keys.begin(), keys.end());
t = clock() - t;
return (float)(t/(double)CLOCKS_PER_SEC);
}
int
main()
{
std::ifstream infile("keys.txt");
if (!infile.is_open())
{
std::cout << "Can't open keys.txt\n";
return 1;
}
std::istream_iterator<std::string> in(infile), eof;
keys.assign(in, eof);
std::cout << "number of keys = " << keys.size() << '\n';
std::random_shuffle(keys.begin(), keys.end());
std::cout << std::scientific;
float v = test(test_vector_insert_string);
float l = test(test_set_insert_string);
std::cout << "vector speed = " << v << '\n';
std::cout << "set speed = " << l << '\n';
std::cout << std::fixed;
std::cout << "vector/set = " << v/l << '\n';
}
The templated test function is just me being fastidious. This function
will take a test-functor, and run it at least 10 times, but no more than
1000 times. Each run results in a timing (represeted by a float). To
keep from waiting all day for tests to complete, test stops repeating
the function run if the accumulated times exceed 1 second (once at least
10 runs are made). The slowest 10% of the runs are tossed out the
window and the remaining fastest 90% of the runs are averaged and that
is returned as the speed of the functor. This heuristic has resulted in
very repeatable timing results.
As described eariler, test_vector_insert_string simply inserts the
strings one at a time into a vector, each time using lower_bound to find
the right place to insert the string. The resulting vector is sorted.
The test_set_insert_string times the same functionality for set, which
is simply constructed from the randomized keys.
The main function reads the keys from keys.txt, prints out the number of
keys so there is some confidence that the read was done correctly, runs
the tests and compares the times.
In Pro 8.x the results are:
Carbon:
number of keys = 530
vector speed = 3.075024e-02
set speed = 2.983515e-03
vector/set = 10.306715
and for Mach-O:
number of keys = 530
vector speed = 3.103448e-02
set speed = 2.829457e-03
vector/set = 10.968351
Actaully I'm simulating Pro 8 by simply turning off move semantics in
Pro 9, so please feel free to correct these figures for me. These
results reflect conventional wisdom. If you're inserting a lot of heavy
weight objects into a vector, you should probably use set instead.
In Pro 9 the results are:
Carbon:
number of keys = 530
vector speed = 3.223833e-03
set speed = 3.000515e-03
vector/set = 1.074427
and for Mach-O:
number of keys = 530
vector speed = 2.696629e-03
set speed = 2.676580e-03
vector/set = 1.007491
The important thing to notice here is that the Pro 9 ordered
vector<string> is nearly as fast as set<string>. In comparison the Pro
8 vector (without move semantics) is 10 to 11 times slower than set!
That is a very significant difference.
Now of course your results may differ, especially for different input
sets. And as the size of the input gets sufficiently large, set is
still going to be the clear winner. It is just that the range of
conditions over which vector is competative with set has now been
greatly expanded.
You should see similar performance improvements with vector::erase. And
this effects not only vector<string>, but also vector<vector<T>>,
vector<set<T>>, vector<Metrowerks::hash_map<K,V>>, etc. There is no
effect on vector<int>, vector<pod>, etc. These instantiations will run
at the same speed as before. It is only heavy-weight objects which our
std::vector knows about that have been optimized within vector.
It is our hope that one day vector will be just as efficient for your
user-defined heavy-weight objects. But for that, we really need the
full move semantics proposal to be standardized.
-Howard
The C++ lib guy
Metrowerks
Technical Details
Message-ID:
<hinnant-3339D2.18134107112003@syrcnyrdrs-03-ge0.nyroc.rr.com>Path:
arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!news.maxwell.syr.edu!news-out.visi.com!petbe.visi.com!yellow.newsread.com!netaxs.com!newsread.com!news-west.rr.com!news.rr.com!news-rtr.nyroc.rr.com!news-out.nyroc.rr.com!twister.nyroc.rr.com.POSTED!53ab2750!not-for-mailShow Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 10bcce,cf58ff37bec3f762,start X-Google-Attributes: gid10bcce,public X-Google-Thread: f635e,cf58ff37bec3f762,start X-Google-Attributes: gidf635e,public X-Google-ArrivalTime: 2003-11-07 15:14:17 PST Path: arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!news.maxwell.syr.edu!news-out.visi.com!petbe.visi.com!yellow.newsread.com!netaxs.com!newsread.com!news-west.rr.com!news.rr.com!news-rtr.nyroc.rr.com!news-out.nyroc.rr.com!twister.nyroc.rr.com.POSTED!53ab2750!not-for-mail From: Howard Hinnant <hinnant@metrowerks.com> Newsgroups: comp.sys.mac.programmer.codewarrior,codewarrior.mac Subject: Limited move semantics available in Pro 9 Organization: Metrowerks User-Agent: MT-NewsWatcher/3.3b1 (PPC Mac OS X) Message-ID: <hinnant-3339D2.18134107112003@syrcnyrdrs-03-ge0.nyroc.rr.com> Lines: 209 Date: Fri, 07 Nov 2003 23:13:40 GMT NNTP-Posting-Host: 24.58.14.109 X-Complaints-To: abuse@rr.com X-Trace: twister.nyroc.rr.com 1068246820 24.58.14.109 (Fri, 07 Nov 2003 18:13:40 EST) NNTP-Posting-Date: Fri, 07 Nov 2003 18:13:40 EST