STXXL  1.4-dev
 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 
423  seqs.begin(), seqs.end(),
424  out_buffer->end() - rest, output_size, cmp);
425  // sequence iterators are progressed appropriately
426 
427  rest -= output_size;
428  num_currently_mergeable -= output_size;
429 
430  STXXL_VERBOSE1("after merge");
431 
432  sort_helper::refill_or_remove_empty_sequences(seqs, buffers, prefetcher);
433  } while (rest > 0 && seqs.size() > 0);
434 
435  #if STXXL_CHECK_ORDER_IN_SORTS
436  if (!stxxl::is_sorted(out_buffer->begin(), out_buffer->end(), cmp))
437  {
438  for (value_type* i = out_buffer->begin() + 1; i != out_buffer->end(); i++)
439  if (cmp(*i, *(i - 1)))
440  {
441  STXXL_VERBOSE1("Error at position " << (i - out_buffer->begin()));
442  }
443  assert(false);
444  }
445 
446  if (j > 0) // do not check in first iteration
447  assert(cmp((*out_buffer)[0], last_elem) == false);
448 
449  last_elem = (*out_buffer)[block_type::size - 1];
450  #endif
451 
452  (*out_run)[j].value = (*out_buffer)[0]; // save smallest value
453 
454  out_buffer = writer.write(out_buffer, (*out_run)[j].bid);
455  }
456 
457 // end of STL-style merging
458 
459 #else
461 #endif
462  }
463  else
464  {
465 // begin of native merging procedure
466 
468  losers(&prefetcher, nruns, run_cursor2_cmp_type(cmp));
469 
470 #if STXXL_CHECK_ORDER_IN_SORTS
471  value_type last_elem = cmp.min_value();
472 #endif
473 
474  for (int_type i = 0; i < out_run_size; ++i)
475  {
476  losers.multi_merge(out_buffer->elem, out_buffer->elem + block_type::size);
477  (*out_run)[i].value = *(out_buffer->elem);
478 
479 #if STXXL_CHECK_ORDER_IN_SORTS
480  assert(stxxl::is_sorted(
481  out_buffer->begin(),
482  out_buffer->end(),
483  cmp));
484 
485  if (i)
486  assert(cmp(*(out_buffer->elem), last_elem) == false);
487 
488  last_elem = (*out_buffer).elem[block_type::size - 1];
489 #endif
490 
491  out_buffer = writer.write(out_buffer, (*out_run)[i].bid);
492  }
493 
494 // end of native merging procedure
495  }
496 
497  delete[] prefetch_seq;
498 
499  block_manager* bm = block_manager::get_instance();
500  for (int_type i = 0; i < nruns; ++i)
501  {
502  unsigned_type sz = in_runs[i]->size();
503  for (unsigned_type j = 0; j < sz; ++j)
504  bm->delete_block((*in_runs[i])[j].bid);
505 
506  delete in_runs[i];
507  }
508 }
509 
510 template <typename BlockType,
511  typename AllocStrategy,
512  typename InputBidIterator,
513  typename ValueCmp>
515 sort_blocks(InputBidIterator input_bids,
516  unsigned_type _n,
517  unsigned_type _m,
518  ValueCmp cmp)
519 {
520  typedef BlockType block_type;
521  typedef AllocStrategy alloc_strategy;
522  typedef InputBidIterator input_bid_iterator;
523  typedef ValueCmp value_cmp;
524  typedef typename block_type::bid_type bid_type;
525  typedef sort_helper::trigger_entry<block_type> trigger_entry_type;
526  typedef simple_vector<trigger_entry_type> run_type;
527  typedef typename interleaved_alloc_traits<alloc_strategy>::strategy interleaved_alloc_strategy;
528 
529  unsigned_type m2 = _m / 2;
530  unsigned_type full_runs = _n / m2;
531  unsigned_type partial_runs = ((_n % m2) ? 1 : 0);
532  unsigned_type nruns = full_runs + partial_runs;
533  unsigned_type i;
534 
535  block_manager* mng = block_manager::get_instance();
536 
537  //STXXL_VERBOSE ("n=" << _n << " nruns=" << nruns << "=" << full_runs << "+" << partial_runs);
538 
539  double begin = timestamp(), after_runs_creation, end;
540 
541  run_type** runs = new run_type*[nruns];
542 
543  for (i = 0; i < full_runs; i++)
544  runs[i] = new run_type(m2);
545 
546  if (partial_runs)
547  runs[i] = new run_type(_n - full_runs * m2);
548 
549  for (i = 0; i < nruns; ++i)
550  mng->new_blocks(alloc_strategy(), make_bid_iterator(runs[i]->begin()), make_bid_iterator(runs[i]->end()));
551 
552  sort_local::create_runs<block_type,
553  run_type,
554  input_bid_iterator,
555  value_cmp>(input_bids, runs, nruns, _m, cmp);
556 
557  after_runs_creation = timestamp();
558 
559  double io_wait_after_rf = stats::get_instance()->get_io_wait_time();
560 
561  disk_queues::get_instance()->set_priority_op(request_queue::WRITE);
562 
563  const int_type merge_factor = optimal_merge_factor(nruns, _m);
564  run_type** new_runs;
565 
566  while (nruns > 1)
567  {
568  int_type new_nruns = div_ceil(nruns, merge_factor);
569  STXXL_VERBOSE("Starting new merge phase: nruns: " << nruns <<
570  " opt_merge_factor: " << merge_factor << " m:" << _m << " new_nruns: " << new_nruns);
571 
572  new_runs = new run_type*[new_nruns];
573 
574  int_type runs_left = nruns;
575  int_type cur_out_run = 0;
576  int_type blocks_in_new_run = 0;
577 
578  while (runs_left > 0)
579  {
580  int_type runs2merge = STXXL_MIN(runs_left, merge_factor);
581  blocks_in_new_run = 0;
582  for (unsigned_type i = nruns - runs_left; i < (nruns - runs_left + runs2merge); i++)
583  blocks_in_new_run += runs[i]->size();
584 
585  // allocate run
586  new_runs[cur_out_run++] = new run_type(blocks_in_new_run);
587  runs_left -= runs2merge;
588  }
589  // allocate blocks for the new runs
590  if (cur_out_run == 1 && blocks_in_new_run == int_type(_n) && !input_bids->is_managed())
591  {
592  // if we sort a file we can reuse the input bids for the output
593  input_bid_iterator cur = input_bids;
594  for (int_type i = 0; cur != (input_bids + _n); ++cur)
595  {
596  (*new_runs[0])[i++].bid = *cur;
597  }
598 
599  bid_type& firstBID = (*new_runs[0])[0].bid;
600  if (firstBID.is_managed())
601  {
602  // the first block does not belong to the file
603  // need to reallocate it
604  mng->new_block(FR(), firstBID);
605  }
606  bid_type& lastBID = (*new_runs[0])[_n - 1].bid;
607  if (lastBID.is_managed())
608  {
609  // the first block does not belong to the file
610  // need to reallocate it
611  mng->new_block(FR(), lastBID);
612  }
613  }
614  else
615  {
616  mng->new_blocks(interleaved_alloc_strategy(new_nruns, alloc_strategy()),
617  runs2bid_array_adaptor2<block_type::raw_size, run_type>(new_runs, 0, new_nruns, blocks_in_new_run),
618  runs2bid_array_adaptor2<block_type::raw_size, run_type>(new_runs, _n, new_nruns, blocks_in_new_run));
619  }
620  // merge all
621  runs_left = nruns;
622  cur_out_run = 0;
623  while (runs_left > 0)
624  {
625  int_type runs2merge = STXXL_MIN(runs_left, merge_factor);
626 #if STXXL_CHECK_ORDER_IN_SORTS
627  assert((check_sorted_runs<block_type, run_type, value_cmp>(runs + nruns - runs_left, runs2merge, m2, cmp)));
628 #endif
629  STXXL_VERBOSE("Merging " << runs2merge << " runs");
630  merge_runs<block_type, run_type>(runs + nruns - runs_left,
631  runs2merge, *(new_runs + (cur_out_run++)), _m, cmp
632  );
633  runs_left -= runs2merge;
634  }
635 
636  nruns = new_nruns;
637  delete[] runs;
638  runs = new_runs;
639  }
640 
641  run_type* result = *runs;
642  delete[] runs;
643 
644  end = timestamp();
645 
646  STXXL_VERBOSE("Elapsed time : " << end - begin << " s. Run creation time: " <<
647  after_runs_creation - begin << " s");
648  STXXL_VERBOSE("Time in I/O wait(rf): " << io_wait_after_rf << " s");
649  STXXL_VERBOSE(*stats::get_instance());
650 
651  return result;
652 }
653 
654 } // namespace sort_local
655 
656 /*!
657  * Sort records comparison-based, see \ref design_algo_sort.
658  *
659  * stxxl::sort sorts the elements in [first, last) into ascending order,
660  * meaning that if \c i and \c j are any two valid iterators in [first, last)
661  * such that \c i precedes \c j, then \c *j is not less than \c *i. Note: as
662  * std::sort, stxxl::sort is not guaranteed to be stable. That is, suppose that
663  * \c *i and \c *j are equivalent: neither one is less than the other. It is
664  * not guaranteed that the relative order of these two elements will be
665  * preserved by stxxl::sort.
666  *
667  * The order is defined by the \c cmp parameter. The sorter's internal memory
668  * consumption is bounded by \a M bytes.
669  *
670  * \param first object of model of \c ext_random_access_iterator concept
671  * \param last object of model of \c ext_random_access_iterator concept
672  * \param cmp comparison object of \ref StrictWeakOrdering
673  * \param M amount of memory for internal use (in bytes)
674  */
675 template <typename ExtIterator, typename StrictWeakOrdering>
676 void sort(ExtIterator first, ExtIterator last, StrictWeakOrdering cmp, unsigned_type M)
677 {
679 
680  typedef typename ExtIterator::vector_type::value_type value_type;
681  typedef typename ExtIterator::block_type block_type;
682  typedef typename ExtIterator::bid_type bid_type;
683  typedef typename ExtIterator::vector_type::alloc_strategy_type alloc_strategy_type;
684  typedef typename ExtIterator::bids_container_iterator bids_container_iterator;
685 
687 
688  unsigned_type n = 0;
689 
690  block_manager* mng = block_manager::get_instance();
691 
692  first.flush();
693 
694  if ((last - first) * sizeof(value_type) * sort_memory_usage_factor() < M)
695  {
696  stl_in_memory_sort(first, last, cmp);
697  }
698  else
699  {
700  if (!(2 * block_type::raw_size * (unsigned_type)sort_memory_usage_factor() <= M)) {
701  throw bad_parameter("stxxl::sort(): INSUFFICIENT MEMORY provided, please increase parameter 'M'");
702  }
703 
704  if (first.block_offset())
705  {
706  if (last.block_offset()) // first and last element are
707  // not the first elements of their block
708  {
709  block_type* first_block = new block_type;
710  block_type* last_block = new block_type;
711  typename ExtIterator::bid_type first_bid, last_bid;
712  request_ptr req;
713 
714  req = first_block->read(*first.bid());
715  mng->new_block(FR(), first_bid); // try to overlap
716  mng->new_block(FR(), last_bid);
717  req->wait();
718 
719  req = last_block->read(*last.bid());
720 
721  unsigned_type i = 0;
722  for ( ; i < first.block_offset(); ++i)
723  {
724  first_block->elem[i] = cmp.min_value();
725  }
726 
727  req->wait();
728 
729  req = first_block->write(first_bid);
730  for (i = last.block_offset(); i < block_type::size; ++i)
731  {
732  last_block->elem[i] = cmp.max_value();
733  }
734 
735  req->wait();
736 
737  req = last_block->write(last_bid);
738 
739  n = last.bid() - first.bid() + 1;
740 
741  std::swap(first_bid, *first.bid());
742  std::swap(last_bid, *last.bid());
743 
744  req->wait();
745 
746  delete first_block;
747  delete last_block;
748 
749  run_type* out =
751  block_type, alloc_strategy_type, bids_container_iterator
752  >(first.bid(), n,
753  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
754 
755  first_block = new block_type;
756  last_block = new block_type;
757  block_type* sorted_first_block = new block_type;
758  block_type* sorted_last_block = new block_type;
759  request_ptr* reqs = new request_ptr[2];
760 
761  reqs[0] = first_block->read(first_bid);
762  reqs[1] = sorted_first_block->read((*(out->begin())).bid);
763 
764  reqs[0]->wait();
765  reqs[1]->wait();
766 
767  reqs[0] = last_block->read(last_bid);
768  reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid);
769 
770  for (i = first.block_offset(); i < block_type::size; i++)
771  {
772  first_block->elem[i] = sorted_first_block->elem[i];
773  }
774 
775  reqs[0]->wait();
776  reqs[1]->wait();
777 
778  req = first_block->write(first_bid);
779 
780  for (i = 0; i < last.block_offset(); ++i)
781  {
782  last_block->elem[i] = sorted_last_block->elem[i];
783  }
784 
785  req->wait();
786 
787  req = last_block->write(last_bid);
788 
789  mng->delete_block(out->begin()->bid);
790  mng->delete_block((*out)[out->size() - 1].bid);
791 
792  *first.bid() = first_bid;
793  *last.bid() = last_bid;
794 
795  typename run_type::iterator it = out->begin();
796  ++it;
797  bids_container_iterator cur_bid = first.bid();
798  ++cur_bid;
799 
800  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
801  {
802  *cur_bid = (*it).bid;
803  }
804 
805  delete first_block;
806  delete sorted_first_block;
807  delete sorted_last_block;
808  delete[] reqs;
809  delete out;
810 
811  req->wait();
812 
813  delete last_block;
814  }
815  else
816  {
817  // first element is
818  // not the first element of its block
819  block_type* first_block = new block_type;
820  bid_type first_bid;
821  request_ptr req;
822 
823  req = first_block->read(*first.bid());
824  mng->new_block(FR(), first_bid); // try to overlap
825  req->wait();
826 
827  unsigned_type i = 0;
828  for ( ; i < first.block_offset(); ++i)
829  {
830  first_block->elem[i] = cmp.min_value();
831  }
832 
833  req = first_block->write(first_bid);
834 
835  n = last.bid() - first.bid();
836 
837  std::swap(first_bid, *first.bid());
838 
839  req->wait();
840 
841  delete first_block;
842 
843  run_type* out =
845  block_type, alloc_strategy_type, bids_container_iterator
846  >(first.bid(), n,
847  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
848 
849  first_block = new block_type;
850 
851  block_type* sorted_first_block = new block_type;
852 
853  request_ptr* reqs = new request_ptr[2];
854 
855  reqs[0] = first_block->read(first_bid);
856  reqs[1] = sorted_first_block->read((*(out->begin())).bid);
857 
858  reqs[0]->wait();
859  reqs[1]->wait();
860 
861  for (i = first.block_offset(); i < block_type::size; ++i)
862  {
863  first_block->elem[i] = sorted_first_block->elem[i];
864  }
865 
866  req = first_block->write(first_bid);
867 
868  mng->delete_block(out->begin()->bid);
869 
870  *first.bid() = first_bid;
871 
872  typename run_type::iterator it = out->begin();
873  ++it;
874  bids_container_iterator cur_bid = first.bid();
875  ++cur_bid;
876 
877  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
878  {
879  *cur_bid = (*it).bid;
880  }
881 
882  *cur_bid = (*it).bid;
883 
884  delete sorted_first_block;
885  delete[] reqs;
886  delete out;
887 
888  req->wait();
889 
890  delete first_block;
891  }
892  }
893  else
894  {
895  if (last.block_offset()) // last is
896  // not the first element of its block
897  {
898  block_type* last_block = new block_type;
899  bid_type last_bid;
900  request_ptr req;
901  unsigned_type i;
902 
903  req = last_block->read(*last.bid());
904  mng->new_block(FR(), last_bid);
905  req->wait();
906 
907  for (i = last.block_offset(); i < block_type::size; ++i)
908  {
909  last_block->elem[i] = cmp.max_value();
910  }
911 
912  req = last_block->write(last_bid);
913 
914  n = last.bid() - first.bid() + 1;
915 
916  std::swap(last_bid, *last.bid());
917 
918  req->wait();
919 
920  delete last_block;
921 
922  run_type* out =
924  block_type, alloc_strategy_type, bids_container_iterator
925  >(first.bid(), n,
926  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
927 
928  last_block = new block_type;
929  block_type* sorted_last_block = new block_type;
930  request_ptr* reqs = new request_ptr[2];
931 
932  reqs[0] = last_block->read(last_bid);
933  reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid);
934 
935  reqs[0]->wait();
936  reqs[1]->wait();
937 
938  for (i = 0; i < last.block_offset(); ++i)
939  {
940  last_block->elem[i] = sorted_last_block->elem[i];
941  }
942 
943  req = last_block->write(last_bid);
944 
945  mng->delete_block((*out)[out->size() - 1].bid);
946 
947  *last.bid() = last_bid;
948 
949  typename run_type::iterator it = out->begin();
950  bids_container_iterator cur_bid = first.bid();
951 
952  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
953  {
954  *cur_bid = (*it).bid;
955  }
956 
957  delete sorted_last_block;
958  delete[] reqs;
959  delete out;
960 
961  req->wait();
962 
963  delete last_block;
964  }
965  else
966  {
967  // first and last element are first elements of their of blocks
968  n = last.bid() - first.bid();
969 
970  run_type* out =
972  block_type, alloc_strategy_type, bids_container_iterator
973  >(first.bid(), n,
974  M / sort_memory_usage_factor() / block_type::raw_size, cmp);
975 
976  typename run_type::iterator it = out->begin();
977  bids_container_iterator cur_bid = first.bid();
978 
979  for ( ; cur_bid != last.bid(); ++cur_bid, ++it)
980  {
981  *cur_bid = (*it).bid;
982  }
983 
984  delete out;
985  }
986  }
987  }
988 
989 #if STXXL_CHECK_ORDER_IN_SORTS
990  typedef typename ExtIterator::const_iterator const_iterator;
991  assert(stxxl::is_sorted(const_iterator(first), const_iterator(last), cmp));
992 #endif
993 }
994 
995 //! \}
996 
998 
999 #endif // !STXXL_ALGO_SORT_HEADER
1000 // vim: et:ts=4:sw=4
#define STXXL_VERBOSE(x)
Definition: verbose.h:116
simple_vector< sort_helper::trigger_entry< BlockType > > * sort_blocks(InputBidIterator input_bids, unsigned_type _n, unsigned_type _m, ValueCmp cmp)
Definition: sort.h:515
#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:220
compat::remove_const< Integral >::type div_ceil(Integral n, Integral2 d)
Definition: utils.h:199
Fully randomized disk allocation scheme functor.
Definition: block_alloc.h:67
unsigned sort_memory_usage_factor()
Definition: parallel.h:73
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:676
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
RandomAccessIterator3 multiway_merge(RandomAccessIteratorPairIterator seqs_begin, RandomAccessIteratorPairIterator seqs_end, RandomAccessIterator3 target, DiffType length, Comparator comp)
Multi-way merging dispatcher.
Definition: parallel.h:144
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:82
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:42
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:113
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...
bool is_sorted(ForwardIterator first, ForwardIterator last, StrictWeakOrdering comp)
Definition: is_sorted.h:24
void new_blocks(const DiskAssignFunctor &functor, BIDIteratorClass bidbegin, BIDIteratorClass bidend, unsigned_type offset=0)
Allocates new blocks.
element_iterator_traits< BlockType, SizeType >::element_iterator make_element_iterator(BlockType *blocks, SizeType offset)
Definition: adaptor.h:646
Provides a static class to store runtime tuning parameters.
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:102
#define STXXL_END_NAMESPACE
Definition: namespace.h:17