func Run(mabcfg Config) error {
	sqlClient, err := createSQLClient(mabcfg.DatabaseConfig)
	if err != nil {
		return err
	}
	defer sqlClient.Close()
	metricsClient, err := createMetricsDatabaseClient(mabcfg.MetricsDatabaseConfig)
	if err != nil {
		return err
	}
	var macrobenchID int
	if sqlClient != nil {
		macrobenchID, err = mabcfg.insertBenchmarkToSQL(sqlClient)
		if err != nil {
			return err
		}
	}
	if mabcfg.WorkingDirectory == "" {
		mabcfg.WorkingDirectory, _ = os.Getwd()
	}
	mabcfg.parseIntoMap(prefixMacroBenchSysbenchConfig)
	newSteps := skipSteps(steps, mabcfg.SkipSteps)
	var resStr []byte
	for _, step := range newSteps {
		args := buildSysbenchArgString(mabcfg.M, step.Name)
		args = append(args, mabcfg.WorkloadPath, step.SysbenchName)
		command := exec.Command(mabcfg.SysbenchExec, args...)
		command.Dir = mabcfg.WorkingDirectory
		out, err := command.Output()
		if err != nil {
			return fmt.Errorf("%s:\n%s", err.Error(), string(out))
		}
		if step.Name == stepRun {
			resStr = out
		}
	}
	err = handleResults(mabcfg, resStr, sqlClient, metricsClient, macrobenchID)
	if err != nil {
		return err
	}
	return nil
}
Run executes a macro benchmark by using sysbench.
Based on the given MacroBenchConfig, the function will
parse the configuration to send down to sysbench (size of tables
duration of benchmark, mysql targets, etc...).
After the execution, the output of the last step (stepRun) is
converted to a slice of MacroBenchmarkResult, which is then
uploaded to MySQL using the mysql.ConfigDB in MacroBenchConfig.

We use two forks of sysbench, one for oltp workloads
and the other for tpcc workload. We use these forks because
they implement a custom method to print results in JSON.

Regular Sysbench: https://github.com/planetscale/sysbench
Sysbench-TPCC: https://github.com/planetscale/sysbench-tpcc
package macrobench
import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/vitessio/arewefastyet/go/exec/metrics"
	"github.com/vitessio/arewefastyet/go/storage/influxdb"
	"github.com/vitessio/arewefastyet/go/storage/psdb"
	"os"
	"os/exec"
	"strings"
)
type PlannerVersion string
const (
	ErrorNoSysBenchResult = "no sysbench results were found"
	prefixMacroBenchSysbenchConfig = "macrobench_"
	V3Planner           PlannerVersion = "V3"
	Gen4FallbackPlanner PlannerVersion = "Gen4Fallback"
)
var (
	PlannerVersions = []PlannerVersion{
		V3Planner,
		Gen4FallbackPlanner,
	}
)
func buildSysbenchArgString(m map[string]string, step string) []string {
	output := map[string]string{}
	for k, v := range m {
		idx := strings.Index(k, "_")
		if idx < 0 {
			continue
		}
		head := k[:idx]
		tail := k[idx+1:]
		if head == step || head == "all" {
			if _, exists := output[tail]; exists {
				if head == "all" {
					continue
				}
			}
			output[tail] = v
		}
	}
	var results []string
	for k, v := range output {
		results = append(results, fmt.Sprintf("--%s=%s", k, v))
	}
	return results
}