Skip to content

Commit dba4061

Browse files
authored
Merge pull request #1 from viniciusfabri/feature/add-benchmark
feat: Add benchmarking feature
2 parents d3cf912 + 108a914 commit dba4061

File tree

3 files changed

+138
-30
lines changed

3 files changed

+138
-30
lines changed

internal/input.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,22 @@ import (
99
)
1010

1111
type Args struct {
12-
day string
13-
part string
14-
year string
12+
Day string
13+
Part string
14+
Year string
1515
path string // plugin path
1616
}
1717

1818
func ProcessArgs() Args {
1919
year := flag.String("year", fmt.Sprint(time.Now().Year()), "Year of the challenge")
20-
day := flag.String("day", "1", "Day of the challenge")
20+
day := flag.String("day", "0", "Day of the challenge. 0 to run all days.")
2121
part := flag.String("part", "1", "Part of the challenge")
2222
flag.Parse()
2323

2424
args := Args{
25-
day: *day,
26-
part: *part,
27-
year: *year,
25+
Day: *day,
26+
Part: *part,
27+
Year: *year,
2828
}
2929

3030
path, err := args.getPath()
@@ -39,7 +39,11 @@ func ProcessArgs() Args {
3939
}
4040

4141
func (args Args) getPath() (string, error) {
42-
path := filepath.Join("./", args.year, "day"+args.day, "part"+args.part)
42+
if args.Day == "0" {
43+
return "", nil
44+
}
45+
46+
path := filepath.Join("./", args.Year, "day"+args.Day, "part"+args.Part)
4347
if _, err := os.Stat(filepath.Dir(path)); os.IsNotExist(err) {
4448
return "", fmt.Errorf("the directory %s does not exist", filepath.Dir(path))
4549
}

internal/processor.go

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os/exec"
77
"path/filepath"
88
"plugin"
9+
"strings"
910
)
1011

1112
type PluginProcessor struct {
@@ -32,7 +33,7 @@ func (p PluginProcessor) CallFunc(input *[]byte) (string, error) {
3233
}
3334

3435
// Look up the Process function
35-
symProcess, err := plug.Lookup("Part" + p.Args.part)
36+
symProcess, err := plug.Lookup("Part" + p.Args.Part)
3637
if err != nil {
3738
return "", fmt.Errorf("error looking up process: %v", err)
3839
}
@@ -47,22 +48,24 @@ func (p PluginProcessor) CallFunc(input *[]byte) (string, error) {
4748
return processFunc(string(*input)), nil
4849
}
4950

50-
func (p PluginProcessor) RunTests() {
51-
cmd := exec.Command("go", "test", fmt.Sprintf("./%s/day%s/", p.Args.year, p.Args.day))
51+
func (p PluginProcessor) RunTests() error {
52+
cmd := exec.Command("go", "test", fmt.Sprintf("./%s/day%s/", p.Args.Year, p.Args.Day))
5253
cmd.Stdout = os.Stdout
5354
cmd.Stderr = os.Stderr
5455

5556
fmt.Printf("\nRunning tests: %s\n", cmd.String())
5657

5758
if err := cmd.Run(); err != nil {
5859
fmt.Println("Tests failed.")
59-
return
60+
return err
6061
}
62+
63+
return nil
6164
}
6265

6366
func (p PluginProcessor) GetInput() (*[]byte, error) {
6467
// Determine the input file path
65-
path := filepath.Join("./", p.Args.year, "day"+p.Args.day, "input.txt")
68+
path := filepath.Join("./", p.Args.Year, "day"+p.Args.Day, "input.txt")
6669

6770
// Read the input file
6871
data, err := os.ReadFile(path)
@@ -76,3 +79,59 @@ func (p PluginProcessor) GetInput() (*[]byte, error) {
7679

7780
return &data, nil
7881
}
82+
83+
func GetAllPluginProcessors(args Args) ([]PluginProcessor, error) {
84+
var baseDir = filepath.Join("./", args.Year)
85+
var processors []PluginProcessor
86+
87+
err := filepath.Walk(baseDir, func(path string, info os.FileInfo, err error) error {
88+
if err != nil {
89+
return err
90+
}
91+
92+
if info.IsDir() {
93+
return nil
94+
}
95+
96+
parts := strings.Split(path, string(os.PathSeparator))
97+
if len(parts) != 3 {
98+
return nil
99+
}
100+
101+
if !strings.HasPrefix(parts[1], "day") {
102+
return nil
103+
}
104+
105+
if !strings.HasPrefix(parts[2], "part") || strings.Contains(parts[2], "test") || !strings.HasSuffix(parts[2], ".go") {
106+
return nil
107+
}
108+
109+
year := parts[0]
110+
day := parts[1][3:]
111+
part := parts[2][4 : len(parts[2])-3]
112+
113+
args := Args{
114+
Year: year,
115+
Day: day,
116+
Part: part,
117+
}
118+
args.path, err = args.getPath()
119+
if err != nil {
120+
return err
121+
}
122+
123+
processors = append(processors, PluginProcessor{
124+
Args: args,
125+
})
126+
127+
return nil
128+
})
129+
130+
if err != nil {
131+
fmt.Println("Error scanning directories:", err)
132+
133+
return nil, err
134+
}
135+
136+
return processors, nil
137+
}

runner.go

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,77 @@ package aoc
22

33
import (
44
"fmt"
5+
"os"
6+
"text/tabwriter"
7+
"time"
58

69
internal "github.com/igorwulff/aoc/internal"
710
)
811

9-
func Run() {
10-
args := internal.ProcessArgs()
12+
type BenchmarkResult struct {
13+
TotalTimeInMs int64
14+
}
1115

12-
plugin := internal.PluginProcessor{Args: args}
13-
if err := plugin.Build(); err != nil {
14-
fmt.Println(err)
15-
return
16+
func Run() ([]BenchmarkResult, error) {
17+
args := internal.ProcessArgs()
18+
var plugins []internal.PluginProcessor
19+
// Benchmarking mode
20+
if args.Day == "0" {
21+
allPlugins, err := internal.GetAllPluginProcessors(args)
22+
if err != nil {
23+
fmt.Println(err)
24+
return nil, err
25+
}
26+
plugins = append(plugins, allPlugins...)
27+
} else {
28+
plugins = append(plugins, internal.PluginProcessor{Args: args})
1629
}
1730

18-
input, err := plugin.GetInput()
19-
if err != nil {
20-
fmt.Println(err)
21-
return
22-
}
31+
results := make([]BenchmarkResult, len(plugins))
32+
for i, plugin := range plugins {
33+
input, err := plugin.GetInput()
34+
if err != nil {
35+
fmt.Printf("Could not find input.txt for Day %s Part %s\n", plugin.Args.Day, plugin.Args.Part)
36+
return nil, err
37+
}
2338

24-
plugin.RunTests()
39+
fmt.Printf("Building day %s part %s... ", plugin.Args.Day, plugin.Args.Part)
40+
if err := plugin.Build(); err != nil {
41+
fmt.Print("ERROR!\n")
42+
fmt.Println(err)
43+
return nil, err
44+
}
45+
fmt.Print("OK!\n")
46+
47+
fmt.Print("Executing tests... ")
48+
if err := plugin.RunTests(); err != nil {
49+
fmt.Print("ERROR!\n")
50+
fmt.Println(err)
51+
return nil, err
52+
}
53+
54+
fmt.Print("Executing main function... ")
55+
timeBeforeExec := time.Now().UnixMilli()
56+
output, err := plugin.CallFunc(input)
57+
if err != nil {
58+
fmt.Print("ERROR!\n")
59+
fmt.Println(err)
60+
return nil, err
61+
}
62+
timeAfterExec := time.Now().UnixMilli()
63+
results[i] = BenchmarkResult{TotalTimeInMs: timeAfterExec - timeBeforeExec}
64+
65+
fmt.Printf("Solution: %s\n", output)
66+
}
2567

26-
output, err := plugin.CallFunc(input)
27-
if err != nil {
28-
fmt.Println(err)
29-
return
68+
fmt.Println("Execution finished! Total time:")
69+
w := tabwriter.NewWriter(os.Stdout, 0, 4, 4, ' ', 0)
70+
fmt.Fprintln(w, "Day\tPart\tTime (ms)")
71+
for i, plugin := range plugins {
72+
// @TODO: would be nice to join day & parts in a single row, but for now it's already nice they're alphabetically sorted
73+
fmt.Fprintf(w, "%s\t%s\t%d\n", plugin.Args.Day, plugin.Args.Part, results[i].TotalTimeInMs)
3074
}
75+
w.Flush()
3176

32-
fmt.Println("\nSolution:\n", output)
77+
return results, nil
3378
}

0 commit comments

Comments
 (0)