1 : // ソートテスト その4 スマートポインタを用いた場合. 2 : #include <stdio.h> 3 : #include <stdlib.h> 4 : #include <time.h> 5 : #include <assert.h> 6 : #include <algorithm> 7 : #include <functional> 8 : #include <vector> 9 : #include <list> 10 : #include <string> 11 : 12 : #if _MSC_VER >= 1500 13 : #include <memory> 14 : using namespace std::tr1; 15 : #else 16 : #include <boost/shared_ptr.hpp> 17 : using namespace boost; 18 : #endif 19 : 20 : 21 : template<typename RAIte, class C > 22 : void quick_sort(RAIte first, RAIte last, C cmp) 23 : { 24 : typedef typename std::iterator_traits<RAIte>::value_type T; 25 : 26 : using std::iter_swap; 27 : std::size_t size = last - first; 28 : if (size <= 32) { 29 : if (size <= 1) 30 : return; 31 : RAIte i = first; 32 : while (++i != last) { 33 : T tmp( *i ); 34 : RAIte j = i; 35 : RAIte k = i; 36 : do { 37 : --k; 38 : if (!cmp(tmp, *k)) 39 : break; 40 : *j = *k; 41 : --j; 42 : } while (k != first); 43 : *j = tmp; 44 : } 45 : return; 46 : } 47 : const T m( *(first + size/2) ); 48 : RAIte l = first; 49 : RAIte r = last; 50 : for (;;) { 51 : while (cmp(*l, m)) 52 : ++l; 53 : do { 54 : --r; 55 : } while (cmp(m, *r)); 56 : if (!(l < r)) 57 : break; 58 : iter_swap(l, r); 59 : ++l; 60 : } 61 : quick_sort(first, l , cmp); 62 : quick_sort(l , last, cmp); 63 : } 64 : 65 : 66 : 67 : template<typename RAIte> inline 68 : void quick_sort(RAIte first, RAIte last) { 69 : quick_sort( first, last, std::less<typename std::iterator_traits<RAIte>::value_type>() ); 70 : } 71 : 72 : 73 : 74 : // =========================================================================== 75 : #ifdef _WIN32 76 : #include <windows.h> 77 : typedef unsigned __int64 PerfCnt_tick_t; 78 : PerfCnt_tick_t PerfCnt_getTick() { PerfCnt_tick_t c; QueryPerformanceCounter((LARGE_INTEGER*)&c); return c; } 79 : PerfCnt_tick_t PerfCnt_tickPerSec() { static PerfCnt_tick_t s = 0; if (!s) QueryPerformanceFrequency((LARGE_INTEGER*)&s); return s; } 80 : #else 81 : #include <time.h> 82 : typedef clock_t PerfCnt_tick_t; 83 : #define PerfCnt_getTick() clock() 84 : #define PerfCnt_tickPerSec() CLOCKS_PER_SEC 85 : #endif 86 : 87 : 88 : 89 : // =========================================================================== 90 : 91 : template<typename T> 92 : T random() { 93 : return T(rand()); 94 : } 95 : 96 : template<> 97 : std::string random<std::string>() { 98 : char buf[128]; 99 : sprintf(buf, "%d%d%d", rand(),rand(),rand()); 100 : return std::string(buf); 101 : } 102 : 103 : 104 : 105 : // =========================================================================== 106 : #ifdef USE_SMPCLASS 107 : #if USE_SMPCLASS != 1 108 : #include <tr1/array> 109 : #endif 110 : #include <boost/intrusive_ptr.hpp> 111 : 112 : class SmpClass { 113 : public: 114 : ~SmpClass() { free(name_); } 115 : SmpClass() : name_(0), x_(0),y_(0),z_(0),argb_(0xFFFFFFFF),refCnt_(0) { /*buf_.resize(256);*/ } 116 : 117 : SmpClass(const SmpClass& r) 118 : : name_(strdup(r.name_)), x_(r.x_), y_(r.y_), z_(r.z_), argb_(r.argb_), refCnt_(0), buf_(r.buf_) {} 119 : 120 : SmpClass(const char* name, double x, double y, double z, unsigned argb=0xffffffff) 121 : : name_(strdup(name)), x_(x), y_(y), z_(z), argb_(argb), refCnt_(0) 122 : { 123 : #if USE_SMPCLASS == 1 124 : buf_.resize(256); 125 : #endif 126 : } 127 : 128 : SmpClass& operator=(const SmpClass& r) { SmpClass(r).swap( *this ); return *this; } 129 : 130 : void swap(SmpClass& r); 131 : bool operator<(const SmpClass& r) const; 132 : 133 : void incRef() { if (this) ++refCnt_; } 134 : void decRef_and_release() { if (this && refCnt_) { if (!(--refCnt_)) delete this; } } 135 : unsigned ref_count() const { return refCnt_; } 136 : 137 : private: 138 : char* name_; 139 : double x_, y_, z_; 140 : unsigned argb_; 141 : unsigned refCnt_; 142 : #if USE_SMPCLASS == 1 143 : std::vector<char> buf_; 144 : #else 145 : std::tr1::array<char,160> buf_; 146 : #endif 147 : }; 148 : 149 : 150 : inline bool SmpClass::operator<(const SmpClass& r) const { 151 : if (z_ < r.z_) 152 : return 1; 153 : if (z_ > r.z_) 154 : return 0; 155 : if (y_ < r.y_) 156 : return 1; 157 : if (y_ > r.y_) 158 : return 0; 159 : return strcmp(name_, r.name_) < 0; 160 : } 161 : 162 : 163 : inline void SmpClass::swap(SmpClass& r) { 164 : using std::swap; 165 : swap(name_, r.name_); 166 : swap(x_ , r.x_ ); 167 : swap(y_ , r.y_ ); 168 : swap(z_ , r.z_ ); 169 : swap(argb_, r.argb_); 170 : swap(refCnt_, r.refCnt_); 171 : swap(buf_ , r.buf_ ); 172 : } 173 : 174 : 175 : void intrusive_ptr_add_ref(SmpClass* p) { p->incRef(); } 176 : void intrusive_ptr_release(SmpClass* p) { p->decRef_and_release(); } 177 : 178 : 179 : 180 : template<> 181 : SmpClass random<SmpClass>() { 182 : char name[128]; 183 : sprintf(name, "%c%c%d", 'A'+rand()%26,'a'+rand()%26,'a'+rand()%26, rand()); 184 : return SmpClass(name, rand(), rand(), rand()); 185 : } 186 : 187 : 188 : 189 : #define TYPE SmpClass 190 : #endif 191 : 192 : 193 : 194 : // =========================================================================== 195 : 196 : template<typename T> 197 : struct ptr_less { 198 : bool operator()(T l, T r) const { 199 : return *l < *r; 200 : } 201 : }; 202 : 203 : 204 : 205 : // vector<T>に確保したデータを その要素へのポインタの配列を作ってソート. 206 : template<typename T> 207 : double benchmark1(unsigned size, unsigned count=1, int seed=1) { 208 : srand(seed); 209 : PerfCnt_tick_t elapsed = 0; 210 : for (unsigned j = 0; j < count; ++j) { 211 : std::vector<T> data; 212 : for (unsigned i = 0; i < size; ++i) 213 : data.push_back(random<T>()); 214 : 215 : PerfCnt_tick_t start_time = PerfCnt_getTick(); 216 : std::vector<T*> ent(size); 217 : typename std::vector<T*>::iterator vi = ent.begin(); 218 : for (typename std::vector<T>::iterator li = data.begin(); li != data.end(); ++li) { 219 : *vi = &*li; 220 : ++vi; 221 : } 222 : quick_sort(ent.begin(), ent.end(), ptr_less<T*>() ); 223 : elapsed += PerfCnt_getTick() - start_time; 224 : 225 : for (unsigned i = 0; i < size-1; ++i) { // ソート状態 チェック. 226 : if (*ent[i+1] < *ent[i]) 227 : printf("error %d : > \n", i); 228 : } 229 : } 230 : return elapsed * 1.0 / (PerfCnt_tickPerSec() * count); 231 : //printf("%s:%13.3fμ秒\n", name, elapsed * 1000000.0 / (PerfCnt_tickPerSec() * count)); 232 : } 233 : 234 : 235 : // vector をソート 236 : template<typename T> 237 : double benchmark2(unsigned size, unsigned count=1, int seed=1) { 238 : srand(seed); 239 : PerfCnt_tick_t elapsed = 0; 240 : for (unsigned j = 0; j < count; ++j) { 241 : std::vector<T> data; 242 : data.reserve(size); 243 : for (unsigned i = 0; i < size; ++i) 244 : data.push_back(random<T>()); 245 : PerfCnt_tick_t start_time = PerfCnt_getTick(); 246 : quick_sort(data.begin(), data.end() ); 247 : elapsed += PerfCnt_getTick() - start_time; 248 : 249 : for (unsigned i = 0; i < size-1; ++i) { // ソート状態 チェック. 250 : if (data[i+1] < data[i]) 251 : printf("error %d : > \n", i); 252 : } 253 : } 254 : return elapsed * 1.0 / (PerfCnt_tickPerSec() * count); 255 : } 256 : 257 : 258 : 259 : // vector<T>に確保したデータを その要素へのポインタの配列を作ってソートし、それを基にvector<T>データを再構築. 260 : template<typename T> 261 : double benchmark3(unsigned size, unsigned count=1, int seed=1) { 262 : srand(seed); 263 : PerfCnt_tick_t elapsed = 0; 264 : for (unsigned j = 0; j < count; ++j) { 265 : std::vector<T> data; 266 : data.reserve( size ); 267 : for (unsigned i = 0; i < size; ++i) 268 : data.push_back(random<T>()); 269 : 270 : PerfCnt_tick_t start_time = PerfCnt_getTick(); 271 : { 272 : std::vector<T*> ent(size); 273 : typename std::vector<T*>::iterator vi = ent.begin(); 274 : for (typename std::vector<T>::iterator it = data.begin(); it != data.end(); ++it) { 275 : *vi = &*it; 276 : ++vi; 277 : } 278 : quick_sort(ent.begin(), ent.end(), ptr_less<T*>() ); 279 : std::vector<T> data2; 280 : data2.reserve( size ); 281 : for (unsigned i = 0; i < size; ++i) 282 : data2.push_back( *ent[i] ); 283 : std::swap(data, data2); 284 : } 285 : elapsed += PerfCnt_getTick() - start_time; 286 : 287 : for (unsigned i = 0; i < size-1; ++i) { // ソート状態 チェック. 288 : if (data[i+1] < data[i]) 289 : printf("error %d : > \n", i); 290 : } 291 : } 292 : return elapsed * 1.0 / (PerfCnt_tickPerSec() * count); 293 : } 294 : 295 : 296 : 297 : // スマートポインタのvectorをソート. 298 : template<typename T> 299 : double benchmark4(unsigned size, unsigned count=1, int seed=1) { 300 : srand(seed); 301 : PerfCnt_tick_t elapsed = 0; 302 : for (unsigned j = 0; j < count; ++j) { 303 : typedef shared_ptr<T> T_ptr; 304 : std::vector< T_ptr > data; 305 : data.reserve( size ); 306 : for (unsigned i = 0; i < size; ++i) 307 : data.push_back( T_ptr( new T( random<T>() ) ) ); 308 : 309 : PerfCnt_tick_t start_time = PerfCnt_getTick(); 310 : quick_sort(data.begin(), data.end(), ptr_less<T_ptr>() ); 311 : elapsed += PerfCnt_getTick() - start_time; 312 : 313 : for (unsigned i = 0; i < size-1; ++i) { // ソート状態 チェック. 314 : if (*data[i+1] < *data[i]) 315 : printf("error %d : > \n", i); 316 : } 317 : } 318 : return elapsed * 1.0 / (PerfCnt_tickPerSec() * count); 319 : } 320 : 321 : 322 : #ifdef USE_SMPCLASS 323 : // intrusive_ptrのvectorをソート. 324 : template<typename T> 325 : double benchmark5(unsigned size, unsigned count=1, int seed=1) { 326 : srand(seed); 327 : PerfCnt_tick_t elapsed = 0; 328 : for (unsigned j = 0; j < count; ++j) { 329 : typedef boost::intrusive_ptr<T> T_ptr; 330 : std::vector< T_ptr > data; 331 : data.reserve( size ); 332 : for (unsigned i = 0; i < size; ++i) 333 : data.push_back( T_ptr( new T( random<T>() ) ) ); 334 : 335 : PerfCnt_tick_t start_time = PerfCnt_getTick(); 336 : quick_sort(data.begin(), data.end(), ptr_less<T_ptr>() ); 337 : elapsed += PerfCnt_getTick() - start_time; 338 : 339 : for (unsigned i = 0; i < size-1; ++i) { // ソート状態 チェック. 340 : if (*data[i+1] < *data[i]) 341 : printf("error %d : > \n", i); 342 : } 343 : } 344 : return elapsed * 1.0 / (PerfCnt_tickPerSec() * count); 345 : } 346 : 347 : 348 : // vector<T>に確保したデータを その要素へのポインタの配列を作ってソートし、それを基にvector<T>データを再構築. 349 : template<typename T> 350 : double benchmark6(unsigned size, unsigned count=1, int seed=1) { 351 : srand(seed); 352 : PerfCnt_tick_t elapsed = 0; 353 : for (unsigned j = 0; j < count; ++j) { 354 : typedef boost::intrusive_ptr<T> T_ptr; 355 : std::vector< T_ptr > data; 356 : data.reserve( size ); 357 : for (unsigned i = 0; i < size; ++i) 358 : data.push_back( T_ptr( new T( random<T>() ) ) ); 359 : 360 : PerfCnt_tick_t start_time = PerfCnt_getTick(); 361 : { 362 : std::vector<T*> ent(size); 363 : typename std::vector<T*>::iterator vi = ent.begin(); 364 : for (typename std::vector<T_ptr>::iterator it = data.begin(); it != data.end(); ++it) { 365 : *vi = it->get(); 366 : ++vi; 367 : } 368 : quick_sort(ent.begin(), ent.end(), ptr_less<T*>() ); 369 : { 370 : std::vector<T_ptr> data2; 371 : data2.reserve( size ); 372 : for (unsigned i = 0; i < size; ++i) 373 : data2.push_back( T_ptr(ent[i]) ); 374 : std::swap(data, data2); 375 : } 376 : } 377 : elapsed += PerfCnt_getTick() - start_time; 378 : 379 : for (unsigned i = 0; i < size; ++i) { // 参照数が誤ってないかチェック. 380 : if (data[i]->ref_count() != 1) 381 : printf("error %d\n", i); 382 : } 383 : for (unsigned i = 0; i < size-1; ++i) { // ソート状態 チェック. 384 : if (*data[i+1] < *data[i]) 385 : printf("error %d : > \n", i); 386 : } 387 : } 388 : return elapsed * 1.0 / (PerfCnt_tickPerSec() * count); 389 : } 390 : #endif 391 : 392 : 393 : 394 : #ifndef TYPE 395 : #define TYPE int 396 : #endif 397 : 398 : struct St { 399 : size_t size; 400 : size_t count; 401 : double elaped[6]; 402 : }; 403 : 404 : // 405 : int main(int argc, char **argv) { 406 : if (argc < 2) { 407 : printf("usage> sort_test4 size1 count1 [size2 count2 ...]\n"); 408 : return 1; 409 : } 410 : std::vector<St> st; 411 : unsigned n = 0; 412 : for (unsigned i = 1; i < argc; i += 2) { 413 : St t; 414 : t.size = atoi(argv[i]); 415 : t.count = (i+1 < argc) ? atoi(argv[i+1]) : 1; 416 : std::fill(t.elaped, t.elaped+6, 0.0); 417 : st.push_back(t); 418 : ++n; 419 : } 420 : printf("\nsort_test4 : sizeof(TYPE)=%dbytes\n", sizeof(TYPE)); 421 : int seed = 1; //time(0); 422 : for (unsigned i = 0; i < n; ++i) { 423 : St& t = st[i]; 424 : printf("個数 %9d, 処理回数 %9d\n", t.size, t.count); 425 : t.elaped[0] = benchmark1<TYPE>(t.size, t.count, seed); // "vector要素へのポインタのvectorのみをsort " 426 : t.elaped[1] = benchmark2<TYPE>(t.size, t.count, seed); // "vectorを sort " 427 : t.elaped[2] = benchmark3<TYPE>(t.size, t.count, seed); // "ポインタでソートして、その結果でvector再構築 " 428 : t.elaped[3] = benchmark4<TYPE>(t.size, t.count, seed); // "shared_ptrのvectorを sort " 429 : #ifdef USE_SMPCLASS 430 : t.elaped[4] = benchmark5<TYPE>(t.size, t.count, seed); // "intrusive_ptrのvectorを sort " 431 : t.elaped[5] = benchmark6<TYPE>(t.size, t.count, seed); // "intrusive_ptrのvectorを生ポインタソートで再構築" 432 : #endif 433 : } 434 : 435 : // 結果表示. 436 : static const char* ttl[] = { 437 : "vector要素へのポインタのvectorのみをsort ", // 1 438 : "vectorを sort ", // 2 439 : "ポインタでソートして、その結果でvector再構築 ", // 3 440 : "shared_ptrのvectorを sort ", // 4 441 : #ifdef USE_SMPCLASS 442 : "intrusive_ptrのvectorを sort ", // 5 443 : "intrusive_ptrのvectorを生ポインタソートで再構築", // 6 444 : #endif 445 : NULL, 446 : }; 447 : printf("\n"); 448 : printf("%47s ,", "個数"); 449 : for (unsigned i = 0; i < n; ++i) { 450 : printf("%9d個,", st[i].size); 451 : }; 452 : printf("\n"); 453 : for (unsigned j = 0; ttl[j]; ++j) { 454 : printf("%-47s ,", ttl[j]); 455 : for (unsigned i = 0; i < n; ++i) { 456 : printf("%11.3f,", st[i].elaped[j]*1000000.0); 457 : }; 458 : printf("\n"); 459 : } 460 : return 0; 461 : }