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