Stxxl
1.4.0
|
00001 /*************************************************************************** 00002 * include/stxxl/bits/algo/ksort.h 00003 * 00004 * Part of the STXXL. See http://stxxl.sourceforge.net 00005 * 00006 * Copyright (C) 2002 Roman Dementiev <dementiev@mpi-sb.mpg.de> 00007 * Copyright (C) 2008-2011 Andreas Beckmann <beckmann@cs.uni-frankfurt.de> 00008 * 00009 * Distributed under the Boost Software License, Version 1.0. 00010 * (See accompanying file LICENSE_1_0.txt or copy at 00011 * http://www.boost.org/LICENSE_1_0.txt) 00012 **************************************************************************/ 00013 00014 #ifndef STXXL_KSORT_HEADER 00015 #define STXXL_KSORT_HEADER 00016 00017 #include <stxxl/bits/mng/mng.h> 00018 #include <stxxl/bits/common/rand.h> 00019 #include <stxxl/bits/mng/adaptor.h> 00020 #include <stxxl/bits/common/simple_vector.h> 00021 #include <stxxl/bits/common/switch.h> 00022 #include <stxxl/bits/mng/block_alloc_interleaved.h> 00023 #include <stxxl/bits/algo/intksort.h> 00024 #include <stxxl/bits/algo/adaptor.h> 00025 #include <stxxl/bits/algo/async_schedule.h> 00026 #include <stxxl/bits/mng/block_prefetcher.h> 00027 #include <stxxl/bits/mng/buf_writer.h> 00028 #include <stxxl/bits/algo/run_cursor.h> 00029 #include <stxxl/bits/algo/losertree.h> 00030 #include <stxxl/bits/algo/inmemsort.h> 00031 #include <stxxl/bits/algo/sort_base.h> 00032 #include <stxxl/bits/common/is_sorted.h> 00033 #include <stxxl/bits/common/utils.h> 00034 00035 00036 //#define INTERLEAVED_ALLOC 00037 00038 #define OPT_MERGING 00039 00040 __STXXL_BEGIN_NAMESPACE 00041 00042 //! \weakgroup stllayer STL-user layer 00043 //! Layer which groups STL compatible algorithms and containers 00044 00045 //! \weakgroup stlalgo Algorithms 00046 //! \ingroup stllayer 00047 //! Algorithms with STL-compatible interface 00048 //! \{ 00049 00050 /*! \internal 00051 */ 00052 namespace ksort_local 00053 { 00054 template <typename _BIDTp, typename _KeyTp> 00055 struct trigger_entry 00056 { 00057 typedef _BIDTp bid_type; 00058 typedef _KeyTp key_type; 00059 00060 bid_type bid; 00061 key_type key; 00062 00063 operator bid_type () 00064 { 00065 return bid; 00066 } 00067 }; 00068 00069 00070 template <typename _BIDTp, typename _KeyTp> 00071 inline bool operator < (const trigger_entry<_BIDTp, _KeyTp> & a, 00072 const trigger_entry<_BIDTp, _KeyTp> & b) 00073 { 00074 return (a.key < b.key); 00075 } 00076 00077 template <typename _BIDTp, typename _KeyTp> 00078 inline bool operator > (const trigger_entry<_BIDTp, _KeyTp> & a, 00079 const trigger_entry<_BIDTp, _KeyTp> & b) 00080 { 00081 return (a.key > b.key); 00082 } 00083 00084 template <typename type, typename key_type1> 00085 struct type_key 00086 { 00087 typedef key_type1 key_type; 00088 key_type key; 00089 type * ptr; 00090 00091 type_key() { } 00092 type_key(key_type k, type * p) : key(k), ptr(p) 00093 { } 00094 }; 00095 00096 template <typename type, typename key1> 00097 bool operator < (const type_key<type, key1> & a, const type_key<type, key1> & b) 00098 { 00099 return a.key < b.key; 00100 } 00101 00102 template <typename type, typename key1> 00103 bool operator > (const type_key<type, key1> & a, const type_key<type, key1> & b) 00104 { 00105 return a.key > b.key; 00106 } 00107 00108 00109 template <typename block_type, typename bid_type> 00110 struct write_completion_handler 00111 { 00112 block_type * block; 00113 bid_type bid; 00114 request_ptr * req; 00115 void operator () (request * /*completed_req*/) 00116 { 00117 * req = block->read(bid); 00118 } 00119 }; 00120 00121 template <typename type_key_, 00122 typename block_type, 00123 typename run_type, 00124 typename input_bid_iterator, 00125 typename key_extractor> 00126 inline void write_out( 00127 type_key_ * begin, 00128 type_key_ * end, 00129 block_type * & cur_blk, 00130 const block_type * end_blk, 00131 int_type & out_block, 00132 int_type & out_pos, 00133 run_type & run, 00134 write_completion_handler<block_type, typename block_type::bid_type> * & next_read, 00135 typename block_type::bid_type * & bids, 00136 request_ptr * write_reqs, 00137 request_ptr * read_reqs, 00138 input_bid_iterator & it, 00139 key_extractor keyobj) 00140 { 00141 typedef typename block_type::bid_type bid_type; 00142 typedef typename block_type::type type; 00143 00144 type * elem = cur_blk->elem; 00145 for (type_key_ * p = begin; p < end; p++) 00146 { 00147 elem[out_pos++] = *(p->ptr); 00148 00149 if (out_pos >= block_type::size) 00150 { 00151 run[out_block].key = keyobj(*(cur_blk->elem)); 00152 00153 if (cur_blk < end_blk) 00154 { 00155 next_read->block = cur_blk; 00156 next_read->req = read_reqs + out_block; 00157 read_reqs[out_block] = NULL; 00158 bids[out_block] = next_read->bid = *(it++); 00159 00160 write_reqs[out_block] = cur_blk->write( 00161 run[out_block].bid, 00162 // postpone read of block from next run 00163 // after write of block from this run 00164 *(next_read++)); 00165 } 00166 else 00167 { 00168 write_reqs[out_block] = cur_blk->write(run[out_block].bid); 00169 } 00170 00171 cur_blk++; 00172 elem = cur_blk->elem; 00173 out_block++; 00174 out_pos = 0; 00175 } 00176 } 00177 } 00178 00179 template < 00180 typename block_type, 00181 typename run_type, 00182 typename input_bid_iterator, 00183 typename key_extractor> 00184 void 00185 create_runs( 00186 input_bid_iterator it, 00187 run_type ** runs, 00188 const unsigned_type nruns, 00189 const unsigned_type m2, 00190 key_extractor keyobj) 00191 { 00192 typedef typename block_type::value_type type; 00193 typedef typename block_type::bid_type bid_type; 00194 typedef typename key_extractor::key_type key_type; 00195 typedef type_key<type, key_type> type_key_; 00196 00197 block_manager * bm = block_manager::get_instance(); 00198 block_type * Blocks1 = new block_type[m2]; 00199 block_type * Blocks2 = new block_type[m2]; 00200 bid_type * bids = new bid_type[m2]; 00201 type_key_ * refs1 = new type_key_[m2 * Blocks1->size]; 00202 type_key_ * refs2 = new type_key_[m2 * Blocks1->size]; 00203 request_ptr * read_reqs = new request_ptr[m2]; 00204 request_ptr * write_reqs = new request_ptr[m2]; 00205 write_completion_handler<block_type, bid_type> * next_run_reads = 00206 new write_completion_handler<block_type, bid_type>[m2]; 00207 00208 run_type * run; 00209 run = *runs; 00210 int_type run_size = (*runs)->size(); 00211 key_type offset = 0; 00212 const int log_k1 = log2_ceil((m2 * block_type::size * sizeof(type_key_) / STXXL_L2_SIZE) ? 00213 (m2 * block_type::size * sizeof(type_key_) / STXXL_L2_SIZE) : 2); 00214 const int log_k2 = log2_floor(m2 * Blocks1->size) - log_k1 - 1; 00215 STXXL_VERBOSE("log_k1: " << log_k1 << " log_k2:" << log_k2); 00216 const int_type k1 = 1 << log_k1; 00217 const int_type k2 = 1 << log_k2; 00218 int_type * bucket1 = new int_type[k1]; 00219 int_type * bucket2 = new int_type[k2]; 00220 int_type i; 00221 00222 disk_queues::get_instance()->set_priority_op(request_queue::WRITE); 00223 00224 for (i = 0; i < run_size; i++) 00225 { 00226 bids[i] = *(it++); 00227 read_reqs[i] = Blocks1[i].read(bids[i]); 00228 } 00229 00230 unsigned_type k = 0; 00231 const int shift1 = sizeof(key_type) * 8 - log_k1; 00232 const int shift2 = shift1 - log_k2; 00233 STXXL_VERBOSE("shift1: " << shift1 << " shift2:" << shift2); 00234 00235 for ( ; k < nruns; k++) 00236 { 00237 run = runs[k]; 00238 run_size = run->size(); 00239 00240 std::fill(bucket1, bucket1 + k1, 0); 00241 00242 type_key_ * ref_ptr = refs1; 00243 for (i = 0; i < run_size; i++) 00244 { 00245 if (k) 00246 write_reqs[i]->wait(); 00247 00248 read_reqs[i]->wait(); 00249 bm->delete_block(bids[i]); 00250 00251 classify_block(Blocks1[i].begin(), Blocks1[i].end(), ref_ptr, bucket1, offset, shift1, keyobj); 00252 } 00253 00254 exclusive_prefix_sum(bucket1, k1); 00255 classify(refs1, refs1 + run_size * Blocks1->size, refs2, bucket1, 00256 offset, shift1); 00257 00258 int_type out_block = 0; 00259 int_type out_pos = 0; 00260 unsigned_type next_run_size = (k < nruns - 1) ? (runs[k + 1]->size()) : 0; 00261 00262 // recurse on each bucket 00263 type_key_ * c = refs2; 00264 type_key_ * d = refs1; 00265 block_type * cur_blk = Blocks2; 00266 block_type * end_blk = Blocks2 + next_run_size; 00267 write_completion_handler<block_type, bid_type> * next_read = next_run_reads; 00268 00269 for (i = 0; i < k1; i++) 00270 { 00271 type_key_ * cEnd = refs2 + bucket1[i]; 00272 type_key_ * dEnd = refs1 + bucket1[i]; 00273 00274 l1sort(c, cEnd, d, bucket2, k2, 00275 offset + (key_type(1) << key_type(shift1)) * key_type(i), shift2); // key_type,key_type,... paranoia 00276 00277 write_out( 00278 d, dEnd, cur_blk, end_blk, 00279 out_block, out_pos, *run, next_read, bids, 00280 write_reqs, read_reqs, it, keyobj); 00281 00282 c = cEnd; 00283 d = dEnd; 00284 } 00285 00286 std::swap(Blocks1, Blocks2); 00287 } 00288 00289 wait_all(write_reqs, m2); 00290 00291 delete[] bucket1; 00292 delete[] bucket2; 00293 delete[] refs1; 00294 delete[] refs2; 00295 delete[] Blocks1; 00296 delete[] Blocks2; 00297 delete[] bids; 00298 delete[] next_run_reads; 00299 delete[] read_reqs; 00300 delete[] write_reqs; 00301 } 00302 00303 template <typename block_type, 00304 typename prefetcher_type, 00305 typename key_extractor> 00306 struct run_cursor2_cmp : public std::binary_function<run_cursor2<block_type, prefetcher_type>, run_cursor2<block_type, prefetcher_type>, bool> 00307 { 00308 typedef run_cursor2<block_type, prefetcher_type> cursor_type; 00309 key_extractor keyobj; 00310 run_cursor2_cmp(key_extractor keyobj_) 00311 { 00312 keyobj = keyobj_; 00313 } 00314 inline bool operator () (const cursor_type & a, const cursor_type & b) const 00315 { 00316 if (UNLIKELY(b.empty())) 00317 return true; 00318 // sentinel emulation 00319 if (UNLIKELY(a.empty())) 00320 return false; 00321 //sentinel emulation 00322 00323 return (keyobj(a.current()) < keyobj(b.current())); 00324 } 00325 00326 private: 00327 run_cursor2_cmp() { } 00328 }; 00329 00330 00331 template <typename record_type, typename key_extractor> 00332 class key_comparison : public std::binary_function<record_type, record_type, bool> 00333 { 00334 key_extractor ke; 00335 00336 public: 00337 key_comparison() { } 00338 key_comparison(key_extractor ke_) : ke(ke_) { } 00339 bool operator () (const record_type & a, const record_type & b) const 00340 { 00341 return ke(a) < ke(b); 00342 } 00343 }; 00344 00345 00346 template <typename block_type, typename run_type, typename key_ext_> 00347 bool check_ksorted_runs(run_type ** runs, 00348 unsigned_type nruns, 00349 unsigned_type m, 00350 key_ext_ keyext) 00351 { 00352 typedef typename block_type::value_type value_type; 00353 00354 STXXL_MSG("check_ksorted_runs Runs: " << nruns); 00355 unsigned_type irun = 0; 00356 for (irun = 0; irun < nruns; ++irun) 00357 { 00358 const unsigned_type nblocks_per_run = runs[irun]->size(); 00359 unsigned_type blocks_left = nblocks_per_run; 00360 block_type * blocks = new block_type[m]; 00361 request_ptr * reqs = new request_ptr[m]; 00362 value_type last = keyext.min_value(); 00363 00364 for (unsigned_type off = 0; off < nblocks_per_run; off += m) 00365 { 00366 const unsigned_type nblocks = STXXL_MIN(blocks_left, m); 00367 const unsigned_type nelements = nblocks * block_type::size; 00368 blocks_left -= nblocks; 00369 00370 for (unsigned_type j = 0; j < nblocks; ++j) 00371 { 00372 reqs[j] = blocks[j].read((*runs[irun])[off + j].bid); 00373 } 00374 wait_all(reqs, reqs + nblocks); 00375 00376 if (off && (keyext(blocks[0][0]) < keyext(last))) 00377 { 00378 STXXL_MSG("check_sorted_runs wrong first value in the run " << irun); 00379 STXXL_MSG(" first value: " << blocks[0][0] << " with key" << keyext(blocks[0][0])); 00380 STXXL_MSG(" last value: " << last << " with key" << keyext(last)); 00381 for (unsigned_type k = 0; k < block_type::size; ++k) 00382 STXXL_MSG("Element " << k << " in the block is :" << blocks[0][k] << " key: " << keyext(blocks[0][k])); 00383 return false; 00384 } 00385 00386 for (unsigned_type j = 0; j < nblocks; ++j) 00387 { 00388 if (keyext(blocks[j][0]) != (*runs[irun])[off + j].key) 00389 { 00390 STXXL_MSG("check_sorted_runs wrong trigger in the run " << irun << " block " << (off + j)); 00391 STXXL_MSG(" trigger value: " << (*runs[irun])[off + j].key); 00392 STXXL_MSG("Data in the block:"); 00393 for (unsigned_type k = 0; k < block_type::size; ++k) 00394 STXXL_MSG("Element " << k << " in the block is :" << blocks[j][k] << " with key: " << keyext(blocks[j][k])); 00395 00396 STXXL_MSG("BIDS:"); 00397 for (unsigned_type k = 0; k < nblocks; ++k) 00398 { 00399 if (k == j) 00400 STXXL_MSG("Bad one comes next."); 00401 STXXL_MSG("BID " << (off + k) << " is: " << ((*runs[irun])[off + k].bid)); 00402 } 00403 00404 return false; 00405 } 00406 } 00407 if (!stxxl::is_sorted(make_element_iterator(blocks, 0), 00408 make_element_iterator(blocks, nelements), 00409 key_comparison<value_type, key_ext_>())) 00410 { 00411 STXXL_MSG("check_sorted_runs wrong order in the run " << irun); 00412 STXXL_MSG("Data in blocks:"); 00413 for (unsigned_type j = 0; j < nblocks; ++j) 00414 { 00415 for (unsigned_type k = 0; k < block_type::size; ++k) 00416 STXXL_MSG(" Element " << k << " in block " << (off + j) << " is :" << blocks[j][k] << " with key: " << keyext(blocks[j][k])); 00417 } 00418 STXXL_MSG("BIDS:"); 00419 for (unsigned_type k = 0; k < nblocks; ++k) 00420 { 00421 STXXL_MSG("BID " << (k + off) << " is: " << ((*runs[irun])[k + off].bid)); 00422 } 00423 00424 return false; 00425 } 00426 last = blocks[nblocks - 1][block_type::size - 1]; 00427 } 00428 00429 assert(blocks_left == 0); 00430 delete[] reqs; 00431 delete[] blocks; 00432 } 00433 00434 return true; 00435 } 00436 00437 00438 template <typename block_type, typename run_type, typename key_extractor> 00439 void merge_runs(run_type ** in_runs, unsigned_type nruns, run_type * out_run, unsigned_type _m, key_extractor keyobj) 00440 { 00441 typedef block_prefetcher<block_type, typename run_type::iterator> prefetcher_type; 00442 typedef run_cursor2<block_type, prefetcher_type> run_cursor_type; 00443 00444 unsigned_type i; 00445 run_type consume_seq(out_run->size()); 00446 00447 int_type * prefetch_seq = new int_type[out_run->size()]; 00448 00449 typename run_type::iterator copy_start = consume_seq.begin(); 00450 for (i = 0; i < nruns; i++) 00451 { 00452 // TODO: try to avoid copy 00453 copy_start = std::copy( 00454 in_runs[i]->begin(), 00455 in_runs[i]->end(), 00456 copy_start); 00457 } 00458 std::stable_sort(consume_seq.begin(), consume_seq.end() _STXXL_SORT_TRIGGER_FORCE_SEQUENTIAL); 00459 00460 unsigned disks_number = config::get_instance()->disks_number(); 00461 00462 #ifdef PLAY_WITH_OPT_PREF 00463 const int_type n_write_buffers = 4 * disks_number; 00464 #else 00465 const int_type n_prefetch_buffers = STXXL_MAX(int_type(2 * disks_number), (3 * (int_type(_m) - int_type(nruns)) / 4)); 00466 STXXL_VERBOSE("Prefetch buffers " << n_prefetch_buffers); 00467 const int_type n_write_buffers = STXXL_MAX(int_type(2 * disks_number), int_type(_m) - int_type(nruns) - int_type(n_prefetch_buffers)); 00468 STXXL_VERBOSE("Write buffers " << n_write_buffers); 00469 // heuristic 00470 const int_type n_opt_prefetch_buffers = 2 * int_type(disks_number) + (3 * (int_type(n_prefetch_buffers) - int_type(2 * disks_number))) / 10; 00471 STXXL_VERBOSE("Prefetch buffers " << n_opt_prefetch_buffers); 00472 #endif 00473 00474 #if STXXL_SORT_OPTIMAL_PREFETCHING 00475 compute_prefetch_schedule( 00476 consume_seq, 00477 prefetch_seq, 00478 n_opt_prefetch_buffers, 00479 disks_number); 00480 #else 00481 for (i = 0; i < out_run->size(); i++) 00482 prefetch_seq[i] = i; 00483 00484 #endif 00485 00486 00487 prefetcher_type prefetcher(consume_seq.begin(), 00488 consume_seq.end(), 00489 prefetch_seq, 00490 nruns + n_prefetch_buffers); 00491 00492 buffered_writer<block_type> writer(n_write_buffers, n_write_buffers / 2); 00493 00494 unsigned_type out_run_size = out_run->size(); 00495 00496 run_cursor2_cmp<block_type, prefetcher_type, key_extractor> cmp(keyobj); 00497 loser_tree< 00498 run_cursor_type, 00499 run_cursor2_cmp<block_type, prefetcher_type, key_extractor> > 00500 losers(&prefetcher, nruns, cmp); 00501 00502 block_type * out_buffer = writer.get_free_block(); 00503 00504 for (i = 0; i < out_run_size; i++) 00505 { 00506 losers.multi_merge(out_buffer->elem, out_buffer->elem + block_type::size); 00507 (*out_run)[i].key = keyobj(out_buffer->elem[0]); 00508 out_buffer = writer.write(out_buffer, (*out_run)[i].bid); 00509 } 00510 00511 delete[] prefetch_seq; 00512 00513 block_manager * bm = block_manager::get_instance(); 00514 for (i = 0; i < nruns; i++) 00515 { 00516 unsigned_type sz = in_runs[i]->size(); 00517 for (unsigned_type j = 0; j < sz; j++) 00518 bm->delete_block((*in_runs[i])[j].bid); 00519 00520 delete in_runs[i]; 00521 } 00522 } 00523 00524 00525 template <typename block_type, 00526 typename alloc_strategy, 00527 typename input_bid_iterator, 00528 typename key_extractor> 00529 00530 simple_vector<trigger_entry<typename block_type::bid_type, typename key_extractor::key_type> > * 00531 ksort_blocks(input_bid_iterator input_bids, unsigned_type _n, unsigned_type _m, key_extractor keyobj) 00532 { 00533 typedef typename block_type::value_type type; 00534 typedef typename key_extractor::key_type key_type; 00535 typedef typename block_type::bid_type bid_type; 00536 typedef trigger_entry<bid_type, typename key_extractor::key_type> trigger_entry_type; 00537 typedef simple_vector<trigger_entry_type> run_type; 00538 typedef typename interleaved_alloc_traits<alloc_strategy>::strategy interleaved_alloc_strategy; 00539 00540 unsigned_type m2 = div_ceil(_m, 2); 00541 const unsigned_type m2_rf = m2 * block_type::raw_size / 00542 (block_type::raw_size + block_type::size * sizeof(type_key<type, key_type>)); 00543 STXXL_VERBOSE("Reducing number of blocks in a run from " << m2 << " to " << 00544 m2_rf << " due to key size: " << sizeof(typename key_extractor::key_type) << " bytes"); 00545 m2 = m2_rf; 00546 unsigned_type full_runs = _n / m2; 00547 unsigned_type partial_runs = ((_n % m2) ? 1 : 0); 00548 unsigned_type nruns = full_runs + partial_runs; 00549 unsigned_type i; 00550 00551 block_manager * mng = block_manager::get_instance(); 00552 00553 STXXL_VERBOSE("n=" << _n << " nruns=" << nruns << "=" << full_runs << "+" << partial_runs); 00554 00555 double begin = timestamp(), after_runs_creation, end; 00556 00557 run_type ** runs = new run_type *[nruns]; 00558 00559 for (i = 0; i < full_runs; i++) 00560 runs[i] = new run_type(m2); 00561 00562 00563 #ifdef INTERLEAVED_ALLOC 00564 if (partial_runs) 00565 { 00566 unsigned_type last_run_size = _n - full_runs * m2; 00567 runs[i] = new run_type(last_run_size); 00568 00569 mng->new_blocks(interleaved_alloc_strategy(nruns, alloc_strategy()), 00570 RunsToBIDArrayAdaptor2<block_type::raw_size, run_type> 00571 (runs, 0, nruns, last_run_size), 00572 RunsToBIDArrayAdaptor2<block_type::raw_size, run_type> 00573 (runs, _n, nruns, last_run_size)); 00574 } 00575 else 00576 mng->new_blocks(interleaved_alloc_strategy(nruns, alloc_strategy()), 00577 RunsToBIDArrayAdaptor<block_type::raw_size, run_type> 00578 (runs, 0, nruns), 00579 RunsToBIDArrayAdaptor<block_type::raw_size, run_type> 00580 (runs, _n, nruns)); 00581 00582 #else 00583 if (partial_runs) 00584 runs[i] = new run_type(_n - full_runs * m2); 00585 00586 for (i = 0; i < nruns; i++) 00587 { 00588 mng->new_blocks(alloc_strategy(), make_bid_iterator(runs[i]->begin()), make_bid_iterator(runs[i]->end())); 00589 } 00590 #endif 00591 00592 create_runs<block_type, 00593 run_type, 00594 input_bid_iterator, 00595 key_extractor>(input_bids, runs, nruns, m2, keyobj); 00596 00597 after_runs_creation = timestamp(); 00598 00599 double io_wait_after_rf = stats::get_instance()->get_io_wait_time(); 00600 00601 disk_queues::get_instance()->set_priority_op(request_queue::WRITE); 00602 00603 const int_type merge_factor = optimal_merge_factor(nruns, _m); 00604 run_type ** new_runs; 00605 00606 while (nruns > 1) 00607 { 00608 int_type new_nruns = div_ceil(nruns, merge_factor); 00609 STXXL_VERBOSE("Starting new merge phase: nruns: " << nruns << 00610 " opt_merge_factor: " << merge_factor << " m:" << _m << " new_nruns: " << new_nruns); 00611 00612 new_runs = new run_type *[new_nruns]; 00613 00614 int_type runs_left = nruns; 00615 int_type cur_out_run = 0; 00616 int_type blocks_in_new_run = 0; 00617 00618 while (runs_left > 0) 00619 { 00620 int_type runs2merge = STXXL_MIN(runs_left, merge_factor); 00621 blocks_in_new_run = 0; 00622 for (unsigned_type i = nruns - runs_left; i < (nruns - runs_left + runs2merge); i++) 00623 blocks_in_new_run += runs[i]->size(); 00624 00625 // allocate run 00626 new_runs[cur_out_run++] = new run_type(blocks_in_new_run); 00627 runs_left -= runs2merge; 00628 } 00629 // allocate blocks in the new runs 00630 if (cur_out_run == 1 && blocks_in_new_run == int_type(_n) && !input_bids->is_managed()) 00631 { 00632 // if we sort a file we can reuse the input bids for the output 00633 input_bid_iterator cur = input_bids; 00634 for (int_type i = 0; cur != (input_bids + _n); ++cur) 00635 { 00636 (*new_runs[0])[i++].bid = *cur; 00637 } 00638 00639 bid_type & firstBID = (*new_runs[0])[0].bid; 00640 if (firstBID.is_managed()) 00641 { 00642 // the first block does not belong to the file 00643 // need to reallocate it 00644 mng->new_block(FR(), firstBID); 00645 } 00646 bid_type & lastBID = (*new_runs[0])[_n - 1].bid; 00647 if (lastBID.is_managed()) 00648 { 00649 // the first block does not belong to the file 00650 // need to reallocate it 00651 mng->new_block(FR(), lastBID); 00652 } 00653 } 00654 else 00655 { 00656 mng->new_blocks(interleaved_alloc_strategy(new_nruns, alloc_strategy()), 00657 RunsToBIDArrayAdaptor2<block_type::raw_size, run_type>(new_runs, 0, new_nruns, blocks_in_new_run), 00658 RunsToBIDArrayAdaptor2<block_type::raw_size, run_type>(new_runs, _n, new_nruns, blocks_in_new_run)); 00659 } 00660 00661 00662 // merge all 00663 runs_left = nruns; 00664 cur_out_run = 0; 00665 while (runs_left > 0) 00666 { 00667 int_type runs2merge = STXXL_MIN(runs_left, merge_factor); 00668 #if STXXL_CHECK_ORDER_IN_SORTS 00669 assert((check_ksorted_runs<block_type, run_type, key_extractor>(runs + nruns - runs_left, runs2merge, m2, keyobj))); 00670 #endif 00671 STXXL_VERBOSE("Merging " << runs2merge << " runs"); 00672 merge_runs<block_type, run_type, key_extractor>(runs + nruns - runs_left, 00673 runs2merge, *(new_runs + (cur_out_run++)), _m, keyobj); 00674 runs_left -= runs2merge; 00675 } 00676 00677 nruns = new_nruns; 00678 delete[] runs; 00679 runs = new_runs; 00680 } 00681 00682 run_type * result = *runs; 00683 delete[] runs; 00684 00685 end = timestamp(); 00686 00687 STXXL_VERBOSE("Elapsed time : " << end - begin << " s. Run creation time: " << 00688 after_runs_creation - begin << " s"); 00689 STXXL_VERBOSE("Time in I/O wait(rf): " << io_wait_after_rf << " s"); 00690 STXXL_VERBOSE(*stats::get_instance()); 00691 STXXL_UNUSED(begin + after_runs_creation + end + io_wait_after_rf); 00692 00693 return result; 00694 } 00695 } 00696 00697 00698 /*! \page key_extractor Key extractor concept 00699 00700 Model of \b Key \b extractor concept must: 00701 - define type \b key_type , 00702 - provide \b operator() that returns key value of an object of user type 00703 - provide \b max_value method that returns a value that is \b strictly \b greater than all 00704 other objects of user type in respect to the key obtained by this key extractor , 00705 - provide \b min_value method that returns a value that is \b strictly \b less than all 00706 other objects of user type in respect to the key obtained by this key extractor , 00707 - operator > , operator <, operator == and operator != on type \b key_type must be defined. 00708 - \b Note: when using unsigned integral types as key, the value 0 cannot 00709 be used as a key value because it would 00710 conflict with the sentinel value returned by \b min_value 00711 00712 Example: extractor class \b GetWeight, that extracts weight from an \b Edge 00713 \verbatim 00714 00715 struct Edge 00716 { 00717 unsigned src,dest,weight; 00718 Edge(unsigned s,unsigned d,unsigned w):src(s),dest(d),weight(w){} 00719 }; 00720 00721 struct GetWeight 00722 { 00723 typedef unsigned key_type; 00724 key_type operator() (const Edge & e) const 00725 { 00726 return e.weight; 00727 } 00728 Edge min_value() const { return Edge(0,0,(std::numeric_limits<key_type>::min)()); }; 00729 Edge max_value() const { return Edge(0,0,(std::numeric_limits<key_type>::max)()); }; 00730 }; 00731 \endverbatim 00732 00733 */ 00734 00735 00736 //! \brief Sort records with integer keys 00737 //! \param first_ object of model of \c ext_random_access_iterator concept 00738 //! \param last_ object of model of \c ext_random_access_iterator concept 00739 //! \param keyobj \link key_extractor key extractor \endlink object 00740 //! \param M__ amount of memory for internal use (in bytes) 00741 //! \remark Order in the result is non-stable 00742 template <typename ExtIterator_, typename KeyExtractor_> 00743 void ksort(ExtIterator_ first_, ExtIterator_ last_, KeyExtractor_ keyobj, unsigned_type M__) 00744 { 00745 typedef simple_vector<ksort_local::trigger_entry<typename ExtIterator_::bid_type, 00746 typename KeyExtractor_::key_type> > run_type; 00747 typedef typename ExtIterator_::vector_type::value_type value_type; 00748 typedef typename ExtIterator_::block_type block_type; 00749 00750 00751 unsigned_type n = 0; 00752 block_manager * mng = block_manager::get_instance(); 00753 00754 first_.flush(); 00755 00756 if ((last_ - first_) * sizeof(value_type) < M__) 00757 { 00758 stl_in_memory_sort(first_, last_, ksort_local::key_comparison<value_type, KeyExtractor_>(keyobj)); 00759 } 00760 else 00761 { 00762 assert(2 * block_type::raw_size <= M__); 00763 00764 if (first_.block_offset()) 00765 { 00766 if (last_.block_offset()) // first and last element reside 00767 // not in the beginning of the block 00768 { 00769 typename ExtIterator_::block_type * first_block = new typename ExtIterator_::block_type; 00770 typename ExtIterator_::block_type * last_block = new typename ExtIterator_::block_type; 00771 typename ExtIterator_::bid_type first_bid, last_bid; 00772 request_ptr req; 00773 00774 req = first_block->read(*first_.bid()); 00775 mng->new_block(FR(), first_bid); // try to overlap 00776 mng->new_block(FR(), last_bid); 00777 req->wait(); 00778 00779 00780 req = last_block->read(*last_.bid()); 00781 00782 unsigned_type i = 0; 00783 for ( ; i < first_.block_offset(); i++) 00784 { 00785 first_block->elem[i] = keyobj.min_value(); 00786 } 00787 00788 req->wait(); 00789 00790 req = first_block->write(first_bid); 00791 for (i = last_.block_offset(); i < block_type::size; i++) 00792 { 00793 last_block->elem[i] = keyobj.max_value(); 00794 } 00795 00796 req->wait(); 00797 00798 req = last_block->write(last_bid); 00799 00800 n = last_.bid() - first_.bid() + 1; 00801 00802 std::swap(first_bid, *first_.bid()); 00803 std::swap(last_bid, *last_.bid()); 00804 00805 req->wait(); 00806 00807 delete first_block; 00808 delete last_block; 00809 00810 run_type * out = 00811 ksort_local::ksort_blocks< 00812 typename ExtIterator_::block_type, 00813 typename ExtIterator_::vector_type::alloc_strategy_type, 00814 typename ExtIterator_::bids_container_iterator, 00815 KeyExtractor_> 00816 (first_.bid(), n, M__ / block_type::raw_size, keyobj); 00817 00818 00819 first_block = new typename ExtIterator_::block_type; 00820 last_block = new typename ExtIterator_::block_type; 00821 typename ExtIterator_::block_type * sorted_first_block = new typename ExtIterator_::block_type; 00822 typename ExtIterator_::block_type * sorted_last_block = new typename ExtIterator_::block_type; 00823 request_ptr * reqs = new request_ptr[2]; 00824 00825 reqs[0] = first_block->read(first_bid); 00826 reqs[1] = sorted_first_block->read((*(out->begin())).bid); 00827 wait_all(reqs, 2); 00828 00829 reqs[0] = last_block->read(last_bid); 00830 reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid); 00831 00832 for (i = first_.block_offset(); i < block_type::size; i++) 00833 { 00834 first_block->elem[i] = sorted_first_block->elem[i]; 00835 } 00836 wait_all(reqs, 2); 00837 00838 req = first_block->write(first_bid); 00839 00840 for (i = 0; i < last_.block_offset(); i++) 00841 { 00842 last_block->elem[i] = sorted_last_block->elem[i]; 00843 } 00844 00845 req->wait(); 00846 00847 00848 req = last_block->write(last_bid); 00849 00850 mng->delete_block(out->begin()->bid); 00851 mng->delete_block((*out)[out->size() - 1].bid); 00852 00853 *first_.bid() = first_bid; 00854 *last_.bid() = last_bid; 00855 00856 typename run_type::iterator it = out->begin(); 00857 it++; 00858 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid(); 00859 cur_bid++; 00860 00861 for ( ; cur_bid != last_.bid(); cur_bid++, it++) 00862 { 00863 *cur_bid = (*it).bid; 00864 } 00865 00866 delete first_block; 00867 delete sorted_first_block; 00868 delete sorted_last_block; 00869 delete[] reqs; 00870 delete out; 00871 00872 req->wait(); 00873 00874 delete last_block; 00875 } 00876 else 00877 { 00878 // first element resides 00879 // not in the beginning of the block 00880 00881 typename ExtIterator_::block_type * first_block = new typename ExtIterator_::block_type; 00882 typename ExtIterator_::bid_type first_bid; 00883 request_ptr req; 00884 00885 req = first_block->read(*first_.bid()); 00886 mng->new_block(FR(), first_bid); // try to overlap 00887 req->wait(); 00888 00889 00890 unsigned_type i = 0; 00891 for ( ; i < first_.block_offset(); i++) 00892 { 00893 first_block->elem[i] = keyobj.min_value(); 00894 } 00895 00896 req = first_block->write(first_bid); 00897 00898 n = last_.bid() - first_.bid(); 00899 00900 std::swap(first_bid, *first_.bid()); 00901 00902 req->wait(); 00903 00904 delete first_block; 00905 00906 run_type * out = 00907 ksort_local::ksort_blocks< 00908 typename ExtIterator_::block_type, 00909 typename ExtIterator_::vector_type::alloc_strategy_type, 00910 typename ExtIterator_::bids_container_iterator, 00911 KeyExtractor_> 00912 (first_.bid(), n, M__ / block_type::raw_size, keyobj); 00913 00914 00915 first_block = new typename ExtIterator_::block_type; 00916 00917 typename ExtIterator_::block_type * sorted_first_block = new typename ExtIterator_::block_type; 00918 00919 request_ptr * reqs = new request_ptr[2]; 00920 00921 reqs[0] = first_block->read(first_bid); 00922 reqs[1] = sorted_first_block->read((*(out->begin())).bid); 00923 wait_all(reqs, 2); 00924 00925 for (i = first_.block_offset(); i < block_type::size; i++) 00926 { 00927 first_block->elem[i] = sorted_first_block->elem[i]; 00928 } 00929 00930 req = first_block->write(first_bid); 00931 00932 mng->delete_block(out->begin()->bid); 00933 00934 *first_.bid() = first_bid; 00935 00936 typename run_type::iterator it = out->begin(); 00937 it++; 00938 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid(); 00939 cur_bid++; 00940 00941 for ( ; cur_bid != last_.bid(); cur_bid++, it++) 00942 { 00943 *cur_bid = (*it).bid; 00944 } 00945 00946 *cur_bid = (*it).bid; 00947 00948 delete sorted_first_block; 00949 delete[] reqs; 00950 delete out; 00951 00952 req->wait(); 00953 00954 delete first_block; 00955 } 00956 } 00957 else 00958 { 00959 if (last_.block_offset()) // last element resides 00960 // not in the beginning of the block 00961 { 00962 typename ExtIterator_::block_type * last_block = new typename ExtIterator_::block_type; 00963 typename ExtIterator_::bid_type last_bid; 00964 request_ptr req; 00965 unsigned_type i; 00966 00967 req = last_block->read(*last_.bid()); 00968 mng->new_block(FR(), last_bid); 00969 req->wait(); 00970 00971 for (i = last_.block_offset(); i < block_type::size; i++) 00972 { 00973 last_block->elem[i] = keyobj.max_value(); 00974 } 00975 00976 req = last_block->write(last_bid); 00977 00978 n = last_.bid() - first_.bid() + 1; 00979 00980 std::swap(last_bid, *last_.bid()); 00981 00982 req->wait(); 00983 00984 delete last_block; 00985 00986 run_type * out = 00987 ksort_local::ksort_blocks< 00988 typename ExtIterator_::block_type, 00989 typename ExtIterator_::vector_type::alloc_strategy_type, 00990 typename ExtIterator_::bids_container_iterator, 00991 KeyExtractor_> 00992 (first_.bid(), n, M__ / block_type::raw_size, keyobj); 00993 00994 00995 last_block = new typename ExtIterator_::block_type; 00996 typename ExtIterator_::block_type * sorted_last_block = new typename ExtIterator_::block_type; 00997 request_ptr * reqs = new request_ptr[2]; 00998 00999 reqs[0] = last_block->read(last_bid); 01000 reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid); 01001 wait_all(reqs, 2); 01002 01003 for (i = 0; i < last_.block_offset(); i++) 01004 { 01005 last_block->elem[i] = sorted_last_block->elem[i]; 01006 } 01007 01008 req = last_block->write(last_bid); 01009 01010 mng->delete_block((*out)[out->size() - 1].bid); 01011 01012 *last_.bid() = last_bid; 01013 01014 typename run_type::iterator it = out->begin(); 01015 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid(); 01016 01017 for ( ; cur_bid != last_.bid(); cur_bid++, it++) 01018 { 01019 *cur_bid = (*it).bid; 01020 } 01021 01022 delete sorted_last_block; 01023 delete[] reqs; 01024 delete out; 01025 01026 req->wait(); 01027 01028 delete last_block; 01029 } 01030 else 01031 { 01032 // first and last element reside in the beginning of blocks 01033 n = last_.bid() - first_.bid(); 01034 01035 run_type * out = 01036 ksort_local::ksort_blocks< 01037 typename ExtIterator_::block_type, 01038 typename ExtIterator_::vector_type::alloc_strategy_type, 01039 typename ExtIterator_::bids_container_iterator, 01040 KeyExtractor_> 01041 (first_.bid(), n, M__ / block_type::raw_size, keyobj); 01042 01043 typename run_type::iterator it = out->begin(); 01044 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid(); 01045 01046 for ( ; cur_bid != last_.bid(); cur_bid++, it++) 01047 { 01048 *cur_bid = (*it).bid; 01049 } 01050 01051 delete out; 01052 } 01053 } 01054 } 01055 01056 #if STXXL_CHECK_ORDER_IN_SORTS 01057 typedef typename ExtIterator_::const_iterator const_iterator; 01058 assert(stxxl::is_sorted(const_iterator(first_), const_iterator(last_), 01059 ksort_local::key_comparison<value_type, KeyExtractor_>())); 01060 #endif 01061 } 01062 01063 template <typename record_type> 01064 struct ksort_defaultkey 01065 { 01066 typedef typename record_type::key_type key_type; 01067 key_type operator () (const record_type & obj) const 01068 { 01069 return obj.key(); 01070 } 01071 record_type max_value() const 01072 { 01073 return record_type::max_value(); 01074 } 01075 record_type min_value() const 01076 { 01077 return record_type::min_value(); 01078 } 01079 }; 01080 01081 01082 //! \brief Sort records with integer keys 01083 //! \param first_ object of model of \c ext_random_access_iterator concept 01084 //! \param last_ object of model of \c ext_random_access_iterator concept 01085 //! \param M__ amount of buffers for internal use 01086 //! \remark Order in the result is non-stable 01087 /*! 01088 Record's type must: 01089 - provide \b max_value method that returns an object that is \b greater than all 01090 other objects of user type , 01091 - provide \b min_value method that returns an object that is \b less than all 01092 other objects of user type , 01093 - \b operator \b < that must define strict weak ordering on record's values 01094 (<A HREF="http://www.sgi.com/tech/stl/StrictWeakOrdering.html">see what it is</A>). 01095 */ 01096 template <typename ExtIterator_> 01097 void ksort(ExtIterator_ first_, ExtIterator_ last_, unsigned_type M__) 01098 { 01099 ksort(first_, last_, 01100 ksort_defaultkey<typename ExtIterator_::vector_type::value_type>(), M__); 01101 } 01102 01103 01104 //! \} 01105 01106 __STXXL_END_NAMESPACE 01107 01108 #endif // !STXXL_KSORT_HEADER 01109 // vim: et:ts=4:sw=4