Guidesort: Simpler Optimal Deterministic Sorting for the Parallel Disk Model

A new algorithm, Guidesort, for sorting in the uniprocessor variant of the parallel disk model (PDM) of Vitter and Shriver is presented. The algorithm is deterministic and executes a number of (parallel) I/O operations that comes within a constant factor $C$ of the optimum. The algorithm and its analysis are simpler than those proposed in previous work, and the achievable constant factor $C$ of essentially 3 appears to be smaller than for all other known deterministic algorithms, at least for plausible parameter values.


Introduction
Sorting is an important problem. In the seventies Knuth quoted an estimate that over 25% of computers' running time is spent on sorting [7]. Frequently the data sets to be sorted are so large that they do not fit in internal memory and must be held on external storage, often one or more magnetic disks or similar devices. In this setting of massive data, sorting acquires even more importance because a high number of algorithms that use external storage efficiently do so by reducing other problems to sorting, so that the time to sort almost can be viewed as playing the role that linear time has in RAM computation.
Accesses to magnetic disks are much slower than CPU operations and accesses to internal memory. A natural and increasingly popular way to sort faster is to use many disks in parallel. Magnetic disks have high latencies, so that efficiency dictates that an access to a magnetic disk must be used to transfer not one data item, but a whole block of many data items. The parallel disk model of Vitter and Shriver [14] tries to capture these characteristics of disk systems and has been used for much of the extensive research on sorting with several disks.

Model and Problem Statement
An instance of the uniprocessor variant of the parallel disk model or PDM of Vitter and Shriver [14] is specified via three positive integers, M, B and D with 2B ≤ M. It features a machine comprising an internal memory of M cells and D disks, each with an infinite number of cells. Every disk is linearly ordered and partitioned into block frames of B consecutive cells, each of which can accommodate a block of B data items. In slight deviation from the original definition of the PDM, we will assume that the internal memory is also linearly ordered and partitioned into block frames of B consecutive cells and-therefore-that M/B is an integer. An I/O operation or, for short, an I/O can copy the blocks stored in D pairwise distinct block frames in the internal memory to block frames on D pairwise distinct disks (an output operation) or vice versa (an input operation). Thus the disks are assumed to be synchronized. The description in [14] does not indicate explicitly whether it is also possible to transfer fewer than D blocks between pairwise distinct block frames in the internal memory and block frames on as many pairwise distinct disks; here we will assume this to be the case. Arbitrary computation (internal computation) can take place on data stored in the internal memory, whereas items stored on disks can participate in computation only after being input to the internal memory. An algorithm is judged primarily by the number of I/O operations that it executes, computation in the internal memory usually being considered free.
So that operations in the internal memory and I/O operations can specify their arguments, we assume that the disks, the cells in the internal memory and the block frames both in the internal memory and on each disk are numbered consecutively, starting at 0 (say). A number of conventions make the PDM convenient to argue about, but less precise. First, the meaning of a "cell" depends on the problem under consideration. In the context of sorting, as relevant here, a cell is the amount of memory needed to store one of the items to be sorted or a comparable object (e.g., for sorting it is generally assumed that one can ensure at no cost that the keys of the input items are pairwise distinct by appending to each its position in the input). Second, the only space accounted for is that taken up by "data items", not that needed to realize the control structure of an algorithm under execution. E.g., algorithms like those discussed in the following may want to manipulate such data structures as a recursion stack and various vectors indexed by disk numbers. Space for such bookkeeping information is assumed implicitly to be available whenever needed.
It is customary to restrict the parallel disk model by imposing an additional condition that says, informally, that M is sufficiently large relative to B and D. The condition varies from description to description, however, and seems to reflect the requirements of particular algorithms more than any fundamental deliberation concerning the model. E.g., [14] requires that D ≤ ⌊M/B⌋, [3] that M ≥ 2DB, and [11] that DB ≤ ⌊(M − M β )/2⌋ for some fixed β < 1. Since no more than M/B disks can take part in a (parallel) I/O operation, the condition D ≤ M/B seems somewhat more canonical than the others, and we will adopt it here (alternatively, D can be interpreted as the minimum of M/B and a true number of disks). It cannot be a priori excluded, however, that more than M/B disks can be put to good use in a PDM algorithm (cf. the RAMBO model of Fredman and Saks [5]).
A sequence of items is said to be stored in the striped format if its blocks are distributed over the disks in a round-robin fashion. More precisely, a sequence (x 0 , . . . , x N −1 ) is stored in the striped format if there are (known) nonnegative integers a 0 , . . . , a D−1 such that the following holds for i = 0, . . . , N − 1: If ⌊i/B⌋ = qD + r for integers q and r with q ≥ 0 and 0 ≤ r < D, then x i is stored on the disk numbered r in the block frame numbered a r + q. Every sequence for which nothing else is stated explicitly in the following is assumed to be stored in the striped format.

The Challenge
In the remainder of the paper, consider the problem of sorting a sequence of N > M items and take n = ⌈N/B⌉ (the number of block frames occupied by the input) and m = M/B (the number of block frames in the internal memory). Without loss of generality we will assume that the N items to be sorted have pairwise distinct keys. The last of the n blocks of input may contain a segment of data beyond the N items to be sorted. Such a "foreign" segment should be treated as a sorted sequence of dummy items larger than all real items, so that the segment will not be modified by the sorting.
In the sequential case, i.e., for D = 1, we can sort within A PDM machine with D disks can simulate one with a single disk but a larger block size of B ′ = BD without slowdown by operating the disks in lock-step, i.e., groups of corresponding block frames, one from each disk, are formed once and for all, and every I/O operation inputs from or outputs to the block frames in a group. Applying this to the sequential merging algorithm discussed above and assuming that m ′ = m/D is an integer and at least 2 yields a sorting algorithm that uses at most 2⌈n/D⌉⌈log m ′ (n/D)⌉ I/Os. Call this algorithm sorting by naive m ′ -way striping. If D is sufficiently small relative to m, there is no significant difference between logarithms to base m and logarithms to base m ′ . In particular, if D = O(m 1−ǫ ) for some fixed ǫ > 0, the bound of 2⌈n/D⌉⌈log m ′ (n/D)⌉ I/Os is within a constant factor of the second lower bound. As D approaches m, however, the problem becomes increasingly difficult. An attempt to parallelize the sequential merging algorithm simply by inputting the D next blocks in parallel meets with the difficulty that the D next blocks may not be known and, even if they are, may not be stored on D distinct disks. This could be called the problem of read contention.

The New Result
We present a new algorithm, Guidesort, for sorting in the PDM. The algorithm is deterministic, simple and easy to analyze and to implement. If the factor of 1 + F ′ (M, B, D, N) of the previous subsection is ignored, the number of I/Os executed by Guidesort is (C/D)Sort M,B (N), where C is approximately 3 for typical values of M, B and D-for brevity, the constant factor of Guidesort is 3. As D becomes large relative to m and B, C grows to a maximum of around 9.
Guidesort works by computing a guide that can be used to redistribute blocks to disks in such a way that the read-contention problem disappears. More details are provided in Section 2.

Previous Work
As befits a fundamental problem of great practical importance, a high number of algorithms for sorting in the PDM has been proposed. Many were qualified as simple. We are not aware, however, of any previously published algorithm that can be proved efficient using simple arguments. Some of the algorithms work via repeated merging [1,3,4,6,8,11,12] and hence bottom-up (this also applies to Guidesort), while others use the approximately inverse process of repeated splitting at chosen partitioning elements [6,10,13,14] and therefore operate in a top-down fashion.
Most published algorithms resort to randomization to cope with the readcontention problem. Some of them [3,6,13] are optimal and achieve constant factors close to 1 if D is sufficiently small relative to m (this is also when sorting by naive striping comes into its own), but as D approaches m their performance degrades.
Explicit constant factors were not indicated for any of the optimal deterministic algorithms published to date. The scheme of Aggarwal and Plaxton [1], based on Sharesort and bottom-up, but with some elements of top-down, is applicable to a variety of computational models. Its constant factor seems difficult to determine, but the generality of the approach lets one expect it to be quite large. Balance Sort by Nodine and Vitter [10] is a deterministic top-down algorithm that depends on subroutines for complicated tasks such as load balancing, matching and derandomization. Again, the constant factor appears to be large.
Greed Sort, also due to Nodine and Vitter [11], is perhaps closest in spirit to the Guidesort algorithm presented here. It is deterministic, based on repeated merging, and sufficiently simple that estimating its constant factor seems feasible. In order to merge, Greed Sort first carries out an approximate R-way merge, for a certain R, that brings each item to a position within some distance L of its rank in the sorted combined sequence, and then finishes by using Leighton's Columnsort [9] to sort locally within overlapping segments of 2L items each.
As indicated in [11], the number of I/Os executed by the approximate merge of Greed Sort is between 3 and 5 times the number of blocks involved. Subsequently each block participates in two applications of Columnsort. Columnsort, in turn, consists of 8 steps, each of which reads and writes every block at least once. Thus each recursive level needs at least 3 + 2 · 8 · 2 = 35 I/Os per block. In addition, R is chosen approximately as √ m, so that sorting based on R-way merging has about twice as many recursive levels as sorting by m-way merging. Since each recursive level in sequential sorting reads and writes each block just once (2 I/Os), this calculation indicates a constant factor for Greed Sort of at least 35. In fact, a more detailed study of [11] reveals the estimate of 35 to be optimistic, especially if D is not much smaller than m. The work described here was borne out of the author's desire to have an optimal sorting algorithm for the PDM simple enough to serve as the basis of a homework problem. Whereas this seemed out of the question for all previously published algorithms, the plan was carried out successfully for Guidesort.

Guidesort
Guidesort still sorts recursively, with the base case given by internal sorting of at most M items and each nonterminal call executing a multiway merge of recursively sorted sequences. Only the merge is done in a novel way.

The Main Idea
Call each sorted input sequence of a merge a run and consider a multiway merge of runs partitioned into blocks. Assume first that the blocks are input one by one. As long as there is enough internal memory to store one block from each run and to buffer the output, each input block must be read only once.
Define the leader of a block of items to be its smallest item. It is natural to read the next block from a run as soon as the last item in the previous block from that run has been consumed, i.e., moved to the output buffer. If we knew the leader x of the next block in the run, however, we could postpone reading that block until just before x is to be consumed. This shows that if the blocks of all runs are input in the order given by the sorted order of their leaders, it is still the case that each input block must be read only once. We can discover the appropriate canonical order by forming the sample of each run as the sorted sequence of its leaders and merging the samples, which creates the canonical sequence. Since the samples are far smaller than the full runs, the cost of merging them is usually negligible.
The computation of the canonical sequence was also considered by Hutchinson, Sanders and Vitter [6], who used the term "trigger" for what we call a leader.
Suppose now that we manage to input the blocks in the canonical order in batches of D ≤ D consecutive blocks each, where a batch is input in a single I/O operation. If we provide an additional buffer of D block frames to hold the latest input batch, it will still be the case that each input block must be read only once. In order for it to be possible to consume the input in batches, the blocks in each batch must be stored on different disks. In addition, to make it possible to produce each run D blocks at a time, we must ensure that if the run is partitioned into subsequences of D consecutive blocks each, the blocks within each subsequence are stored on different disks. Viewed more abstractly, we are faced with the problem of coloring the vertices of a graph G defined by the canonical sequence with at most D colors in such a way that no two adjacent vertices receive the same color. The vertices of G correspond to the leaders or the blocks in all runs, each edge joins two blocks that must be stored on distinct disks, and the D colors correspond to the D disks. The degree of G is bounded by 2(D − 1). If we choose D = D, coloring G may be difficult or impossible. With D ≤ ⌈D/2⌉, however, the obvious greedy algorithm can color the canonical sequence in a single pass. Call the resulting sequence of colored leaders the guide. While keeping the full guide, we also transfer the colors of leaders found to the original samples. This can be done with a recursive splitting that reverses the steps of the merge that created the canonical sequence.
To carry out the top-level merge, we first process each run, redistributing its blocks to the disks specified in its colored sample. This can be accomplished in a single pass over the run synchronized with a pass over its colored sample. Subsequently the top-level merge of the runs can proceed under the control of the guide, D blocks at a time, and this process can also create the corresponding sample for the merge at the next higher recursive level at essentially no additional cost.
To summarize, Guidesort comprises the following steps, illustrated in Fig. 1  While the back-of-the-envelope estimate essentially leads to the correct result, a more precise argument must account for the cost of Steps 1-3, which is not always negligible, and must also work without a number of assumptions that were made implicitly above. This is the topic of the next two subsections.

A Realistic Simple Special Case
Define the block length of a stored sequence to be the number of block frames that it occupies (fully or in part). Let us be more specific about the recursive sorting algorithm, which is parameterized by an integer r with 2 ≤ r ≤ m. When asked to sort a sequence of block length p, the algorithm first computes k = min{⌈p/m⌉, r}. If k = 1, the sorting takes place in the internal memory without recursive calls. Otherwise the input sequence is split into k subsequences, each of block length ⌊p/k⌋ or ⌈p/k⌉, and the k subsequences are sorted recursively and subsequently merged. The main point is that although the algorithm "nominally" uses r-way merging, a call that issues terminal calls issues only as many as necessary. Without increasing the depth of the recursion, this ensures that each terminal call deals with at least m/2 blocks and therefore that the number of terminal calls and the number of calls altogether are O(n/m). This is useful for dealing with rounding issues. E.g., if each merge executed as part of the overall sorting is associated with a quantity of the form ⌈t⌉, where t is some expression, we can upper-bound the sum of ⌈t⌉ over all merges by summing t over all merges and adding O(n/m).
Our analysis frequently sums the number of I/Os of a particular kind over all merges carried out as part of the overall sorting. We shall use the term "accumulated" to denote this situation, i.e., "accumulated" means "summed over all merges". Let z be the accumulated total block length of the runs of all merges. Exactly as in the sequential sorting algorithm, z ≤ n⌈log r n⌉. Similarly, let y be the accumulated block length of all samples produced by the algorithm. Since each leader in a sample "represents" B items, an application of the counting method set out at the end of the previous paragraph shows that y = z/B + O(n/m).
Step 1 merges at most r samples. If the block length of some sample is < m, and therefore the block lengths of all samples are ≤ m, the samples are first partitioned into bundles in such a way that the total block length of the runs in each bundle, except possibly the last bundle, is at least m/2 and at most m. The blocks in each bundle are then input, D at a time, sorted internally, and output as one sorted sequence, again D blocks at a time, at an accumulated cost of 2y/D + O(n/m) I/Os. Assume that the number of sorted runs (original samples or sorted bundles) at this point is r ′ . The r ′ runs are merged in a binary merge tree of height ⌈log 2 r ′ ⌉ in which each binary merge is carried out with D 1 disks that operate in lock-step to simulate a single disk with a block size of B ′ = D 1 B.
Observe that n/m ≤ n/D = O((z/D)(1/log m n)) (a convexity argument shows that we even have n/D ≤ (z/D)(1/log m n)). When r ′ runs are merged in a binary merge tree, each run, except possibly the last one, contains at least M/2 leaders that "represent" at least MB/2 input items. With respect to a block size of B ′ , the accumulated block length of all runs input to nontrivial binary merge trees-those with r ′ ≥ 2 leaves-is therefore O(z/(D 1 B)) = O(z/(DB)), and the merges can be carried out with O(z⌈log 2 r⌉/(DB)) = O((z ln m)/(DB)) I/Os. Altogether, the number of I/Os executed by Step 1 is O((z ln m)/(DB) + n/m). This bound also covers Step 3, which reverses the merging to transfer the information attached to leaders in Step 2 from the guide to the samples. Steps 1 and 3 need 2D 1 block frames of internal memory, which are available since D 1 ≤ m/2.
Step 2 colors the canonical sequence. Say that a color is used recently in a sequence of k colored objects if it is the color of one of the min{D − 1, k} last objects in the sequence. The leaders are processed in the order in which they occur in the canonical sequence, and each leader x is given a color in {0, . . . , D − 1} that is used recently neither in the complete sorted sequence of colored leaders nor in its (not necessarily contiguous) subsequence of leaders drawn from the same sample as x. To accomplish its task, the algorithm maintains at most r + 1 history sequences of the chronologically ordered recently used colors overall and within each sample. To process a leader, the algorithm identifies and assigns an appropriate color to the leader and updates two history sequences accordingly, all of which is straightforward. In addition, the leaders of each color are numbered consecutively in the order in which they are colored and the number of each leader, called its index, is attached to the leader. We will assume that the history sequences with their at most (r + 1)(D − 1) color values can be stored in q = ⌈(r + 1)(D − 1)/B⌉ block frames. Using an additional input/output buffer of D 2 block frames, we can execute Step 2 with an accumulated number of I/Os of 2y/D 2 + O(n/m) = 2z/(D 2 B) + O(n/m). We must ensure that q + D 2 ≤ m.
Step 4 redistributes blocks to new disks one run at a time. When processing a run of ℓ blocks, the algorithm inputs the ℓ blocks and, interleaved, a sample of ℓ colored leaders and, for i = 1, . . . , ℓ, stores the ith block on the disk corresponding to the color of the ith leader and in a block frame whose number is the index of the ith leader plus an offset chosen for that disk. Thus the blocks on each disk are stored compactly, but they are not necessarily written in the order of increasing frame numbers. With a "primary" input buffer of D 4 block frames for the input blocks, a "secondary" input buffer of D L block frames for the leaders and an output buffer of D block frames for the redistributed blocks, the accumulated number of I/Os spent in Step 4 is z/D 4 + z/D + y/D L + O(n/m) = z(1/D 4 + 1/D + 1/(D L B)) + O(n/m). We must ensure that D 4 + D + D L ≤ m.
Step 5 actually merges the runs with the aid of one block frame of input buffer for each run, a total of at most r block frames, an input buffer of D block frames for the latest batch (D − 1 block frames actually suffice), two buffers of D L block frames each for the guide, which is input, and the sample for the next recursive level, which is output, and finally a buffer of D 5 block frames for the primary output, the final outcome of the merge. The accumulated number of I/Os is z/D + z/D 5 + 2y/D L + O(n/m) = z(1/D + 1/D 5 + 2/(D L B)) + O(n/m), and we must ensure that r + D + D 5 + 2D L ≤ m.
Collecting the contributions identified above and not forgetting the O(n/D) I/Os consumed by terminal calls of the recursive sorting algorithm, we arrive at a total number of I/Os for the complete sorting of

The General Case: An Order-of-Magnitude Bound
In order to deal with situations in which B is smaller than D or ln m is not small relative to B, we generalize the algorithm by introducing an additional parameter, s, which must be a positive divisor of D. The algorithm described so far corresponds to the special case s = 1.
Whereas until now a leader was the smallest item within a block, we redefine it to be the smallest item within a segment of s consecutive blocks in some run. Thus each run is partitioned into segments of sB items each, except that the last segment may be smaller, and each segment contributes only a single leader to the sample of the run. As a consequence, the accumulated block length of all samples now is y = z/(sB) + O(n/m). We stipulate that the s blocks that form a segment are colored using consecutive colors that begin at a multiple of s. An intuitive view of this is that the task now is to color segments with one of 2D/s − 1 colors so as to avoid the at most D/s − 1 most recent colors both overall and within the same run. This has the beneficial effect of reducing the state information that must be kept by the greedy coloring in Step 2 from (r + 1)(D −1) colors to at most (r + 1)(D − 1)/s colors, which can be stored in q = ⌈(r + 1)(D − 1)/(sB)⌉ blocks.
On the other hand, in order for the leaders to fulfil their function, Step 5 must be changed to input runs whole segments at a time, which means that an input buffer of s block frames rather than of a single block frame must be provided for each run. The requirement for Step 5 accordingly becomes rs + D + D 5 + 2D L ≤ m for the revised sorting algorithm, while the total number of I/Os generalizes from (1) to For m ≤ 3 and therefore D ≤ 3, sequential sorting obviously works within  N)). If we want to prove a more precise bound, we must choose the parameters more carefully.

The General Case: Good Constant Factors
In order to obtain the best result, we change the algorithm slightly: In Step 4, instead of having separate primary input and output buffers of D 4 and D block frames, respectively, we use a single buffer of D 4 block frames for both input and output. This is trivial, but requires us to ensure that D | D 4 (i.e., D divides D 4 ). Besides r, s, D, D 2 , D 4 , D 5 and D L being positive integers, the conditions that the parameters must satisfy for the final algorithm are the following: rs Our task at this point is to (approximately) minimize the I/O bound of (2) subject to the constraints (3). As an aid in dealing with the divisibility requirements of the last constraint, we first prove a simple technical lemma that, informally, says that, given two positive integers a and b, we can make the smaller divide the larger without changing their sorted order by lowering each by less than half and b by less than its square root. Let N = {1, 2, . . .}.
There is a function f : N 2 → N 2 that can be evaluated in constant time and has the following properties : For all a, b ∈ N, if (a ′ , b ′ ) = f (a, b), then From now on assume that 2 ≤ a ≤ b − 2. Since then b ≥ 4 and √ b ≤ b/2, we need no longer verify the condition b ′ > b/2 explicitly. Consider two cases: If a ≤ √ b + 1, take a ′ = a and b ′ = ⌊b/a⌋a ≤ b and observe that if a < √ b + 1, , take a ′ = ⌊b/⌈b/a⌉⌋ ≤ a and observe that if a ≥ b/2, then a ′ = ⌊b/2⌋ ≥ ⌊(a + 2)/2⌋ > a/2, whereas if a < b/2, then we can successively conclude that a ≥ 4, b ≥ 9 and a ≥ 5 and then that a ′ ≥ ⌊b/(b/a + 1)⌋ = ⌊ab/(b + a)⌋ ≥ ⌊2a/3⌋ > a/2. Also take and note that b ′ ≤ b is obvious from the third expression in the previous line.
The stage is set for our main result: Proof. Because of the term 1/ √ D in the expression for F ′ , we can assume without loss of generality that m is larger than a certain constant m 0 , which we choose as m 0 = 2 12 . As justified earlier, we will also assume that D ≥ √ m. What remains is to prove that r ≥ 2 or, equivalently, that r 2 ≥ 4 and r 5 ≥ 2. First, and hence, by the second property of Lemma 2.1, s ≥ (1/2) 7D/(16B). Now (m − 1)sB/(D − 1) ≥ 2sB ≥ 7D/16 ≥ 5, where the last inequality follows from D ≥ √ m ≥ 2 6 , and this shows that r 2 ≥ 4.
In order to demonstrate that r 5 ≥ 2, we prove that m − D − D 5 − 2D L ≥ 2s.
We next bound the number of I/Os executed by the algorithm, essentially by estimating the values of its parameters. First By the third property of Lemma 2.1, it follows that As observed earlier, (m − 1)sB/(D − 1) ≥ r 2 +1. But r 2 +1 ≥ 2r+1 ≥ (3/2)(r+1) and therefore (r + 1)(D − 1)/(sB) ≤ (2/3)(m−1). As a consequence, D 2 = Ω(D). Because D 4 is just 2D, Noting that for x ≥ 1, we find that We are almost ready to sum the terms in (2). Observe first that since D 4 , D 5 and D are all larger than ǫD for some fixed ǫ > 0, our bound of the form D 4 = D(1 − O(· · · )) yields a bound of the form 1/D 4 = (1/D)(1 + O(· · · )), and analogously for D 5 and D. We already noted that sB = Ω( √ DB). Hence We also have z ln m sDB Now the total number of I/Os can be seen to be By the second property of Lemma 2. where F ′ is as in the theorem. To show that r 2 ≥ 4, the proof of Theorem 2.2 argued that 2sB ≥ 5, a relation that is a triviality for B ≥ 16. In the case of r 5 ≥ 2, the relation to show was m > 16s − 10. But for 8 ≤ m ≤ 16 this is clear since s = 1, while for m ≥ 16 it follows from s ≤ D/B ≤ (1/4) √ m.
It is easy to see that the asymptotic assertions of Theorem 2.2 continue to hold.

Conclusion
Guidesort is simple and based on a natural idea. If a reasonably programmed algorithm for sorting through multiway merging is available, the new algorithm can be grafted onto it by replacing the old subroutine for multiway merging by one that executes Steps 1-5.
Step 1 is standard merging. Because the sequences to be merged are smaller by a factor of B than the actual runs, in many practical situations the merging can be done any which way. The algorithm proposed here that can be viewed as the final part of sorting by naive 2-way striping is also very easy to implement. Step 3 is an even simpler approximately inverse operation.
Step 5 is standard merging, except that the tests to identify the disks from which to input the next blocks have been executed beforehand.
Step 2 implements a straightforward greedy algorithm, and Step 4 is a trivial redistribution of blocks according to a precomputed pattern.
While most or all previous algorithms are optimal with respect to internal computation, i.e., execute O(N ln N) steps of internal computation to sort N items, it is not obvious how to carry out the greedy coloring of our Step 2 in less than Θ(D/s) time per leader (or Θ(D/(sw) + 1) time per leader if w bits can be manipulated together in constant time), for which reason we can bound the amount of internal computation of Guidesort only by O(N ln N +(nD/s) log m n) = O(N(ln N + D/B 3 log m n)). For realistic parameter values, however, this is still O (N ln N).
It may seem deplorable that the function F ′ should include an "error term" of O(1/log m n), which can be quite large even for realistic values of the parameters n and m. However, recall that the term represents just O(n/D) I/Os, i.e., the cost of a single pass over the input at full parallel speed. Approximating the total depth of the leaves in the recursion tree of a bottom-up or top-down algorithm similar to those published to date by ⌈log m n⌉ times the number of leaves incurs an error of the same magnitude. An "error" of O(n/m), which is comparable if D ≈ m, seems even harder to avoid: The number of nodes in the recursion tree is Θ(n/m), so if Ω(1) I/Os are "lost" on average at every node, e.g., because of a last block that is only partially occupied by items, the accumulated waste amounts to Ω(n/m) I/Os.