435
// Running 'go test -calibrate' runs the calibration to find a plausible
436
// cutoff point for linear search of a range list vs. binary search.
437
// We create a fake table and then time how long it takes to do a
438
// sequence of searches within that table, for all possible inputs
439
// relative to the ranges (something before all, in each, between each, after all).
440
// This assumes that all possible runes are equally likely.
441
// In practice most runes are ASCII so this is a conservative estimate
442
// of an effective cutoff value. In practice we could probably set it higher
443
// than what this function recommends.
445
var calibrate = flag.Bool("calibrate", false, "compute crossover for linear vs. binary search")
447
func TestCalibrate(t *testing.T) {
452
if runtime.GOARCH == "amd64" {
453
fmt.Printf("warning: running calibration on %s\n", runtime.GOARCH)
456
// Find the point where binary search wins by more than 10%.
457
// The 10% bias gives linear search an edge when they're close,
458
// because on predominantly ASCII inputs linear search is even
459
// better than our benchmarks measure.
460
n := sort.Search(64, func(n int) bool {
462
blinear := func(b *testing.B) {
465
for i := 0; i < b.N; i++ {
466
for j := 0; j <= max; j++ {
467
linear(tab, uint16(j))
471
bbinary := func(b *testing.B) {
474
for i := 0; i < b.N; i++ {
475
for j := 0; j <= max; j++ {
476
binary(tab, uint16(j))
480
bmlinear := testing.Benchmark(blinear)
481
bmbinary := testing.Benchmark(bbinary)
482
fmt.Printf("n=%d: linear=%d binary=%d\n", n, bmlinear.NsPerOp(), bmbinary.NsPerOp())
483
return bmlinear.NsPerOp()*100 > bmbinary.NsPerOp()*110
485
fmt.Printf("calibration: linear cutoff = %d\n", n)
488
func fakeTable(n int) []Range16 {
490
for i := 0; i < n; i++ {
491
r16 = append(r16, Range16{uint16(i*5 + 10), uint16(i*5 + 12), 1})
496
func linear(ranges []Range16, r uint16) bool {
497
for i := range ranges {
503
return (r-range_.Lo)%range_.Stride == 0
509
func binary(ranges []Range16, r uint16) bool {
510
// binary search over ranges
516
if range_.Lo <= r && r <= range_.Hi {
517
return (r-range_.Lo)%range_.Stride == 0
528
func TestLatinOffset(t *testing.T) {
529
var maps = []map[string]*RangeTable{
536
for _, m := range maps {
537
for name, tab := range m {
539
for i < len(tab.R16) && tab.R16[i].Hi <= MaxLatin1 {
542
if tab.LatinOffset != i {
543
t.Errorf("%s: LatinOffset=%d, want %d", name, tab.LatinOffset, i)