Skip to content

Commit 5c3d1ef

Browse files
feat(benchmark): Add dataset generator and sorting benchmarks for quickSort and pdqsort
This commit introduces a new dataset generator for creating various data patterns used in benchmarking sorting algorithms. It also implements a comprehensive benchmark harness that compares the performance of the baseline quickSort and the enhanced pdqsort across multiple data conditions, including random, sorted, reverse sorted, few unique, and pathological datasets. The results will help evaluate the effectiveness of the pdqsort enhancement.
1 parent 3c80f38 commit 5c3d1ef

File tree

2 files changed

+67
-60
lines changed

2 files changed

+67
-60
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// Centralized generation of datasets for all benchmarks.
6+
///
7+
/// Ensures all algorithms are tested on the exact same data.
8+
library;
9+
10+
11+
import 'dart:math';
12+
13+
const size = 50000;
14+
const count = 128; // Number of lists to cycle through.
15+
16+
final List<List<int>> random = _generateRandom();
17+
final List<List<int>> sorted = _generateSorted();
18+
final List<List<int>> reverse = _generateReverse();
19+
final List<List<int>> fewUnique = _generateFewUnique();
20+
final List<List<int>> pathological = _generatePathological();
21+
22+
List<List<int>> _generateRandom() {
23+
final r = Random(12345);
24+
return List.generate(
25+
count, (_) => List.generate(size, (_) => r.nextInt(2000)));
26+
}
27+
28+
List<List<int>> _generateSorted() {
29+
final base = List.generate(size, (i) => i);
30+
return List.generate(count, (_) => List<int>.from(base));
31+
}
32+
33+
List<List<int>> _generateReverse() {
34+
final base = List.generate(size, (i) => size - 1 - i);
35+
return List.generate(count, (_) => List<int>.from(base));
36+
}
37+
38+
List<List<int>> _generateFewUnique() {
39+
final r = Random(67890);
40+
return List.generate(count, (_) => List.generate(size, (_) => r.nextInt(7)));
41+
}
42+
43+
List<List<int>> _generatePathological() {
44+
final base = List.generate(size, (i) => i);
45+
// Creates a "V-shape" or "organ pipe" array that can be challenging
46+
// for quicksort implementations by promoting unbalanced partitions.
47+
final pathological = <int>[
48+
for (int i = 0; i < size; i++)
49+
if (i.isEven) base[i],
50+
for (int i = size - 1; i > 0; i--)
51+
if (i.isOdd) base[i],
52+
];
53+
return List.generate(count, (_) => List<int>.from(pathological));
54+
}

pkgs/collection/benchmark/sort_comparison_benchmark.dart renamed to pkgs/collection/benchmark/sort_benchmark.dart

Lines changed: 13 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,11 @@ import 'package:benchmark_harness/benchmark_harness.dart';
88
import 'package:collection/src/algorithms.dart' show quickSort;
99
import 'package:collection/src/utils.dart';
1010

11+
import 'dataset_generator.dart' as dataset_generator;
12+
1113
// Sink variable to prevent the compiler from optimizing away benchmark code.
1214
int sink = 0;
1315

14-
/// Centralized generation of datasets for all benchmarks.
15-
///
16-
/// Ensures all algorithms are tested on the exact same data.
17-
class DatasetGenerator {
18-
static const size = 50000;
19-
static const count = 128; // Number of lists to cycle through.
20-
21-
static final List<List<int>> random = _generateRandom();
22-
static final List<List<int>> sorted = _generateSorted();
23-
static final List<List<int>> reverse = _generateReverse();
24-
static final List<List<int>> fewUnique = _generateFewUnique();
25-
static final List<List<int>> pathological = _generatePathological();
26-
27-
static List<List<int>> _generateRandom() {
28-
final r = Random(12345);
29-
return List.generate(
30-
count, (_) => List.generate(size, (_) => r.nextInt(2000)));
31-
}
32-
33-
static List<List<int>> _generateSorted() {
34-
final base = List.generate(size, (i) => i);
35-
return List.generate(count, (_) => List<int>.from(base));
36-
}
37-
38-
static List<List<int>> _generateReverse() {
39-
final base = List.generate(size, (i) => size - 1 - i);
40-
return List.generate(count, (_) => List<int>.from(base));
41-
}
42-
43-
static List<List<int>> _generateFewUnique() {
44-
final r = Random(67890);
45-
return List.generate(
46-
count, (_) => List.generate(size, (_) => r.nextInt(7)));
47-
}
48-
49-
static List<List<int>> _generatePathological() {
50-
final base = List.generate(size, (i) => i);
51-
// Creates a "V-shape" or "organ pipe" array that can be challenging
52-
// for quicksort implementations by promoting unbalanced partitions.
53-
final pathological = <int>[
54-
for (int i = 0; i < size; i++)
55-
if (i.isEven) base[i],
56-
for (int i = size - 1; i > 0; i--)
57-
if (i.isOdd) base[i],
58-
];
59-
return List.generate(count, (_) => List<int>.from(pathological));
60-
}
61-
}
62-
6316
/// The final aggregated result of a benchmark.
6417
class BenchmarkResult {
6518
final double mean;
@@ -99,7 +52,7 @@ abstract class SortBenchmarkBase extends BenchmarkBase {
9952
// Baseline (Old SDK quickSort)
10053
class QuickSortBaselineRandomBenchmark extends SortBenchmarkBase {
10154
QuickSortBaselineRandomBenchmark()
102-
: super('Baseline.Random', DatasetGenerator.random);
55+
: super('Baseline.Random', dataset_generator.random);
10356
@override
10457
void performSort() {
10558
final list = getNextList();
@@ -110,7 +63,7 @@ class QuickSortBaselineRandomBenchmark extends SortBenchmarkBase {
11063

11164
class QuickSortBaselineSortedBenchmark extends SortBenchmarkBase {
11265
QuickSortBaselineSortedBenchmark()
113-
: super('Baseline.Sorted', DatasetGenerator.sorted);
66+
: super('Baseline.Sorted', dataset_generator.sorted);
11467
@override
11568
void performSort() {
11669
final list = getNextList();
@@ -121,7 +74,7 @@ class QuickSortBaselineSortedBenchmark extends SortBenchmarkBase {
12174

12275
class QuickSortBaselineReverseBenchmark extends SortBenchmarkBase {
12376
QuickSortBaselineReverseBenchmark()
124-
: super('Baseline.Reverse', DatasetGenerator.reverse);
77+
: super('Baseline.Reverse', dataset_generator.reverse);
12578
@override
12679
void performSort() {
12780
final list = getNextList();
@@ -132,7 +85,7 @@ class QuickSortBaselineReverseBenchmark extends SortBenchmarkBase {
13285

13386
class QuickSortBaselineFewUniqueBenchmark extends SortBenchmarkBase {
13487
QuickSortBaselineFewUniqueBenchmark()
135-
: super('Baseline.FewUnique', DatasetGenerator.fewUnique);
88+
: super('Baseline.FewUnique', dataset_generator.fewUnique);
13689
@override
13790
void performSort() {
13891
final list = getNextList();
@@ -143,7 +96,7 @@ class QuickSortBaselineFewUniqueBenchmark extends SortBenchmarkBase {
14396

14497
class QuickSortBaselinePathologicalBenchmark extends SortBenchmarkBase {
14598
QuickSortBaselinePathologicalBenchmark()
146-
: super('Baseline.Pathological', DatasetGenerator.pathological);
99+
: super('Baseline.Pathological', dataset_generator.pathological);
147100
@override
148101
void performSort() {
149102
final list = getNextList();
@@ -155,7 +108,7 @@ class QuickSortBaselinePathologicalBenchmark extends SortBenchmarkBase {
155108
// Enhancement (New pdqsort)
156109
class PdqSortEnhancementRandomBenchmark extends SortBenchmarkBase {
157110
PdqSortEnhancementRandomBenchmark()
158-
: super('Enhancement.Random', DatasetGenerator.random);
111+
: super('Enhancement.Random', dataset_generator.random);
159112
@override
160113
void performSort() {
161114
final list = getNextList();
@@ -166,7 +119,7 @@ class PdqSortEnhancementRandomBenchmark extends SortBenchmarkBase {
166119

167120
class PdqSortEnhancementSortedBenchmark extends SortBenchmarkBase {
168121
PdqSortEnhancementSortedBenchmark()
169-
: super('Enhancement.Sorted', DatasetGenerator.sorted);
122+
: super('Enhancement.Sorted', dataset_generator.sorted);
170123
@override
171124
void performSort() {
172125
final list = getNextList();
@@ -177,7 +130,7 @@ class PdqSortEnhancementSortedBenchmark extends SortBenchmarkBase {
177130

178131
class PdqSortEnhancementReverseBenchmark extends SortBenchmarkBase {
179132
PdqSortEnhancementReverseBenchmark()
180-
: super('Enhancement.Reverse', DatasetGenerator.reverse);
133+
: super('Enhancement.Reverse', dataset_generator.reverse);
181134
@override
182135
void performSort() {
183136
final list = getNextList();
@@ -188,7 +141,7 @@ class PdqSortEnhancementReverseBenchmark extends SortBenchmarkBase {
188141

189142
class PdqSortEnhancementFewUniqueBenchmark extends SortBenchmarkBase {
190143
PdqSortEnhancementFewUniqueBenchmark()
191-
: super('Enhancement.FewUnique', DatasetGenerator.fewUnique);
144+
: super('Enhancement.FewUnique', dataset_generator.fewUnique);
192145
@override
193146
void performSort() {
194147
final list = getNextList();
@@ -199,7 +152,7 @@ class PdqSortEnhancementFewUniqueBenchmark extends SortBenchmarkBase {
199152

200153
class PdqSortEnhancementPathologicalBenchmark extends SortBenchmarkBase {
201154
PdqSortEnhancementPathologicalBenchmark()
202-
: super('Enhancement.Pathological', DatasetGenerator.pathological);
155+
: super('Enhancement.Pathological', dataset_generator.pathological);
203156
@override
204157
void performSort() {
205158
final list = getNextList();
@@ -416,4 +369,4 @@ void _movingInsertionSortBaseline<E, K>(
416369
target.setRange(min + 1, targetOffset + i + 1, target, min);
417370
target[min] = element;
418371
}
419-
}
372+
}

0 commit comments

Comments
 (0)