func Sparkline(values []uint64) string {
	if len(values) == 0 {
		return ""
	}
	var min uint64 = math.MaxUint64
	var max uint64
	for _, v := range values {
		if v < min {
			min = v
		}
		if v > max {
			max = v
		}
	}
	delta := max - min
	var sb strings.Builder
	for _, v := range values {
		var tick uint64
		if delta == 0 {
			tick = 4
		} else {
			tick = (v - min) * 7 / delta
		}
		if v == min && false {
			sb.WriteString("\x1b[92m")
			sb.WriteRune(rune(0x2581 + tick))
			sb.WriteString("\x1b[0m")
		} else {
			sb.WriteRune(rune(0x2581 + tick))
		}
	}
	return sb.String()
}
Sparkline creates a histogram chart of values. The chart is scaled
to [min...max] containing differences between values.
package main
import (
	"flag"
	"fmt"
	"log"
	"math"
	"os"
	"runtime/pprof"
	"strings"
	"github.com/markkurossi/mpc/compiler"
	"github.com/markkurossi/mpc/compiler/utils"
)
var template = `
package main
func main(a, b int%d) int {
    return a * b
}
`
type result struct {
	bits       int
	bestLimit  int
	bestCost   uint64
	worstLimit int
	worstCost  uint64
	costs      []uint64
}
func main() {
	numWorkers := flag.Int("workers", 8, "number of workers")
	startBits := flag.Int("start", 8, "start bit count")
	endBits := flag.Int("end", 0xffffffff, "end bit count")
	minLimit := flag.Int("min", 8, "treshold minimum limit")
	maxLimit := flag.Int("max", 22, "treshold maximum limit")
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to `file`")
	flag.Parse()
	if len(*cpuprofile) > 0 {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		defer f.Close()
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
		defer pprof.StopCPUProfile()
	}
	results := make(map[int]*result)
	ch := make(chan *result)
	for i := 0; i < *numWorkers; i++ {
		go func(bits int) {
			for ; bits <= *endBits; bits += *numWorkers {
				code := fmt.Sprintf(template, bits)
				var bestLimit int
				var bestCost uint64
				var worstLimit int
				var worstCost uint64
				var costs []uint64
				params := utils.NewParams()
				for limit := *minLimit; limit <= *maxLimit; limit++ {
					params.CircMultArrayTreshold = limit
					circ, _, err := compiler.New(params).Compile(code)
					if err != nil {
						log.Fatalf("Compilation %d:%d failed: %s\n%s",
							bits, limit, err, code)
					}
					cost := circ.Cost()
					costs = append(costs, cost)
					if bestCost == 0 || cost < bestCost ||
						(limit == 21 && cost <= bestCost) {
						bestCost = cost
						bestLimit = limit
					}
					if cost > worstCost {
						worstCost = cost
						worstLimit = limit
					}
				}
				ch <- &result{
					bits:       bits,
					bestLimit:  bestLimit,
					bestCost:   bestCost,
					worstLimit: worstLimit,
					worstCost:  worstCost,
					costs:      costs,
				}
			}
		}(*startBits + i)
	}
	next := *startBits
outer:
	for result := range ch {
		results[result.bits] = result
		for {
			r, ok := results[next]
			if !ok {
				break
			}
			if r.bestLimit == 21 {
				fmt.Printf("\t// %d: %d, %10d\t%.4f\t%s\n",
					r.bits, r.bestLimit,
					r.bestCost, float64(r.bestCost)/float64(r.worstCost),
					Sparkline(r.costs))
			} else {
				fmt.Printf("\t%d: %d, // %10d\t%.4f\t%s\n",
					r.bits, r.bestLimit,
					r.bestCost, float64(r.bestCost)/float64(r.worstCost),
					Sparkline(r.costs))
			}
			if next >= *endBits {
				break outer
			}
			next++
		}
	}
}