Skip to content

Commit d7e16ff

Browse files
Merge pull request #78 from segmentio/diversify-qsort-benchmarks
qsort: add benchmarks for partially ordered data
2 parents 3011ec0 + 1d52a37 commit d7e16ff

File tree

1 file changed

+82
-18
lines changed

1 file changed

+82
-18
lines changed

qsort/sort_test.go

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,12 @@ func randint(lo, hi int) int {
161161

162162
func BenchmarkSort8(b *testing.B) {
163163
for _, count := range []int{1e3, 1e4, 1e5, 1e6} {
164-
b.Run(strconv.Itoa(count), benchSort(count, 8, random, nil))
164+
b.Run("random-"+strconv.Itoa(count), benchSort(count, 8, 0, random, nil))
165+
if count > 1e4 {
166+
b.Run("partially-ordered(10)-"+strconv.Itoa(count), benchSort(count, 8, 10, random, nil))
167+
b.Run("partially-ordered(100)-"+strconv.Itoa(count), benchSort(count, 8, 100, random, nil))
168+
b.Run("partially-ordered(1000)-"+strconv.Itoa(count), benchSort(count, 8, 1000, random, nil))
169+
}
165170
}
166171
}
167172

@@ -182,62 +187,103 @@ func stdlibSort8(b *testing.B, size int) {
182187
}
183188
}
184189

190+
func stdlibSort8PartiallySorted(b *testing.B, size int, partitions int) {
191+
// 8 bytes per int64
192+
b.SetBytes(8 * int64(size))
193+
data := make([]int64, size)
194+
// panic if not a whole number
195+
partitionSize := int(size / partitions)
196+
partitionOrder := rand.Perm(partitions)
197+
groupedPartitions := make([][]int64, partitions)
198+
199+
for i := 0; i < len(groupedPartitions); i++ {
200+
partition := make([]int64, partitionSize)
201+
for j := 0; j < len(partition); j++ {
202+
partition[j] = int64(rand.Intn(size / 10))
203+
}
204+
sort.Slice(partition, func(i, j int) bool { return partition[i] < partition[j] })
205+
groupedPartitions[partitionOrder[i]] = partition
206+
}
207+
208+
partiallyOrdered := make([]int64, size)
209+
for _, partition := range groupedPartitions {
210+
partiallyOrdered = append(partiallyOrdered, partition...)
211+
}
212+
213+
b.StopTimer()
214+
for i := 0; i < b.N; i++ {
215+
copy(data, partiallyOrdered)
216+
b.StartTimer()
217+
sort.Slice(data, func(i, j int) bool { return data[i] < data[j] })
218+
b.StopTimer()
219+
}
220+
}
221+
185222
func BenchmarkStdlibSort8(b *testing.B) {
186223
for _, size := range []int{1e5, 1e6} {
187-
b.Run(strconv.Itoa(size), func(b *testing.B) {
224+
b.Run("random-"+strconv.Itoa(size), func(b *testing.B) {
188225
stdlibSort8(b, size)
189226
})
227+
b.Run("partially-sorted(10)-"+strconv.Itoa(size), func(b *testing.B) {
228+
stdlibSort8PartiallySorted(b, size, 10)
229+
})
230+
b.Run("partially-sorted(100)-"+strconv.Itoa(size), func(b *testing.B) {
231+
stdlibSort8PartiallySorted(b, size, 100)
232+
})
233+
b.Run("partially-sorted(1000)-"+strconv.Itoa(size), func(b *testing.B) {
234+
stdlibSort8PartiallySorted(b, size, 1000)
235+
})
190236
}
191237
}
192238

193239
func BenchmarkSort8Indirect(b *testing.B) {
194240
swap := func(int, int) {}
195241
const count = 100000
196-
b.Run("random", benchSort(count, 8, random, swap))
197-
b.Run("asc", benchSort(count, 8, asc, swap))
198-
b.Run("desc", benchSort(count, 8, desc, swap))
242+
b.Run("random", benchSort(count, 8, 0, random, swap))
243+
b.Run("asc", benchSort(count, 8, 0, asc, swap))
244+
b.Run("desc", benchSort(count, 8, 0, desc, swap))
199245
}
200246

201247
func BenchmarkSort16(b *testing.B) {
202248
for _, count := range []int{1e3, 1e4, 1e5, 1e6} {
203-
b.Run(strconv.Itoa(count), benchSort(count, 16, random, nil))
249+
b.Run(strconv.Itoa(count), benchSort(count, 16, 0, random, nil))
204250
}
205251
}
206252

207253
func BenchmarkSort16Indirect(b *testing.B) {
208254
swap := func(int, int) {}
209255
const count = 100000
210-
b.Run("random", benchSort(count, 16, random, swap))
211-
b.Run("asc", benchSort(count, 16, asc, swap))
212-
b.Run("desc", benchSort(count, 16, desc, swap))
256+
b.Run("random", benchSort(count, 16, 0, random, swap))
257+
b.Run("asc", benchSort(count, 16, 0, asc, swap))
258+
b.Run("desc", benchSort(count, 16, 0, desc, swap))
213259
}
214260

215261
func BenchmarkSort24(b *testing.B) {
216262
for _, count := range []int{1e3, 1e4, 1e5, 1e6} {
217-
b.Run(strconv.Itoa(count), benchSort(count, 24, random, nil))
263+
b.Run(strconv.Itoa(count), benchSort(count, 24, 0, random, nil))
218264
}
219265
}
220266

221267
func BenchmarkSort24Indirect(b *testing.B) {
222268
swap := func(int, int) {}
223269
const count = 100000
224-
b.Run("random", benchSort(count, 24, random, swap))
225-
b.Run("asc", benchSort(count, 24, asc, swap))
226-
b.Run("desc", benchSort(count, 24, desc, swap))
270+
b.Run("random", benchSort(count, 24, 0, random, swap))
271+
b.Run("asc", benchSort(count, 24, 0, asc, swap))
272+
b.Run("desc", benchSort(count, 24, 0, desc, swap))
227273
}
228274

229275
func BenchmarkSort32(b *testing.B) {
230276
for _, count := range []int{1e3, 1e4, 1e5, 1e6} {
231-
b.Run(strconv.Itoa(count), benchSort(count, 32, random, nil))
277+
b.Run(strconv.Itoa(count), benchSort(count, 0, 32, random, nil))
232278
}
233279
}
234280

235281
func BenchmarkSort32Indirect(b *testing.B) {
236282
swap := func(int, int) {}
237283
const count = 100000
238-
b.Run("random", benchSort(count, 32, random, swap))
239-
b.Run("asc", benchSort(count, 32, asc, swap))
240-
b.Run("desc", benchSort(count, 32, desc, swap))
284+
b.Run("random", benchSort(count, 32, 0, random, swap))
285+
b.Run("asc", benchSort(count, 32, 0, asc, swap))
286+
b.Run("desc", benchSort(count, 32, 0, desc, swap))
241287
}
242288

243289
type order int
@@ -246,9 +292,10 @@ const (
246292
random order = iota
247293
asc
248294
desc
295+
partiallyOrdered
249296
)
250297

251-
func benchSort(count, size int, order order, indirect func(int, int)) func(*testing.B) {
298+
func benchSort(count, size, partitions int, order order, indirect func(int, int)) func(*testing.B) {
252299
return func(b *testing.B) {
253300
b.StopTimer()
254301
buf := make([]byte, count*size)
@@ -266,6 +313,23 @@ func benchSort(count, size int, order order, indirect func(int, int)) func(*test
266313
}
267314
}
268315

316+
if order == partiallyOrdered {
317+
// panic if not a whole number
318+
partitionSize := int((count * size) / partitions)
319+
partitionOrder := rand.Perm(partitions)
320+
groupedPartitions := make([][]byte, partitions)
321+
322+
for i := 0; i < len(groupedPartitions); i++ {
323+
partition := make([]byte, partitionSize)
324+
sort.Sort(newGeneric(partition, partitionSize, nil))
325+
groupedPartitions[partitionOrder[i]] = partition
326+
}
327+
328+
for _, partition := range groupedPartitions {
329+
unsorted = append(unsorted, partition...)
330+
}
331+
}
332+
269333
b.SetBytes(int64(len(buf)))
270334

271335
for i := 0; i < b.N; i++ {

0 commit comments

Comments
 (0)