func (c *collector) generateAsmText(asmLines []string) []byte {
	var buf bytes.Buffer
	buf.WriteString("// Code generated by avx512counters. DO NOT EDIT.\n")
	buf.WriteString("TEXT ·avx512routine(SB), 0, $0\n")
	buf.WriteString("\tMOVQ memory+0(FP), R12\n")
	for samples := uint(0); samples < c.iformSpanSize; samples++ {
		for _, line := range asmLines {
			if c.vmemArgRE.MatchString(line) {
				line = c.vmemArgRE.ReplaceAllString(line, "(R12)(${1}10*1)")
			} else {
				line = c.memArgRE.ReplaceAllString(line, "(R12)")
			}
			buf.WriteString(line + "\n")
			samples++
		}
	}
	buf.WriteString("\tRET\n")
	return buf.Bytes()
}
generateAsmText returns asm file text that contains avx512routine function
definition which is supposed to be called from evaluating loop.
package main
import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"time"
)
func main() {
	type step struct {
		name string
		fn   func() error
	}
	var c collector
	steps := []step{
		{"init collector", c.init},
		{"locate test dir", c.locateTestDir},
		{"read extensions", c.readExtensions},
		{"parse command-line args", c.parseFlags},
		{"validate command-line args", c.validateFlags},
		{"check perf tool", c.checkPerfTool},
		{"prepare work dir", c.prepareWorkDir},
		{"visit work dir", c.visitWorkDir},
		{"collect counters", c.collectCounters},
		{"print csv", c.printCSV},
	}
	for _, s := range steps {
		if err := s.fn(); err != nil {
			log.Fatalf("%s: %v", s.name, err)
		}
	}
}
type collector struct {
	memArgRE *regexp.Regexp
	vmemArgRE *regexp.Regexp
	testDir string
	availableExt map[string]bool
	stats []*iformStats
	current struct {
		extension string
		scanner   testFileScanner
	}
	extensions    []string
	perfTool      string
	workDir       string
	iformSpanSize uint
	loopCount     uint
	perfRounds    uint
}
func (c *collector) init() error {
	c.memArgRE = regexp.MustCompile(`(?:-?\d+)?\(\w+\)(?:\(\w+\*[1248]\))?`)
	c.vmemArgRE = regexp.MustCompile(`(?:-?\d+)?\(\w+\)\(([XYZ])\d+\*[1248]\)`)
	c.availableExt = make(map[string]bool)
	return nil
}
func (c *collector) locateTestDir() error {
	goroot := runtime.GOROOT()
	c.testDir = filepath.Join(goroot,
		"src", "cmd", "asm", "internal", "asm", "testdata", "avx512enc")
	if !fileExists(c.testDir) {
		return fmt.Errorf("can't locate AVX-512 testdata: %s doesn't exist", c.testDir)
	}
	return nil
}
func (c *collector) readExtensions() error {
	files, err := ioutil.ReadDir(c.testDir)
	if err != nil {
		return err
	}
	for _, f := range files {
		ext := strings.TrimSuffix(f.Name(), ".s")
		c.availableExt[ext] = true
	}
	return nil
}
func (c *collector) parseFlags() error {
	extensions := flag.String("extensions", "avx512f,avx512dq,avx512cd,avx512bw",
		`comma-separated list of extensions to be evaluated`)
	flag.StringVar(&c.perfTool, "perf", "perf",
		`perf tool binary name. ocperf and other drop-in replacements will do`)
	flag.StringVar(&c.workDir, "workDir", "./avx512counters-workdir",
		`where to put results and the intermediate files`)
	flag.UintVar(&c.iformSpanSize, "iformSpanSize", 100,
		`how many instruction lines form a single iform span. Higher values slow down the collection`)
	flag.UintVar(&c.loopCount, "loopCount", 1*1000*1000,
		`how many times to execute every iform span. Higher values slow down the collection`)
	flag.UintVar(&c.perfRounds, "perfRounds", 1,
		`how many times to re-validate perf results. Higher values slow down the collection`)
	flag.Parse()
	for _, ext := range strings.Split(*extensions, ",") {
		ext = strings.TrimSpace(ext)
		c.extensions = append(c.extensions, ext)
	}
	absWorkDir, err := filepath.Abs(c.workDir)
	if err != nil {
		return fmt.Errorf("expand -workDir: %v", err)
	}
	c.workDir = absWorkDir
	return nil
}
func (c *collector) validateFlags() error {
	for _, ext := range c.extensions {
		if !c.availableExt[ext] {
			return fmt.Errorf("unavailable extension: %q", ext)
		}
	}
	switch {
	case len(c.extensions) == 0:
		return errors.New("expected at least 1 extension name")
	case c.perfTool == "":
		return errors.New("argument -perf can't be empty")
	case c.iformSpanSize == 0:
		return errors.New("argument -iformSpanSize can't be 0")
	case c.loopCount == 0:
		return errors.New("argument -loopCount can't be 0")
	case c.perfRounds == 0:
		return errors.New("argument -perfRounds can't be 0")
	default:
		return nil
	}
}
func (c *collector) checkPerfTool() error {
	_, err := c.runPerf("echo")
	return err
}
func (c *collector) prepareWorkDir() error {
	if !fileExists(c.workDir) {
		if err := os.Mkdir(c.workDir, 0700); err != nil {
			return err
		}
	}
	mainFile := filepath.Join(c.workDir, "main.go")
	mainFileContents := fmt.Sprintf(`
		package main
		func avx512routine(*[1024]byte)
		func main() {
			var memory [1024]byte
			for i := 0; i < %d; i++ {
				for i := range memory {
					memory[i] = byte(i)
				}
				avx512routine(&memory)
			}
		}`, c.loopCount)
	return ioutil.WriteFile(mainFile, []byte(mainFileContents), 0666)
}
func (c *collector) visitWorkDir() error {
	return os.Chdir(c.workDir)
}
func (c *collector) collectCounters() error {
	for _, ext := range c.extensions {
		filename := filepath.Join(c.testDir, ext+".s")
		c.current.extension = ext
		c.current.scanner = testFileScanner{}
		if err := c.current.scanner.init(filename); err != nil {
			log.Printf("skip %s: can't scan test file: %v", ext, err)
			continue
		}
		stats, err := c.evaluateCurrent()
		if err != nil {
			log.Printf("failed %s: %v", ext, err)
			continue
		}
		c.stats = append(c.stats, stats...)
	}
	return nil
}
func (c *collector) evaluateCurrent() ([]*iformStats, error) {
	testMap := make(map[string][]string)
	for c.current.scanner.scan() {
		l := c.current.scanner.line
		iform := instructionForm(l)
		testMap[iform] = append(testMap[iform], l.text)
	}
	stats := make([]*iformStats, 0, len(testMap))
	for iform, lines := range testMap {
		asmText := c.generateAsmText(lines)
		istats, err := c.evaluateIform(iform, asmText)
		if err != nil {
			log.Printf("%s: skip %s: %v", c.current.extension, iform, err)
		} else {
			istats.ext = c.current.extension
			stats = append(stats, istats)
			log.Printf("%s: collected %s", c.current.extension, iform)
		}
	}
	return stats, c.current.scanner.err
}