if (!size)
return 0;
if (!ctx->last_pass_time)
- return -1;
+ return 0;
return (uns)((double)size / (1<<20) * 1000 / ctx->last_pass_time);
}
sorter_alloc_buf(ctx);
if (in->flags & SBF_CUSTOM_PRESORT)
{
+ /*
+ * The trick with automatic joining, which we use for the normal presorter,
+ * is not necessary with the custom presorter, because the custom presorter
+ * is never called in the middle of the sorted data.
+ */
struct fastbuf *f = sbuck_write(out);
out->runs++;
- return ctx->custom_presort(f, ctx->big_buf, ctx->big_buf_size); // FIXME: out_only optimization?
+ return ctx->custom_presort(f, ctx->big_buf, ctx->big_buf_size);
}
return ctx->internal_sort(ctx, in, out, out_only);
}
static sh_off_t
sbuck_ins_or_join(struct sort_bucket *b, cnode *list_pos, struct sort_bucket *join, sh_off_t join_size)
{
- if (join)
+ if (join && join->runs >= 2)
{
if (b)
sbuck_drop(b);
{
// The final bucket doesn't have any file associated yet, so replace
// it with the new bucket.
- SORT_XTRACE(2, "Replaced final bucket");
+ SORT_XTRACE(3, "Replaced final bucket");
b->flags |= SBF_FINAL;
sbuck_drop(join);
}
{
sorter_stop_timer(ctx, &ctx->total_pre_time);
sh_off_t size = sbuck_ins_or_join(ins[0], list_pos, join, join_size);
- SORT_XTRACE(((b->flags & SBF_SOURCE) ? 1 : 2), "Sorted in memory (%s, %dMB/s)", stk_fsize(size), sorter_speed(ctx, size));
+ SORT_XTRACE(((b->flags & SBF_SOURCE) ? 1 : 3), "Sorted in memory (%s, %dMB/s)", stk_fsize(size), sorter_speed(ctx, size));
sbuck_drop(b);
return;
}
cnode *list_pos = b->n.prev;
sh_off_t join_size;
struct sort_bucket *join = sbuck_join_to(b, &join_size);
- uns trace_level = (b->flags & SBF_SOURCE) ? 1 : 2;
+ uns trace_level = (b->flags & SBF_SOURCE) ? 1 : 3;
clist_init(&parts);
ASSERT(!(sorter_debug & SORT_DEBUG_NO_PRESORT));
uns max_ways = 1 << sorter_max_multiway_bits;
struct sort_bucket *ways[max_ways+1];
- SORT_XTRACE(2, "Starting up to %d-way merge", max_ways);
+ SORT_XTRACE(3, "Starting up to %d-way merge", max_ways);
for (;;)
{
uns n = 0;
static void
sorter_radix(struct sort_context *ctx, struct sort_bucket *b, uns bits)
{
+ // Add more bits if requested and allowed.
+ bits = MIN(bits + sorter_add_radix_bits, sorter_max_radix_bits);
+
uns nbuck = 1 << bits;
- SORT_XTRACE(2, "Running radix split on %s with hash %d bits of %d (expecting %s buckets)",
+ SORT_XTRACE(3, "Running radix split on %s with hash %d bits of %d (expecting %s buckets)",
F_BSIZE(b), bits, b->hash_bits, stk_fsize(sbuck_size(b) / nbuck));
sorter_free_buf(ctx);
sorter_start_timer(ctx);
// Drop empty buckets
if (!sbuck_have(b))
{
- SORT_XTRACE(3, "Dropping empty bucket");
+ SORT_XTRACE(4, "Dropping empty bucket");
sbuck_drop(b);
return;
}
// How many bits of bucket size we have to reduce before it fits in the RAM?
// (this is insanely large if the input size is unknown, but it serves our purpose)
u64 insize = sbuck_size(b);
- u64 mem = ctx->internal_estimate(ctx, b) * 0.8; // FIXME: Magical factor for various non-uniformities
+ u64 mem = ctx->internal_estimate(ctx, b) * 0.8; // Magical factor accounting for various non-uniformities
uns bits = 0;
while ((insize >> bits) > mem)
bits++;
multiway_bits = 0;
}
- SORT_XTRACE(2, "Decisions: size=%s max=%s runs=%d bits=%d hash=%d -> radix=%d multi=%d",
+ SORT_XTRACE(3, "Decisions: size=%s max=%s runs=%d bits=%d hash=%d -> radix=%d multi=%d",
stk_fsize(insize), stk_fsize(mem), b->runs, bits, b->hash_bits,
radix_bits, multiway_bits);
bin->hash_bits = ctx->hash_bits;
clist_add_tail(&ctx->bucket_list, &bin->n);
SORT_XTRACE(2, "Input size: %s, %d hash bits", F_BSIZE(bin), bin->hash_bits);
+ ctx->fb_params = (bin->size < sorter_small_input) ? &sorter_small_fb_params : &sorter_fb_params;
// Create bucket for the output
struct sort_bucket *bout = sbuck_new(ctx);
SORT_XTRACE(2, "Final timings: %.3fs external sorting, %.3fs presorting, %.3fs internal sorting",
ctx->total_ext_time/1000., ctx->total_pre_time/1000., ctx->total_int_time/1000.);
ctx->out_fb = sbuck_read(bout);
+ mp_delete(ctx->pool);
}