TPIE

2362a60
sort.h
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 // Copyright 2011, 2012, The TPIE development team
4 //
5 // This file is part of TPIE.
6 //
7 // TPIE is free software: you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation, either version 3 of the License, or (at your
10 // option) any later version.
11 //
12 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
19 
20 #ifndef __TPIE_PIPELINING_SORT_H__
21 #define __TPIE_PIPELINING_SORT_H__
22 
23 #include <tpie/pipelining/node.h>
24 #include <tpie/pipelining/pipe_base.h>
25 #include <tpie/pipelining/factory_base.h>
26 #include <tpie/pipelining/merge_sorter.h>
27 #include <tpie/parallel_sort.h>
28 #include <tpie/file_stream.h>
29 #include <tpie/tempname.h>
30 #include <tpie/memory.h>
31 #include <queue>
32 #include <memory>
33 
34 namespace tpie {
35 
36 namespace pipelining {
37 
38 namespace bits {
39 
40 template <typename T, typename pred_t, typename store_t>
42 
43 template <typename T, typename pred_t, typename store_t>
45 
46 template <typename T, typename pred_t, typename store_t>
47 class sort_output_base : public node {
48  // node has virtual dtor
49 public:
51  typedef T item_type;
52 
56  typedef typename sorter_t::ptr sorterptr;
57 
58  sorterptr get_sorter() const {
59  return m_sorter;
60  }
61 
62  virtual void propagate() override {
63  set_steps(m_sorter->item_count());
64  forward("items", static_cast<stream_size_type>(m_sorter->item_count()));
65  memory_size_type memory_usage = m_sorter->actual_memory_phase_3();
66  set_minimum_memory(memory_usage);
67  set_maximum_memory(memory_usage);
69  m_propagate_called = true;
70  }
71 
72  void add_calc_dependency(node_token tkn) {
74  }
75 
76 protected:
77  virtual void resource_available_changed(resource_type type, memory_size_type available) override {
78  // TODO: Handle changing parameters of sorter after data structures has been frozen, i.e. after propagate
79  if (m_propagate_called)
80  return;
81 
82  if (type == MEMORY)
83  m_sorter->set_phase_3_memory(available);
84  else if (type == FILES) {
85  m_sorter->set_phase_3_files(available);
86  }
87  }
88 
90  : m_sorter(sorter)
91  , m_propagate_called(false)
92  {
93  }
94 
95  sorterptr m_sorter;
96  bool m_propagate_called;
97 };
98 
104 template <typename T, typename pred_t, typename store_t>
105 class sort_pull_output_t : public sort_output_base<T, pred_t, store_t> {
106 public:
108  typedef T item_type;
109 
113  typedef typename sorter_t::ptr sorterptr;
114 
116  : sort_output_base<T, pred_t, store_t>(sorter)
117  {
118  this->set_minimum_resource_usage(FILES, sorter_t::minimumFilesPhase3);
119  this->set_resource_fraction(FILES, 1.0);
120  this->set_minimum_memory(sorter_t::minimum_memory_phase_3());
121  this->set_maximum_memory(sorter_t::maximum_memory_phase_3());
122  this->set_name("Write sorted output", PRIORITY_INSIGNIFICANT);
123  this->set_memory_fraction(1.0);
124  this->set_plot_options(node::PLOT_BUFFERED);
125  }
126 
127  void begin() override {
128  this->m_sorter->set_owner(this);
129  }
130 
131  bool can_pull() const {
132  return this->m_sorter->can_pull();
133  }
134 
135  item_type pull() {
136  this->step();
137  return this->m_sorter->pull();
138  }
139 
140  void end() override {
141  this->m_sorter.reset();
142  }
143 
144  // Despite this go() implementation, a sort_pull_output_t CANNOT be used as
145  // an initiator node. Normally, it is a type error to have a phase without
146  // an initiator, but with a passive_sorter you can circumvent this
147  // mechanism. Thus we customize the error message printed (but throw the
148  // same type of exception.)
149  virtual void go() override {
150  log_warning() << "Passive sorter used without an initiator in the final merge and output phase.\n"
151  << "Define an initiator and pair it up with the pipe from passive_sorter::output()." << std::endl;
152  throw not_initiator_node();
153  }
154 };
155 
161 template <typename pred_t, typename dest_t, typename store_t>
162 class sort_output_t : public sort_output_base<typename push_type<dest_t>::type, pred_t, store_t> {
163 public:
166 
172  typedef typename sorter_t::ptr sorterptr;
173 
174  inline sort_output_t(dest_t dest, sorterptr sorter)
175  : p_t(sorter)
176  , dest(std::move(dest))
177  {
178  this->add_push_destination(dest);
179  this->set_minimum_resource_usage(FILES, sorter_t::minimumFilesPhase3);
180  this->set_resource_fraction(FILES, 1.0);
181  this->set_minimum_memory(sorter_t::minimum_memory_phase_3());
182  this->set_maximum_memory(sorter_t::maximum_memory_phase_3());
183  this->set_name("Write sorted output", PRIORITY_INSIGNIFICANT);
184  this->set_memory_fraction(1.0);
185  this->set_plot_options(node::PLOT_BUFFERED);
186  }
187 
188  void begin() override {
189  this->m_sorter->set_owner(this);
190  }
191 
192  virtual void go() override {
193  while (this->m_sorter->can_pull()) {
194  item_type && y=this->m_sorter->pull();
195  dest.push(std::move(y));
196  this->step();
197  }
198  }
199 
200  void end() override {
201  this->m_sorter.reset();
202  }
203 
204 private:
205  dest_t dest;
206 };
207 
213 template <typename T, typename pred_t, typename store_t>
214 class sort_calc_t : public node {
215 public:
217  typedef T item_type;
218 
222  typedef typename sorter_t::ptr sorterptr;
223 
225 
226  sort_calc_t(sort_calc_t && other) = default;
227 
228  template <typename dest_t>
229  sort_calc_t(dest_t dest)
230  : dest(new dest_t(std::move(dest)))
231  {
232  m_sorter = this->dest->get_sorter();
233  this->dest->add_calc_dependency(this->get_token());
234  init();
235  }
236 
237  sort_calc_t(sorterptr sorter, node_token tkn)
238  : node(tkn), m_sorter(sorter)
239  {
240  init();
241  }
242 
243  void init() {
244  set_minimum_resource_usage(FILES, sorter_t::minimumFilesPhase2);
245  set_resource_fraction(FILES, 1.0);
246  set_minimum_memory(sorter_t::minimum_memory_phase_2());
247  set_name("Perform merge heap", PRIORITY_SIGNIFICANT);
248  set_memory_fraction(1.0);
249  set_plot_options(PLOT_BUFFERED | PLOT_SIMPLIFIED_HIDE);
250  m_propagate_called = false;
251  }
252 
253  virtual void propagate() override {
254  set_steps(1000);
255  m_propagate_called = true;
256  }
257 
258  void begin() override {
259  this->m_sorter->set_owner(this);
260  }
261 
262  void end() override {
263  m_weakSorter = m_sorter;
264  m_sorter.reset();
265  }
266 
267  virtual bool is_go_free() const override {return m_sorter->is_calc_free();}
268 
269  virtual void go() override {
271  m_sorter->calc(*pi);
272  }
273 
274  virtual bool can_evacuate() override {
275  return true;
276  }
277 
278  virtual void evacuate() override {
279  sorterptr sorter = m_weakSorter.lock();
280  if (sorter) sorter->evacuate_before_reporting();
281  }
282 
283  sorterptr get_sorter() const {
284  return m_sorter;
285  }
286 
287  void set_input_node(node & input) {
289  }
290 
291 protected:
292  virtual void resource_available_changed(resource_type type, memory_size_type available) override {
293  // TODO: Handle changing parameters of sorter after data structures has been frozen, i.e. after propagate
294  if (m_propagate_called)
295  return;
296 
297  if (type == MEMORY)
298  m_sorter->set_phase_2_memory(available);
299  else if (type == FILES) {
300  m_sorter->set_phase_2_files(available);
301  }
302  }
303 
304 private:
305  sorterptr m_sorter;
306  std::weak_ptr<typename sorterptr::element_type> m_weakSorter;
307  bool m_propagate_called;
308  std::shared_ptr<Output> dest;
309 };
310 
316 template <typename T, typename pred_t, typename store_t>
317 class sort_input_t : public node {
318 public:
320  typedef T item_type;
321 
325  typedef typename sorter_t::ptr sorterptr;
326 
328  : m_sorter(dest.get_sorter())
329  , m_propagate_called(false)
330  , dest(std::move(dest))
331  {
332  this->dest.set_input_node(*this);
333  set_name("Form input runs", PRIORITY_SIGNIFICANT);
334  set_minimum_resource_usage(FILES, sorter_t::minimumFilesPhase1);
335  set_resource_fraction(FILES, 0.0);
336  set_minimum_memory(m_sorter->minimum_memory_phase_1());
337  set_memory_fraction(1.0);
338  set_plot_options(PLOT_BUFFERED | PLOT_SIMPLIFIED_HIDE);
339  }
340 
341  virtual void propagate() override {
342  if (this->can_fetch("items"))
343  m_sorter->set_items(this->fetch<stream_size_type>("items"));
344  m_propagate_called = true;
345  }
346 
347  void push(item_type && item) {
348  m_sorter->push(std::move(item));
349  }
350 
351  void push(const item_type & item) {
352  m_sorter->push(item);
353  }
354 
355  void begin() override {
356  m_sorter->begin();
357  m_sorter->set_owner(this);
358  }
359 
360 
361  virtual void end() override {
362  node::end();
363  m_sorter->end();
364  m_weakSorter = m_sorter;
365  m_sorter.reset();
366  }
367 
368  virtual bool can_evacuate() override {
369  return true;
370  }
371 
372  virtual void evacuate() override {
373  sorterptr sorter = m_weakSorter.lock();
374  if (sorter) sorter->evacuate_before_merging();
375  }
376 
377 protected:
378  virtual void resource_available_changed(resource_type type, memory_size_type available) override {
379  // TODO: Handle changing parameters of sorter after data structures has been frozen, i.e. after propagate
380  if (m_propagate_called)
381  return;
382 
383  if (type == MEMORY)
384  m_sorter->set_phase_1_memory(available);
385  else if (type == FILES) {
386  m_sorter->set_phase_1_files(available);
387  }
388  }
389 private:
390  sorterptr m_sorter;
391  std::weak_ptr<typename sorterptr::element_type> m_weakSorter;
392  bool m_propagate_called;
394 };
395 
396 template <typename child_t, typename store_t>
398  const child_t & self() const { return *static_cast<const child_t *>(this); }
399 public:
400  template <typename dest_t>
401  struct constructed {
402  private:
404  typedef typename push_type<dest_t>::type item_type;
405  typedef typename store_t::template element_type<item_type>::type element_type;
406  public:
407  typedef typename child_t::template predicate<element_type>::type pred_type;
409  };
410 
411  template <typename dest_t>
412  typename constructed<dest_t>::type construct(dest_t dest) {
413  typedef typename push_type<dest_t>::type item_type;
414  typedef typename store_t::template element_type<item_type>::type element_type;
415  typedef typename constructed<dest_t>::pred_type pred_type;
416 
418  std::move(dest),
420  self().template get_pred<element_type>(),
421  m_store));
422  this->init_sub_node(output);
424  this->init_sub_node(calc);
426  this->init_sub_node(input);
427 
428  return std::move(input);
429  }
430 
431  sort_factory_base(store_t store): m_store(store) {}
432 private:
433  store_t m_store;
434 
435 };
436 
440 template <typename store_t>
441 class default_pred_sort_factory : public sort_factory_base<default_pred_sort_factory<store_t>, store_t> {
442 public:
443  template <typename item_type>
444  class predicate {
445  public:
446  typedef std::less<item_type> type;
447  };
448 
449  template <typename T>
450  std::less<T> get_pred() const {
451  return std::less<T>();
452  }
453 
454  default_pred_sort_factory(const store_t & store)
455  : sort_factory_base<default_pred_sort_factory<store_t>, store_t>(store)
456  {
457  }
458 };
459 
463 template <typename pred_t, typename store_t>
464 class sort_factory : public sort_factory_base<sort_factory<pred_t, store_t>, store_t> {
465 public:
466  template <typename Dummy>
467  class predicate {
468  public:
469  typedef pred_t type;
470  };
471 
472  sort_factory(const pred_t & p, const store_t & store)
473  : sort_factory_base<sort_factory<pred_t, store_t>, store_t>(store)
474  , pred(p)
475  {
476  }
477 
478  template <typename T>
479  pred_t get_pred() const {
480  return pred;
481  }
482 private:
483  pred_t pred;
484 };
485 
486 } // namespace bits
487 
491 inline pipe_middle<bits::default_pred_sort_factory<default_store> >
492 sort() {
494  return pipe_middle<fact>(fact(default_store())).name("Sort");
495 }
496 
501 template <typename store_t>
502 inline pipe_middle<bits::default_pred_sort_factory<store_t> >
503 store_sort(store_t store=store_t()) {
505  return pipe_middle<fact>(fact(store)).name("Sort");
506 }
507 
511 template <typename pred_t>
512 inline pipe_middle<bits::sort_factory<pred_t, default_store> >
513 sort(const pred_t & p) {
515  return pipe_middle<fact>(fact(p, default_store())).name("Sort");
516 }
517 
522 template <typename pred_t, typename store_t>
523 inline pipe_middle<bits::sort_factory<pred_t, store_t> >
524 sort(const pred_t & p, store_t store) {
526  return pipe_middle<fact>(fact(p, store)).name("Sort");
527 }
528 
529 template <typename T, typename pred_t=std::less<T>, typename store_t=default_store>
531 
532 namespace bits {
533 
537 template <typename T, typename pred_t, typename store_t>
539 public:
542  typedef input_t constructed_type;
544  typedef typename sorter_t::ptr sorterptr;
545 
546  passive_sorter_factory_input(sorterptr sorter, node_token calc_token)
547  : m_sorter(sorter)
548  , m_calc_token(calc_token) {}
549 
550  constructed_type construct() {
551  calc_t calc(std::move(m_sorter), m_calc_token);
552  this->init_node(calc);
553  input_t input(std::move(calc));
554  this->init_node(input);
555  return input;
556  }
557 
558 private:
559  sorterptr m_sorter;
560  node_token m_calc_token;
561 };
562 
566 template <typename T, typename pred_t, typename store_t>
568 public:
570  typedef typename sorter_t::ptr sorterptr;
572 
573  passive_sorter_factory_output(sorterptr sorter, node_token calc_token)
574  : m_sorter(sorter)
575  , m_calc_token(calc_token)
576  {}
577 
578  constructed_type construct() {
579  constructed_type res(std::move(m_sorter));
580  res.add_calc_dependency(m_calc_token);
581  init_node(res);
582  return res;
583  }
584 private:
585  sorterptr m_sorter;
586  node_token m_calc_token;
587 };
588 
589 } // namespace bits
590 
598 template <typename T, typename pred_t, typename store_t>
599 class passive_sorter {
600 public:
602  typedef T item_type;
606  typedef typename sorter_t::ptr sorterptr;
609 
610  passive_sorter(pred_t pred = pred_t(),
611  store_t store = store_t())
612  : m_sorterInput(std::make_shared<sorter_t>(pred, store))
613  , m_sorterOutput(m_sorterInput)
614  {}
615 
616  passive_sorter(const passive_sorter &) = delete;
617  passive_sorter & operator=(const passive_sorter &) = delete;
618  passive_sorter(passive_sorter && ) = default;
619  passive_sorter & operator=(passive_sorter &&) = default;
620 
623 
628  tp_assert(m_sorterInput, "input() called more than once");
630  std::move(m_sorterInput), m_calc_token);
631  return {std::move(ret)};
632  }
633 
638  tp_assert(m_sorterOutput, "output() called more than once");
640  std::move(m_sorterOutput), m_calc_token);
641  return {std::move(ret)};
642  }
643 
644 private:
645  sorterptr m_sorterInput, m_sorterOutput;
646  node_token m_calc_token;
647 };
648 
649 } // namespace pipelining
650 
651 } // namespace tpie
652 
653 #endif
T item_type
Type of items sorted.
Definition: sort.h:108
sorter_t::ptr sorterptr
Smart pointer to sorter_t.
Definition: sort.h:606
push_type< dest_t >::type item_type
Type of items sorted.
Definition: sort.h:165
output_pipe_t output()
Get the output pull node.
Definition: sort.h:637
pipe_begin< factory< bits::input_t, file_stream< T > &, stream_options > > input(file_stream< T > &fs, stream_options options=stream_options())
Pipelining nodes that pushes the contents of the given file stream to the next node in the pipeline...
Definition: file_stream.h:379
virtual void go() override
For initiator nodes, execute this phase by pushing all items to be pushed.
Definition: sort.h:149
Memory management subsystem.
virtual void propagate() override
Propagate stream metadata.
Definition: sort.h:341
Sort factory using the given predicate as comparator.
Definition: sort.h:464
The base class for indicating the progress of some task.
void add_memory_share_dependency(const node_token &dest)
Called by implementers to declare a node memory share dependency, that is, a requirement that another...
void begin() override
Begin pipeline processing phase.
Definition: sort.h:127
Base class of all pipelining factories.
Definition: factory_base.h:73
Merge sorting consists of three phases.
Definition: merge_sorter.h:150
void init_node(node &r)
Initialize node constructed in a subclass.
Definition: factory_base.h:134
const node_token & get_token() const
Get the node_token that maps this node's ID to a pointer to this.
Definition: node.h:632
Pipelined sorter with push input and pull output.
Definition: sort.h:530
Pipe sorter middle node.
Definition: sort.h:41
merge_sorter< T, true, pred_t, store_t > sorter_t
Type of the merge sort implementation used.
Definition: sort.h:54
merge_sorter< item_type, true, pred_t, store_t > sorter_t
Type of the merge sort implementation used.
Definition: sort.h:323
virtual void evacuate() override
Overridden by nodes that have data to evacuate.
Definition: sort.h:278
Base class of all nodes.
Definition: node.h:78
T item_type
Type of items sorted.
Definition: sort.h:217
T item_type
Type of items sorted.
Definition: sort.h:51
void add_push_destination(const node_token &dest)
Called by implementers to declare a push destination.
Class to deduce the item_type of a node of type T.
Definition: node_traits.h:152
progress_indicator_base * proxy_progress_indicator()
Get a non-initialized progress indicator for use with external implementations.
sorter_t::ptr sorterptr
Smart pointer to sorter_t.
Definition: sort.h:113
merge_sorter< item_type, true, pred_t, store_t > sorter_t
Type of the merge sort implementation used.
Definition: sort.h:604
virtual bool can_evacuate() override
Overridden by nodes that have data to evacuate.
Definition: sort.h:274
sorter_t::ptr sorterptr
Smart pointer to sorter_t.
Definition: sort.h:172
void forward(std::string key, T value, memory_size_type k=std::numeric_limits< memory_size_type >::max())
Called by implementers to forward auxiliary data to successors.
Definition: node.h:564
Simple parallel quick sort implementation with progress tracking.
void set_maximum_memory(memory_size_type maximumMemory)
Called by implementers to declare maximum memory requirements.
Definition: node.h:217
virtual void propagate() override
Propagate stream metadata.
Definition: sort.h:253
Factory for the passive sorter output node.
Definition: sort.h:567
Sort factory using std::less as comparator.
Definition: sort.h:441
virtual void propagate() override
Propagate stream metadata.
Definition: sort.h:62
merge_sorter< item_type, true, pred_t, store_t > sorter_t
Type of the merge sort implementation used.
Definition: sort.h:111
void set_name(const std::string &name, priority_type priority=PRIORITY_USER)
Set this node's name.
Factory for the passive sorter input node.
Definition: sort.h:538
void set_minimum_resource_usage(resource_type type, memory_size_type usage)
Called by implementers to declare minimum resource requirements.
void set_minimum_memory(memory_size_type minimumMemory)
Called by implementers to declare minimum memory requirements.
Definition: node.h:207
merge_sorter< item_type, true, pred_t, store_t > sorter_t
Type of the merge sort implementation used.
Definition: sort.h:220
virtual void resource_available_changed(resource_type type, memory_size_type available) override
Called by the resource manager to notify the node's available amount of resource has changed...
Definition: sort.h:292
bits::sort_pull_output_t< item_type, pred_t, store_t > output_t
Type of pipe sorter output.
Definition: sort.h:608
input_pipe_t input()
Get the input push node.
Definition: sort.h:627
Pipe sorter pull output node.
Definition: sort.h:105
void init_sub_node(node &r)
Initialize node constructed in a subclass.
Definition: factory_base.h:157
pipe_middle< tempfactory< bits::item_type_t< T > > > item_type()
Create item type defining identity pipe node.
Definition: helpers.h:654
Pipe sorter push output node.
Definition: sort.h:162
T item_type
Type of items sorted.
Definition: sort.h:602
void set_plot_options(flags< PLOT > options)
Set options specified for plot(), as a combination of node::PLOT values.
Definition: node.h:459
virtual void end()
End pipeline processing phase.
Definition: node.h:329
void end() override
End pipeline processing phase.
Definition: sort.h:262
void step(stream_size_type steps=1)
Step the progress indicator.
Definition: node.h:654
void begin() override
Begin pipeline processing phase.
Definition: sort.h:258
sorter_t::ptr sorterptr
Smart pointer to sorter_t.
Definition: sort.h:56
void set_memory_fraction(double f)
Set the memory priority of this node.
Definition: node.h:225
pipe_middle< bits::default_pred_sort_factory< default_store > > sort()
Pipelining sorter using std::less.
Definition: sort.h:492
virtual void resource_available_changed(resource_type type, memory_size_type available) override
Called by the resource manager to notify the node's available amount of resource has changed...
Definition: sort.h:77
A pipe_middle class pushes input down the pipeline.
Definition: pipe_base.h:241
void begin() override
Begin pipeline processing phase.
Definition: sort.h:355
pipe_end< termfactory< bits::output_t< T >, file_stream< T > & > > output(file_stream< T > &fs)
A pipelining node that writes the pushed items to a file stream.
Definition: file_stream.h:431
void set_resource_fraction(resource_type type, double f)
Set the resource priority of this node.
sorter_t::ptr sorterptr
Smart pointer to sorter_t.
Definition: sort.h:325
virtual void go() override
For initiator nodes, execute this phase by pushing all items to be pushed.
Definition: sort.h:269
Temporary file names.
Fantastic store strategy.
Definition: store.h:218
virtual void resource_available_changed(resource_type type, memory_size_type available) override
Called by the resource manager to notify the node's available amount of resource has changed...
Definition: sort.h:378
virtual void evacuate() override
Overridden by nodes that have data to evacuate.
Definition: sort.h:372
sorter_t::ptr sorterptr
Smart pointer to sorter_t.
Definition: sort.h:222
void set_steps(stream_size_type steps)
Called by implementers that intend to call step().
#define tp_assert(condition, message)
Definition: tpie_assert.h:48
pipe_middle< bits::default_pred_sort_factory< store_t > > store_sort(store_t store=store_t())
A pipelining node that sorts large elements indirectly by using a store and std::less.
Definition: sort.h:503
void end() override
End pipeline processing phase.
Definition: sort.h:140
bool can_fetch(std::string key)
Find out if there is a piece of auxiliary data forwarded with a given name.
Definition: node.h:589
T item_type
Type of items sorted.
Definition: sort.h:320
sort_output_base< item_type, pred_t, store_t > p_t
Base class.
Definition: sort.h:168
merge_sorter< item_type, true, pred_t, store_t > sorter_t
Type of the merge sort implementation used.
Definition: sort.h:170
virtual void go() override
For initiator nodes, execute this phase by pushing all items to be pushed.
Definition: sort.h:192
logstream & log_warning()
Return logstream for writing warning log messages.
Definition: tpie_log.h:157
virtual bool can_evacuate() override
Overridden by nodes that have data to evacuate.
Definition: sort.h:368
virtual void end() override
End pipeline processing phase.
Definition: sort.h:361
Pipe sorter input node.
Definition: sort.h:44
void begin() override
Begin pipeline processing phase.
Definition: sort.h:188
void end() override
End pipeline processing phase.
Definition: sort.h:200