STXXL  1.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sort.h
Go to the documentation of this file.
1 /***************************************************************************
2  * include/stxxl/bits/algo/sort.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2002-2003 Roman Dementiev <[email protected]>
7  * Copyright (C) 2006 Johannes Singler <[email protected]>
8  * Copyright (C) 2008-2011 Andreas Beckmann <[email protected]>
9  * Copyright (C) 2013 Timo Bingmann <[email protected]>
10  *
11  * Distributed under the Boost Software License, Version 1.0.
12  * (See accompanying file LICENSE_1_0.txt or copy at
13  * http://www.boost.org/LICENSE_1_0.txt)
14  **************************************************************************/
15 
16 #ifndef STXXL_ALGO_SORT_HEADER
17 #define STXXL_ALGO_SORT_HEADER
18 
19 #include <functional>
20 
22 #include <stxxl/bits/common/rand.h>
23 #include <stxxl/bits/mng/adaptor.h>
39 #include <stxxl/bits/parallel.h>
41 
43 
44 //! \addtogroup stlalgo
45 //! \{
46 
47 /*! \internal
48  */
49 namespace sort_local {
50 
51 template <typename BlockType, typename BidType>
53 {
54  typedef BlockType block_type;
56  BidType bid;
58  void operator () (request* /*completed_req*/)
59  {
60  * req = block->read(bid);
61  }
62 };
63 
64 template <
65  typename BlockType,
66  typename RunType,
67  typename InputBidIterator,
68  typename ValueCmp>
69 void
71  InputBidIterator it,
72  RunType** runs,
73  int_type nruns,
74  int_type _m,
75  ValueCmp cmp)
76 {
77  typedef BlockType block_type;
78  typedef RunType run_type;
79 
80  typedef typename block_type::bid_type bid_type;
81  STXXL_VERBOSE1("stxxl::create_runs nruns=" << nruns << " m=" << _m);
82 
83  int_type m2 = _m / 2;
84  block_manager* bm = block_manager::get_instance();
85  block_type* Blocks1 = new block_type[m2];
86  block_type* Blocks2 = new block_type[m2];
87  bid_type* bids1 = new bid_type[m2];
88  bid_type* bids2 = new bid_type[m2];
89  request_ptr* read_reqs1 = new request_ptr[m2];
90  request_ptr* read_reqs2 = new request_ptr[m2];
91  request_ptr* write_reqs = new request_ptr[m2];
94 
95  disk_queues::get_instance()->set_priority_op(request_queue::WRITE);
96 
97  int_type i;
98  int_type run_size = 0;
99 
100  assert(nruns >= 2);
101 
102  run_size = runs[0]->size();
103  assert(run_size == m2);
104 
105  for (i = 0; i < run_size; ++i)
106  {
107  STXXL_VERBOSE1("stxxl::create_runs posting read " << Blocks1[i].elem);
108  bids1[i] = *(it++);
109  read_reqs1[i] = Blocks1[i].read(bids1[i]);
110  }
111 
112  run_size = runs[1]->size();
113 
114  for (i = 0; i < run_size; ++i)
115  {
116  STXXL_VERBOSE1("stxxl::create_runs posting read " << Blocks2[i].elem);
117  bids2[i] = *(it++);
118  read_reqs2[i] = Blocks2[i].read(bids2[i]);
119  }
120 
121  for (int_type k = 0; k < nruns - 1; ++k)
122  {
123  run_type* run = runs[k];
124  run_size = run->size();
125  assert(run_size == m2);
126  int_type next_run_size = runs[k + 1]->size();
127  STXXL_ASSERT((next_run_size == m2) || (next_run_size <= m2 && k == nruns - 2));
128 
129  STXXL_VERBOSE1("stxxl::create_runs start waiting read_reqs1");
130  wait_all(read_reqs1, run_size);
131  STXXL_VERBOSE1("stxxl::create_runs finish waiting read_reqs1");
132  for (i = 0; i < run_size; ++i)
133  bm->delete_block(bids1[i]);
134 
137  sort(make_element_iterator(Blocks1, 0),
138  make_element_iterator(Blocks1, run_size * block_type::size),
139  cmp);
140 
141  STXXL_VERBOSE1("stxxl::create_runs start waiting write_reqs");
142  if (k > 0)
143  wait_all(write_reqs, m2);
144  STXXL_VERBOSE1("stxxl::create_runs finish waiting write_reqs");
145 
146  int_type runplus2size = (k < nruns - 2) ? runs[k + 2]->size() : 0;
147  for (i = 0; i < m2; ++i)
148  {
149  STXXL_VERBOSE1("stxxl::create_runs posting write " << Blocks1[i].elem);
150  (*run)[i].value = Blocks1[i][0];
151  if (i >= runplus2size) {
152  write_reqs[i] = Blocks1[i].write((*run)[i].bid);
153  }
154  else
155  {
156  next_run_reads[i].block = Blocks1 + i;
157  next_run_reads[i].req = read_reqs1 + i;
158  bids1[i] = next_run_reads[i].bid = *(it++);
159  write_reqs[i] = Blocks1[i].write((*run)[i].bid, next_run_reads[i]);
160  }
161  }
162  std::swap(Blocks1, Blocks2);
163  std::swap(bids1, bids2);
164  std::swap(read_reqs1, read_reqs2);
165  }
166 
167  run_type* run = runs[nruns - 1];
168  run_size = run->size();
169  STXXL_VERBOSE1("stxxl::create_runs start waiting read_reqs1");
170  wait_all(read_reqs1, run_size);
171  STXXL_VERBOSE1("stxxl::create_runs finish waiting read_reqs1");
172  for (i = 0; i < run_size; ++i)
173  bm->delete_block(bids1[i]);
174 
177  sort(make_element_iterator(Blocks1, 0),
178  make_element_iterator(Blocks1, run_size * block_type::size),
179  cmp);
180 
181  STXXL_VERBOSE1("stxxl::create_runs start waiting write_reqs");
182  wait_all(write_reqs, m2);
183  STXXL_VERBOSE1("stxxl::create_runs finish waiting write_reqs");
184 
185  for (i = 0; i < run_size; ++i)
186  {
187  STXXL_VERBOSE1("stxxl::create_runs posting write " << Blocks1[i].elem);
188  (*run)[i].value = Blocks1[i][0];
189  write_reqs[i] = Blocks1[i].write((*run)[i].bid);
190  }
191 
192  STXXL_VERBOSE1("stxxl::create_runs start waiting write_reqs");
193  wait_all(write_reqs, run_size);
194  STXXL_VERBOSE1("stxxl::create_runs finish waiting write_reqs");
195 
196  delete[] Blocks1;
197  delete[] Blocks2;
198  delete[] bids1;
199  delete[] bids2;
200  delete[] read_reqs1;
201  delete[] read_reqs2;
202  delete[] write_reqs;
203  delete[] next_run_reads;
204 }
205 
206 template <typename BlockType, typename RunType, typename ValueCmp>
207 bool check_sorted_runs(RunType** runs,
208  unsigned_type nruns,
209  unsigned_type m,
210  ValueCmp cmp)
211 {
212  typedef BlockType block_type;
213  typedef typename block_type::value_type value_type;
214 
215  STXXL_MSG("check_sorted_runs Runs: " << nruns);
216  unsigned_type irun = 0;
217  for (irun = 0; irun < nruns; ++irun)
218  {
219  const unsigned_type nblocks_per_run = runs[irun]->size();
220  unsigned_type blocks_left = nblocks_per_run;
221  block_type* blocks = new block_type[m];
222  request_ptr* reqs = new request_ptr[m];
223  value_type last = cmp.min_value();
224 
225  for (unsigned_type off = 0; off < nblocks_per_run; off += m)
226  {
227  const unsigned_type nblocks = STXXL_MIN(blocks_left, m);
228  const unsigned_type nelements = nblocks * block_type::size;
229  blocks_left -= nblocks;
230 
231  for (unsigned_type j = 0; j < nblocks; ++j)
232  {
233  reqs[j] = blocks[j].read((*runs[irun])[j + off].bid);
234  }
235  wait_all(reqs, reqs + nblocks);
236 
237  if (off && cmp(blocks[0][0], last))
238  {
239  STXXL_MSG("check_sorted_runs wrong first value in the run " << irun);
240  STXXL_MSG(" first value: " << blocks[0][0]);
241  STXXL_MSG(" last value: " << last);
242  for (unsigned_type k = 0; k < block_type::size; ++k)
243  STXXL_MSG("Element " << k << " in the block is :" << blocks[0][k]);
244 
245  delete[] reqs;
246  delete[] blocks;
247  return false;
248  }
249 
250  for (unsigned_type j = 0; j < nblocks; ++j)
251  {
252  if (!(blocks[j][0] == (*runs[irun])[j + off].value))
253  {
254  STXXL_MSG("check_sorted_runs wrong trigger in the run " << irun << " block " << (j + off));
255  STXXL_MSG(" trigger value: " << (*runs[irun])[j + off].value);
256  STXXL_MSG("Data in the block:");
257  for (unsigned_type k = 0; k < block_type::size; ++k)
258  STXXL_MSG("Element " << k << " in the block is :" << blocks[j][k]);
259 
260  STXXL_MSG("BIDS:");
261  for (unsigned_type k = 0; k < nblocks; ++k)
262  {
263  if (k == j)
264  STXXL_MSG("Bad one comes next.");
265  STXXL_MSG("BID " << (k + off) << " is: " << ((*runs[irun])[k + off].bid));
266  }
267 
268  delete[] reqs;
269  delete[] blocks;
270  return false;
271  }
272  }
273  if (!stxxl::is_sorted(make_element_iterator(blocks, 0),
274  make_element_iterator(blocks, nelements),
275  cmp))
276  {
277  STXXL_MSG("check_sorted_runs wrong order in the run " << irun);
278  STXXL_MSG("Data in blocks:");
279  for (unsigned_type j = 0; j < nblocks; ++j)
280  {
281  for (unsigned_type k = 0; k < block_type::size; ++k)
282  STXXL_MSG(" Element " << k << " in block " << (j + off) << " is :" << blocks[j][k]);
283  }
284  STXXL_MSG("BIDS:");
285  for (unsigned_type k = 0; k < nblocks; ++k)
286  {
287  STXXL_MSG("BID " << (k + off) << " is: " << ((*runs[irun])[k + off].bid));
288  }
289 
290  delete[] reqs;
291  delete[] blocks;
292  return false;
293  }
294 
295  last = blocks[nblocks - 1][block_type::size - 1];
296  }
297 
298  assert(blocks_left == 0);
299  delete[] reqs;
300  delete[] blocks;
301  }
302 
303  return true;
304 }
305 
306 template <typename BlockType, typename RunType, typename ValueCmp>
307 void merge_runs(RunType** in_runs, int_type nruns,
308  RunType* out_run, unsigned_type _m, ValueCmp cmp)
309 {
310  typedef BlockType block_type;
311  typedef RunType run_type;
312  typedef ValueCmp value_cmp;
313  typedef typename run_type::value_type trigger_entry_type;
315  typedef run_cursor2<block_type, prefetcher_type> run_cursor_type;
317 
318  run_type consume_seq(out_run->size());
319 
320  int_type* prefetch_seq = new int_type[out_run->size()];
321 
322  typename run_type::iterator copy_start = consume_seq.begin();
323  for (int_type i = 0; i < nruns; i++)
324  {
325  // \todo: try to avoid copy
326  copy_start = std::copy(
327  in_runs[i]->begin(),
328  in_runs[i]->end(),
329  copy_start);
330  }
331 
332  std::stable_sort(consume_seq.begin(), consume_seq.end(),
334 
335  int_type disks_number = config::get_instance()->disks_number();
336 
337 #ifdef PLAY_WITH_OPT_PREF
338  const int_type n_write_buffers = 4 * disks_number;
339 #else
340  const int_type n_prefetch_buffers = STXXL_MAX(2 * disks_number, (3 * (int_type(_m) - nruns) / 4));
341  const int_type n_write_buffers = STXXL_MAX(2 * disks_number, int_type(_m) - nruns - n_prefetch_buffers);
342  #if STXXL_SORT_OPTIMAL_PREFETCHING
343  // heuristic
344  const int_type n_opt_prefetch_buffers = 2 * disks_number + (3 * (n_prefetch_buffers - 2 * disks_number)) / 10;
345  #endif
346 #endif
347 
348 #if STXXL_SORT_OPTIMAL_PREFETCHING
350  consume_seq,
351  prefetch_seq,
352  n_opt_prefetch_buffers,
353  config::get_instance()->get_max_device_id());
354 #else
355  for (unsigned_type i = 0; i < out_run->size(); i++)
356  prefetch_seq[i] = i;
357 
358 #endif
359 
360  prefetcher_type prefetcher(consume_seq.begin(),
361  consume_seq.end(),
362  prefetch_seq,
363  nruns + n_prefetch_buffers);
364 
365  buffered_writer<block_type> writer(n_write_buffers, n_write_buffers / 2);
366 
367  int_type out_run_size = out_run->size();
368 
369  block_type* out_buffer = writer.get_free_block();
370 
371 //If parallelism is activated, one can still fall back to the
372 //native merge routine by setting stxxl::SETTINGS::native_merge= true, //otherwise, it is used anyway.
373 
374  if (do_parallel_merge())
375  {
376 #if STXXL_PARALLEL_MULTIWAY_MERGE
377 
378 // begin of STL-style merging
379 
380  typedef stxxl::int64 diff_type;
381  typedef std::pair<typename block_type::iterator, typename block_type::iterator> sequence;
382  std::vector<sequence> seqs(nruns);
383  std::vector<block_type*> buffers(nruns);
384 
385  for (int_type i = 0; i < nruns; i++) // initialize sequences
386  {
387  buffers[i] = prefetcher.pull_block(); // get first block of each run
388  seqs[i] = std::make_pair(buffers[i]->begin(), buffers[i]->end());
389  // this memory location stays the same, only the data is exchanged
390  }
391 
392  #if STXXL_CHECK_ORDER_IN_SORTS
393  value_type last_elem = cmp.min_value();
394  #endif
395  diff_type num_currently_mergeable = 0;
396 
397  for (int_type j = 0; j < out_run_size; ++j) // for the whole output run, out_run_size is in blocks
398  {
399  diff_type rest = block_type::size; // elements still to merge for this output block
400 
401  STXXL_VERBOSE1("output block " << j);
402  do {
403  if (num_currently_mergeable < rest)
404  {
405  if (prefetcher.empty())
406  {
407  // anything remaining is already in memory
408  num_currently_mergeable = (out_run_size - j) * block_type::size
409  - (block_type::size - rest);
410  }
411  else
412  {
413  num_currently_mergeable = sort_helper::count_elements_less_equal(
414  seqs, consume_seq[prefetcher.pos()].value, cmp);
415  }
416  }
417 
418  diff_type output_size = STXXL_MIN(num_currently_mergeable, rest); // at most rest elements
419 
420  STXXL_VERBOSE1("before merge " << output_size);
421 
422  stxxl::parallel::multiway_merge(seqs.begin(), seqs.end(), out_buffer->end() - rest, cmp, output_size);
423  // sequence iterators are progressed appropriately
424 
425  rest -= output_size;
426  num_currently_mergeable -= output_size;
427 
428  STXXL_VERBOSE1("after merge");
429 
430  sort_helper::refill_or_remove_empty_sequences(seqs, buffers, prefetcher);
431  } while (rest > 0 && seqs.size() > 0);
432 
433  #if STXXL_CHECK_ORDER_IN_SORTS
434  if (!stxxl::is_sorted(out_buffer->begin(), out_buffer->end(), cmp))
435  {
436  for (value_type* i = out_buffer->begin() + 1; i != out_buffer->end(); i++)
437  if (cmp(*i, *(i - 1)))
438  {
439  STXXL_VERBOSE1("Error at position " << (i - out_buffer->begin()));
440  }
441  assert(false);
442  }
443 
444  if (j > 0) // do not check in first iteration
445  assert(cmp((*out_buffer)[0], last_elem) == false);
446 
447  last_elem = (*out_buffer)[block_type::size - 1];
448  #endif
449 
450  (*out_run)[j].value = (*out_buffer)[0]; // save smallest value
451 
452  out_buffer = writer.write(out_buffer, (*out_run)[j].bid);
453  }
454 
455 // end of STL-style merging
456 
457 #else
459 #endif
460  }
461  else
462  {
463 // begin of native merging procedure
464 
466  losers(&prefetcher, nruns, run_cursor2_cmp_type(cmp));
467 
468 #if STXXL_CHECK_ORDER_IN_SORTS
469  value_type last_elem = cmp.min_value();
470 #endif
471 
472  for (int_type i = 0; i < out_run_size; ++i)
473  {
474  losers.multi_merge(out_buffer->elem, out_buffer->elem + block_type::size);
475  (*out_run)[i].value = *(out_buffer->elem);
476 
477 #if STXXL_CHECK_ORDER_IN_SORTS
478  assert(stxxl::is_sorted(
479  out_buffer->begin(),
480  out_buffer->end(),
481  cmp));
482 
483  if (i)
484  assert(cmp(*(out_buffer->elem), last_elem) == false);
485 
486  last_elem = (*out_buffer).elem[block_type::size - 1];
487 #endif
488 
489  out_buffer = writer.write(out_buffer, (*out_run)[i].bid);
490  }
491 
492 // end of native merging procedure
493  }
494 
495  delete[] prefetch_seq;
496 
497  block_manager* bm = block_manager::get_instance();
498  for (int_type i = 0; i < nruns; ++i)
499  {
500  unsigned_type sz = in_runs[i]->size();
501  for (unsigned_type j = 0; j < sz; ++j)
502  bm->delete_block((*in_runs[i])[j].bid);
503 
504  delete in_runs[i];
505  }
506 }
507 
508 template <typename BlockType,
509  typename AllocStrategy,
510  typename InputBidIterator,
511  typename ValueCmp>
513 sort_blocks(InputBidIterator input_bids,
514  unsigned_type _n,
515  unsigned_type _m,
516  ValueCmp cmp)
517 {
518  typedef BlockType block_type;
519  typedef AllocStrategy alloc_strategy;
520  typedef InputBidIterator input_bid_iterator;
521  typedef ValueCmp value_cmp;
522  typedef typename block_type::bid_type bid_type;
523  typedef sort_helper::trigger_entry<block_type> trigger_entry_type;
524  typedef simple_vector<trigger_entry_type> run_type;
525  typedef typename interleaved_alloc_traits<alloc_strategy>::strategy interleaved_alloc_strategy;
526 
527  unsigned_type m2 = _m / 2;
528  unsigned_type full_runs = _n / m2;
529  unsigned_type partial_runs = ((_n % m2) ? 1 : 0);
530  unsigned_type nruns = full_runs + partial_runs;
531  unsigned_type i;
532 
533  block_manager* mng = block_manager::get_instance();
534 
535  //STXXL_VERBOSE ("n=" << _n << " nruns=" << nruns << "=" << full_runs << "+" << partial_runs);
536 
537  double begin = timestamp(), after_runs_creation, end;
538 
539  run_type** runs = new run_type*[nruns];
540 
541  for (i = 0; i < full_runs; i++)
542  runs[i] = new run_type(m2);
543 
544  if (partial_runs)
545  runs[i] = new run_type(_n - full_runs * m2);
546 
547  for (i = 0; i < nruns; ++i)
548  mng->new_blocks(alloc_strategy(), make_bid_iterator(runs[i]->begin()), make_bid_iterator(runs[i]->end()));
549 
550  sort_local::create_runs<block_type,
551  run_type,
552  input_bid_iterator,
553  value_cmp>(input_bids, runs, nruns, _m, cmp);
554 
555  after_runs_creation = timestamp();
556 
557  double io_wait_after_rf = stats::get_instance()->get_io_wait_time();
558 
559  disk_queues::get_instance()->set_priority_op(request_queue::WRITE);
560 
561  const int_type merge_factor = optimal_merge_factor(nruns, _m);
562  run_type** new_runs;
563 
564  while (nruns > 1)
565  {
566  int_type new_nruns = div_ceil(nruns, merge_factor);
567  STXXL_VERBOSE("Starting new merge phase: nruns: " << nruns <<
568  " opt_merge_factor: " << merge_factor << " m:" << _m << " new_nruns: " << new_nruns);
569 
570  new_runs = new run_type*[new_nruns];
571 
572  int_type runs_left = nruns;
573  int_type cur_out_run = 0;
574  int_type blocks_in_new_run = 0;
575 
576  while (runs_left > 0)
577  {
578  int_type runs2merge = STXXL_MIN(runs_left, merge_factor);
579  blocks_in_new_run = 0;
580  for (unsigned_type i = nruns - runs_left; i < (nruns - runs_left + runs2merge); i++)
581  blocks_in_new_run += runs[i]->size();
582 
583  // allocate run
584  new_runs[cur_out_run++] = new run_type(blocks_in_new_run);
585  runs_left -= runs2merge;
586  }
587  // allocate blocks for the new runs
588  if (cur_out_run == 1 && blocks_in_new_run == int_type(_n) && !input_bids->is_managed())
589  {
590  // if we sort a file we can reuse the input bids for the output
591  input_bid_iterator cur = input_bids;
592  for (int_type i = 0; cur != (input_bids + _n); ++cur)
593  {
594  (*new_runs[0])[i++].bid = *cur;
595  }
596 
597  bid_type& firstBID = (*new_runs[0])[0].bid;
598  if (firstBID.is_managed())
599  {
600  // the first block does not belong to the file
601  // need to reallocate it
602  mng->new_block(FR(), firstBID);
603  }
604  bid_type& lastBID = (*new_runs[0])[_n - 1].bid;
605  if (lastBID.is_managed())
606  {
607  // the first block does not belong to the file
608  // need to reallocate it
609  mng->new_block(FR(), lastBID);
610  }
611  }
612  else
613  {
614  mng->new_blocks(interleaved_alloc_strategy(new_nruns, alloc_strategy()),
615  runs2bid_array_adaptor2<block_type::raw_size, run_type>(new_runs, 0, new_nruns, blocks_in_new_run),
616  runs2bid_array_adaptor2<block_type::raw_size, run_type>(new_runs, _n, new_nruns, blocks_in_new_run));
617  }
618  // merge all
619  runs_left = nruns;
620  cur_out_run = 0;
621  while (runs_left > 0)
622  {
623  int_type runs2merge = STXXL_MIN(runs_left, merge_factor);
624 #if STXXL_CHECK_ORDER_IN_SORTS
625  assert((check_sorted_runs<block_type, run_type, value_cmp>(runs + nruns - runs_left, runs2merge, m2, cmp)));
626 #endif
627  STXXL_VERBOSE("Merging " << runs2merge << " runs");
628  merge_runs<block_type, run_type>(runs + nruns - runs_left,
629  runs2merge, *(new_runs + (cur_out_run++)), _m, cmp
630  );
631  runs_left -= runs2merge;
632  }
633 
634  nruns = new_nruns;
635  delete[] runs;
636  runs = new_runs;
637  }
638 
639  run_type* result = *runs;
640  delete[] runs;
641 
642  end = timestamp();
643 
644  STXXL_VERBOSE("Elapsed time : " << end - begin << " s. Run creation time: " <<
645  after_runs_creation - begin << " s");
646  STXXL_VERBOSE("Time in I/O wait(rf): " << io_wait_after_rf << " s");
647  STXXL_VERBOSE(*stats::get_instance());
648 
649  return result;
650 }
651 
652 } // namespace sort_local
653 
654 /*!
655  * Sort records comparison-based, see \ref design_algo_sort.
656  *
657  * stxxl::sort sorts the elements in [first, last) into ascending order,
658  * meaning that if \c i and \c j are any two valid iterators in [first, last)
659  * such that \c i precedes \c j, then \c *j is not less than \c *i. Note: as
660  * std::sort, stxxl::sort is not guaranteed to be stable. That is, suppose that
661  * \c *i and \c *j are equivalent: neither one is less than the other. It is
662  * not guaranteed that the relative order of these two elements will be
663  * preserved by stxxl::sort.
664  *
665  * The order is defined by the \c cmp parameter. The sorter's internal memory
666  * consumption is bounded by \a M bytes.
667  *
668  * \param first object of model of \c ext_random_access_iterator concept
669  * \param last object of model of \c ext_random_access_iterator concept
670  * \param cmp comparison object of \ref StrictWeakOrdering
671  * \param M amount of memory for internal use (in bytes)
672  */
673 template <typename ExtIterator, typename StrictWeakOrdering>
674 void sort(ExtIterator first, ExtIterator last, StrictWeakOrdering cmp, unsigned_type M)
675 {
677 
678  typedef typename ExtIterator::vector_type::value_type value_type;
679  typedef typename ExtIterator::block_type block_type;
680  typedef typename ExtIterator::bid_type bid_type;
681  typedef typename ExtIterator::vector_type::alloc_strategy_type alloc_strategy_type;
682  typedef typename ExtIterator::bids_container_iterator bids_container_iterator;
683 
685 
686  unsigned_type n = 0;
687 
688  block_manager* mng = block_manager::get_instance();
689 
690  first.flush();
691 
692  if ((last - first) * sizeof(value_type) * sort_memory_usage_factor() < M)
693  {
694  stl_in_memory_sort(first, last, cmp);
695  }
696  else
697  {
698  if (!(2 * block_type::raw_size * (unsigned_type)sort_memory_usage_factor() <= M)) {
699  throw bad_parameter("stxxl::sort(): INSUFFICIENT MEMORY provided, please increase parameter 'M'");
700  }
701 
702  if (first.block_offset())
703  {
704  if (last.block_offset()) // first and last element are
705  // not the first elements of their block
706  {
707  block_type* first_block = new block_type;
708  block_type* last_block = new block_type;
709  typename ExtIterator::bid_type first_bid, last_bid;
710  request_ptr req;
711 
712  req = first_block->read(*first.bid());
713  mng->new_block(FR(), first_bid); // try to overlap
714  mng->new_block(FR(), last_bid);
715  req->wait();
716 
717  req = last_block->read(*last.bid());
718 
719  unsigned_type i = 0;
720  for ( ; i < first.block_offset(); ++i)
721  {
722  first_block->elem[i] = cmp.min_value();
723  }
724 
725  req->wait();
726 
727  req = first_block->write(first_bid);
728  for (i = last.block_offset(); i < block_type::size; ++i)
729  {
730  last_block->elem[i] = cmp.max_value();
731  }
732 
733  req->wait();
734 
735  req = last_block->write(last_bid);
736 
737  n = last.bid() - first.bid() + 1;
738 
739  std::swap(first_bid, *first.bid());
740  std::swap(last_bid, *last.bid());
741 
742  req->wait();
743 
744  delete first_block;
745  delete last_block;
746 
747  run_type* out =
749  block_type, alloc_strategy_type, bids_container_iterator
750  >(first.bid(), n,
751  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
752 
753  first_block = new block_type;
754  last_block = new block_type;
755  block_type* sorted_first_block = new block_type;
756  block_type* sorted_last_block = new block_type;
757  request_ptr* reqs = new request_ptr[2];
758 
759  reqs[0] = first_block->read(first_bid);
760  reqs[1] = sorted_first_block->read((*(out->begin())).bid);
761 
762  reqs[0]->wait();
763  reqs[1]->wait();
764 
765  reqs[0] = last_block->read(last_bid);
766  reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid);
767 
768  for (i = first.block_offset(); i < block_type::size; i++)
769  {
770  first_block->elem[i] = sorted_first_block->elem[i];
771  }
772 
773  reqs[0]->wait();
774  reqs[1]->wait();
775 
776  req = first_block->write(first_bid);
777 
778  for (i = 0; i < last.block_offset(); ++i)
779  {
780  last_block->elem[i] = sorted_last_block->elem[i];
781  }
782 
783  req->wait();
784 
785  req = last_block->write(last_bid);
786 
787  mng->delete_block(out->begin()->bid);
788  mng->delete_block((*out)[out->size() - 1].bid);
789 
790  *first.bid() = first_bid;
791  *last.bid() = last_bid;
792 
793  typename run_type::iterator it = out->begin();
794  ++it;
795  bids_container_iterator cur_bid = first.bid();
796  ++cur_bid;
797 
798  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
799  {
800  *cur_bid = (*it).bid;
801  }
802 
803  delete first_block;
804  delete sorted_first_block;
805  delete sorted_last_block;
806  delete[] reqs;
807  delete out;
808 
809  req->wait();
810 
811  delete last_block;
812  }
813  else
814  {
815  // first element is
816  // not the first element of its block
817  block_type* first_block = new block_type;
818  bid_type first_bid;
819  request_ptr req;
820 
821  req = first_block->read(*first.bid());
822  mng->new_block(FR(), first_bid); // try to overlap
823  req->wait();
824 
825  unsigned_type i = 0;
826  for ( ; i < first.block_offset(); ++i)
827  {
828  first_block->elem[i] = cmp.min_value();
829  }
830 
831  req = first_block->write(first_bid);
832 
833  n = last.bid() - first.bid();
834 
835  std::swap(first_bid, *first.bid());
836 
837  req->wait();
838 
839  delete first_block;
840 
841  run_type* out =
843  block_type, alloc_strategy_type, bids_container_iterator
844  >(first.bid(), n,
845  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
846 
847  first_block = new block_type;
848 
849  block_type* sorted_first_block = new block_type;
850 
851  request_ptr* reqs = new request_ptr[2];
852 
853  reqs[0] = first_block->read(first_bid);
854  reqs[1] = sorted_first_block->read((*(out->begin())).bid);
855 
856  reqs[0]->wait();
857  reqs[1]->wait();
858 
859  for (i = first.block_offset(); i < block_type::size; ++i)
860  {
861  first_block->elem[i] = sorted_first_block->elem[i];
862  }
863 
864  req = first_block->write(first_bid);
865 
866  mng->delete_block(out->begin()->bid);
867 
868  *first.bid() = first_bid;
869 
870  typename run_type::iterator it = out->begin();
871  ++it;
872  bids_container_iterator cur_bid = first.bid();
873  ++cur_bid;
874 
875  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
876  {
877  *cur_bid = (*it).bid;
878  }
879 
880  *cur_bid = (*it).bid;
881 
882  delete sorted_first_block;
883  delete[] reqs;
884  delete out;
885 
886  req->wait();
887 
888  delete first_block;
889  }
890  }
891  else
892  {
893  if (last.block_offset()) // last is
894  // not the first element of its block
895  {
896  block_type* last_block = new block_type;
897  bid_type last_bid;
898  request_ptr req;
899  unsigned_type i;
900 
901  req = last_block->read(*last.bid());
902  mng->new_block(FR(), last_bid);
903  req->wait();
904 
905  for (i = last.block_offset(); i < block_type::size; ++i)
906  {
907  last_block->elem[i] = cmp.max_value();
908  }
909 
910  req = last_block->write(last_bid);
911 
912  n = last.bid() - first.bid() + 1;
913 
914  std::swap(last_bid, *last.bid());
915 
916  req->wait();
917 
918  delete last_block;
919 
920  run_type* out =
922  block_type, alloc_strategy_type, bids_container_iterator
923  >(first.bid(), n,
924  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
925 
926  last_block = new block_type;
927  block_type* sorted_last_block = new block_type;
928  request_ptr* reqs = new request_ptr[2];
929 
930  reqs[0] = last_block->read(last_bid);
931  reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid);
932 
933  reqs[0]->wait();
934  reqs[1]->wait();
935 
936  for (i = 0; i < last.block_offset(); ++i)
937  {
938  last_block->elem[i] = sorted_last_block->elem[i];
939  }
940 
941  req = last_block->write(last_bid);
942 
943  mng->delete_block((*out)[out->size() - 1].bid);
944 
945  *last.bid() = last_bid;
946 
947  typename run_type::iterator it = out->begin();
948  bids_container_iterator cur_bid = first.bid();
949 
950  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
951  {
952  *cur_bid = (*it).bid;
953  }
954 
955  delete sorted_last_block;
956  delete[] reqs;
957  delete out;
958 
959  req->wait();
960 
961  delete last_block;
962  }
963  else
964  {
965  // first and last element are first elements of their of blocks
966  n = last.bid() - first.bid();
967 
968  run_type* out =
970  block_type, alloc_strategy_type, bids_container_iterator
971  >(first.bid(), n,
972  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
973 
974  typename run_type::iterator it = out->begin();
975  bids_container_iterator cur_bid = first.bid();
976 
977  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
978  {
979  *cur_bid = (*it).bid;
980  }
981 
982  delete out;
983  }
984  }
985  }
986 
987 #if STXXL_CHECK_ORDER_IN_SORTS
988  typedef typename ExtIterator::const_iterator const_iterator;
989  assert(stxxl::is_sorted(const_iterator(first), const_iterator(last), cmp));
990 #endif
991 }
992 
993 //! \}
994 
996 
997 #endif // !STXXL_ALGO_SORT_HEADER
998 // vim: et:ts=4:sw=4
#define STXXL_VERBOSE(x)
Definition: verbose.h:102
simple_vector< sort_helper::trigger_entry< BlockType > > * sort_blocks(InputBidIterator input_bids, unsigned_type _n, unsigned_type _m, ValueCmp cmp)
Definition: sort.h:513
#define STXXL_THROW_UNREACHABLE()
Throws stxxl::unreachable with &quot;Error in file [file], line [line] : this code should never be reachab...
#define STXXL_ASSERT(condition)
Definition: verbose.h:171
compat::remove_const< Integral >::type div_ceil(Integral n, Integral2 d)
Definition: utils.h:199
bool is_sorted(ForwardIterator first, ForwardIterator last)
Definition: is_sorted.h:53
Fully randomized disk allocation scheme functor.
Definition: block_alloc.h:67
unsigned sort_memory_usage_factor()
Definition: parallel.h:87
const Type & STXXL_MIN(const Type &a, const Type &b)
Definition: utils.h:146
bool check_sorted_runs(RunType **runs, unsigned_type nruns, unsigned_type m, ValueCmp cmp)
Definition: sort.h:207
Block manager class.
Definition: block_manager.h:61
long long int int64
Definition: types.h:38
void sort(ExtIterator first, ExtIterator last, StrictWeakOrdering cmp, unsigned_type M)
Sort records comparison-based, see stxxl::sort -- Sorting Comparison-Based.
Definition: sort.h:674
trigger_entry_iterator< Iterator > make_bid_iterator(Iterator iter)
Definition: adaptor.h:239
unsigned_type count_elements_less_equal(const SequenceVector &seqs, const ValueType &bound, Comparator cmp)
Definition: sort_helper.h:101
void stl_in_memory_sort(ExtIterator first, ExtIterator last, StrictWeakOrdering cmp)
Definition: inmemsort.h:29
void verify_sentinel_strict_weak_ordering(StrictWeakOrdering cmp)
Definition: sort_helper.h:28
void refill_or_remove_empty_sequences(SequenceVector &seqs, BufferPtrVector &buffers, Prefetcher &prefetcher)
Definition: sort_helper.h:121
void delete_block(const BID< BLK_SIZE > &bid)
Deallocates a block.
Definition: sort_helper.h:53
void check_sort_settings()
Definition: parallel.h:96
Encapsulates asynchronous prefetching engine.
External sequence or deque container without random access. Introduction to sequence container: se...
Definition: sequence.h:62
void merge_runs(RunType **in_runs, unsigned_type nruns, RunType *out_run, unsigned_type _m, KeyExtractor keyobj)
Definition: ksort.h:443
#define _STXXL_SORT_TRIGGER_FORCE_SEQUENTIAL
Definition: parallel.h:58
choose_int_types< my_pointer_size >::int_type int_type
Definition: types.h:63
const Type & STXXL_MAX(const Type &a, const Type &b)
Definition: utils.h:153
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
#define STXXL_VERBOSE1(x)
Definition: verbose.h:99
void new_block(const DiskAssignFunctor &functor, BID< BLK_SIZE > &bid, unsigned_type offset=0)
Allocates a new block according to the strategy given by functor and stores the block identifier to b...
void new_blocks(const DiskAssignFunctor &functor, BIDIteratorClass bidbegin, BIDIteratorClass bidend, unsigned_type offset=0)
Allocates new blocks.
Provides a static class to store runtime tuning parameters.
element_iterator_traits< BlockType, SizeType >::element_iterator make_element_iterator(BlockType *blocks, SizeType offset)
Definition: adaptor.h:646
Simpler non-growing vector without initialization.
Definition: simple_vector.h:39
void wait_all(RequestIterator reqs_begin, RequestIterator reqs_end)
Collection of functions to track statuses of a number of requests.
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
Definition: types.h:64
double timestamp()
Returns number of seconds since the epoch, high resolution.
Definition: timer.h:44
void compute_prefetch_schedule(const int_type *first, const int_type *last, int_type *out_first, int_type m, int_type D)
#define STXXL_MSG(x)
Definition: verbose.h:73
unsigned_type optimal_merge_factor(unsigned_type num_runs, unsigned_type max_concurrent_runs)
Definition: sort_base.h:40
Definition: sort_helper.h:37
void create_runs(InputBidIterator it, RunType **runs, const unsigned_type nruns, const unsigned_type m2, KeyExtractor keyobj)
Definition: ksort.h:181
Request object encapsulating basic properties like file and offset.
Definition: request.h:38
void multi_merge(value_type *out_first, value_type *out_last)
Definition: losertree.h:200
bool do_parallel_merge()
Definition: parallel.h:115
#define STXXL_END_NAMESPACE
Definition: namespace.h:17