Skip to content

Commit fe0ca6d

Browse files
fixes #75
1 parent 4f73e0a commit fe0ca6d

File tree

12 files changed

+692
-658
lines changed

12 files changed

+692
-658
lines changed

cli/config.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cli
2+
3+
import (
4+
"github.com/AlexsanderHamir/prof/engine/tracker"
5+
)
6+
7+
// setGlobalTrackingVariables sets the global CLI variables for tracking
8+
func setGlobalTrackingVariables(selections *tracker.Selections) {
9+
Baseline = selections.Baseline
10+
Current = selections.Current
11+
benchmarkName = selections.BenchmarkName
12+
profileType = selections.ProfileType
13+
outputFormat = selections.OutputFormat
14+
failOnRegression = selections.UseThreshold
15+
regressionThreshold = selections.RegressionThreshold
16+
}

cli/discovery.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
9+
"github.com/AlexsanderHamir/prof/internal"
10+
)
11+
12+
// discoverAvailableTags scans the bench directory for existing tags
13+
func discoverAvailableTags() ([]string, error) {
14+
root, err := internal.FindGoModuleRoot()
15+
if err != nil {
16+
return nil, fmt.Errorf("failed to locate module root: %w", err)
17+
}
18+
19+
benchDir := filepath.Join(root, internal.MainDirOutput)
20+
entries, err := os.ReadDir(benchDir)
21+
if err != nil {
22+
if os.IsNotExist(err) {
23+
return []string{}, nil
24+
}
25+
return nil, fmt.Errorf("failed to read bench directory: %w", err)
26+
}
27+
28+
var tags []string
29+
for _, entry := range entries {
30+
if entry.IsDir() {
31+
tags = append(tags, entry.Name())
32+
}
33+
}
34+
35+
return tags, nil
36+
}
37+
38+
// discoverAvailableBenchmarks scans a specific tag directory for available benchmarks
39+
func discoverAvailableBenchmarks(tag string) ([]string, error) {
40+
root, err := internal.FindGoModuleRoot()
41+
if err != nil {
42+
return nil, fmt.Errorf("failed to locate module root: %w", err)
43+
}
44+
45+
benchDir := filepath.Join(root, internal.MainDirOutput, tag, internal.ProfileTextDir)
46+
entries, err := os.ReadDir(benchDir)
47+
if err != nil {
48+
if os.IsNotExist(err) {
49+
return []string{}, nil
50+
}
51+
return nil, fmt.Errorf("failed to read benchmark directory for tag %s: %w", tag, err)
52+
}
53+
54+
var availableBenchmarks []string
55+
for _, entry := range entries {
56+
if entry.IsDir() {
57+
availableBenchmarks = append(availableBenchmarks, entry.Name())
58+
}
59+
}
60+
61+
return availableBenchmarks, nil
62+
}
63+
64+
// discoverAvailableProfiles scans a specific tag and benchmark for available profile types
65+
func discoverAvailableProfiles(tag, benchmarkName string) ([]string, error) {
66+
root, err := internal.FindGoModuleRoot()
67+
if err != nil {
68+
return nil, fmt.Errorf("failed to locate module root: %w", err)
69+
}
70+
71+
benchDir := filepath.Join(root, internal.MainDirOutput, tag, internal.ProfileTextDir, benchmarkName)
72+
entries, err := os.ReadDir(benchDir)
73+
if err != nil {
74+
if os.IsNotExist(err) {
75+
return []string{}, nil
76+
}
77+
return nil, fmt.Errorf("failed to read profile directory for tag %s, benchmark %s: %w", tag, benchmarkName, err)
78+
}
79+
80+
var availableProfiles []string
81+
for _, entry := range entries {
82+
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".txt") {
83+
// Extract profile type from filename like "BenchmarkName_cpu.txt"
84+
name := entry.Name()
85+
if strings.HasPrefix(name, benchmarkName+"_") {
86+
profileTypeName := strings.TrimSuffix(strings.TrimPrefix(name, benchmarkName+"_"), ".txt")
87+
if profileTypeName == "cpu" || profileTypeName == "memory" || profileTypeName == "mutex" || profileTypeName == "block" {
88+
availableProfiles = append(availableProfiles, profileTypeName)
89+
}
90+
}
91+
}
92+
}
93+
94+
return availableProfiles, nil
95+
}

cli/helpers.go renamed to cli/selections.go

Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@ package cli
22

33
import (
44
"fmt"
5-
"os"
6-
"path/filepath"
75
"strconv"
8-
"strings"
96

107
"github.com/AlecAivazis/survey/v2"
118

129
"github.com/AlexsanderHamir/prof/engine/tracker"
13-
"github.com/AlexsanderHamir/prof/internal"
1410
)
1511

1612
// getTrackSelections collects all user selections interactively
@@ -143,99 +139,3 @@ func selectRegressionThreshold(selections *tracker.Selections) error {
143139

144140
return nil
145141
}
146-
147-
// setGlobalTrackingVariables sets the global CLI variables for tracking
148-
func setGlobalTrackingVariables(selections *tracker.Selections) {
149-
Baseline = selections.Baseline
150-
Current = selections.Current
151-
benchmarkName = selections.BenchmarkName
152-
profileType = selections.ProfileType
153-
outputFormat = selections.OutputFormat
154-
failOnRegression = selections.UseThreshold
155-
regressionThreshold = selections.RegressionThreshold
156-
}
157-
158-
// discoverAvailableTags scans the bench directory for existing tags
159-
func discoverAvailableTags() ([]string, error) {
160-
root, err := internal.FindGoModuleRoot()
161-
if err != nil {
162-
return nil, fmt.Errorf("failed to locate module root: %w", err)
163-
}
164-
165-
benchDir := filepath.Join(root, internal.MainDirOutput)
166-
entries, err := os.ReadDir(benchDir)
167-
if err != nil {
168-
if os.IsNotExist(err) {
169-
return []string{}, nil
170-
}
171-
return nil, fmt.Errorf("failed to read bench directory: %w", err)
172-
}
173-
174-
var tags []string
175-
for _, entry := range entries {
176-
if entry.IsDir() {
177-
tags = append(tags, entry.Name())
178-
}
179-
}
180-
181-
return tags, nil
182-
}
183-
184-
// discoverAvailableBenchmarks scans a specific tag directory for available benchmarks
185-
func discoverAvailableBenchmarks(tag string) ([]string, error) {
186-
root, err := internal.FindGoModuleRoot()
187-
if err != nil {
188-
return nil, fmt.Errorf("failed to locate module root: %w", err)
189-
}
190-
191-
benchDir := filepath.Join(root, internal.MainDirOutput, tag, internal.ProfileTextDir)
192-
entries, err := os.ReadDir(benchDir)
193-
if err != nil {
194-
if os.IsNotExist(err) {
195-
return []string{}, nil
196-
}
197-
return nil, fmt.Errorf("failed to read benchmark directory for tag %s: %w", tag, err)
198-
}
199-
200-
var availableBenchmarks []string
201-
for _, entry := range entries {
202-
if entry.IsDir() {
203-
availableBenchmarks = append(availableBenchmarks, entry.Name())
204-
}
205-
}
206-
207-
return availableBenchmarks, nil
208-
}
209-
210-
// discoverAvailableProfiles scans a specific tag and benchmark for available profile types
211-
func discoverAvailableProfiles(tag, benchmarkName string) ([]string, error) {
212-
root, err := internal.FindGoModuleRoot()
213-
if err != nil {
214-
return nil, fmt.Errorf("failed to locate module root: %w", err)
215-
}
216-
217-
benchDir := filepath.Join(root, internal.MainDirOutput, tag, internal.ProfileTextDir, benchmarkName)
218-
entries, err := os.ReadDir(benchDir)
219-
if err != nil {
220-
if os.IsNotExist(err) {
221-
return []string{}, nil
222-
}
223-
return nil, fmt.Errorf("failed to read profile directory for tag %s, benchmark %s: %w", tag, benchmarkName, err)
224-
}
225-
226-
var availableProfiles []string
227-
for _, entry := range entries {
228-
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".txt") {
229-
// Extract profile type from filename like "BenchmarkName_cpu.txt"
230-
name := entry.Name()
231-
if strings.HasPrefix(name, benchmarkName+"_") {
232-
profileTypeName := strings.TrimSuffix(strings.TrimPrefix(name, benchmarkName+"_"), ".txt")
233-
if profileTypeName == "cpu" || profileTypeName == "memory" || profileTypeName == "mutex" || profileTypeName == "block" {
234-
availableProfiles = append(availableProfiles, profileTypeName)
235-
}
236-
}
237-
}
238-
}
239-
240-
return availableProfiles, nil
241-
}

engine/benchmark/constants.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package benchmark
2+
3+
var SupportedProfiles = []string{"cpu", "memory", "mutex", "block"}
4+
5+
var ProfileFlags = map[string]string{
6+
"cpu": "-cpuprofile=cpu.out",
7+
"memory": "-memprofile=memory.out",
8+
"mutex": "-mutexprofile=mutex.out",
9+
"block": "-blockprofile=block.out",
10+
}
11+
12+
var ExpectedFiles = map[string]string{
13+
"cpu": "cpu.out",
14+
"memory": "memory.out",
15+
"mutex": "mutex.out",
16+
"block": "block.out",
17+
}
18+
19+
const (
20+
binExtension = "out"
21+
descriptionFileName = "description.txt"
22+
moduleNotFoundMsg = "go: cannot find main module"
23+
waitForFiles = 100
24+
descritpionFileMessage = "The explanation for this profilling session goes here"
25+
26+
// Minimum number of regex capture groups expected for benchmark function
27+
minCaptureGroups = 2
28+
)

engine/benchmark/directories.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package benchmark
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/AlexsanderHamir/prof/internal"
10+
)
11+
12+
// createBenchDirectories creates the main structure of the library's output.
13+
func createBenchDirectories(tagDir string, benchmarks []string) error {
14+
binDir := filepath.Join(tagDir, internal.ProfileBinDir)
15+
textDir := filepath.Join(tagDir, internal.ProfileTextDir)
16+
descFile := filepath.Join(tagDir, descriptionFileName)
17+
18+
// Create main directories
19+
if err := os.Mkdir(binDir, internal.PermDir); err != nil {
20+
return fmt.Errorf("failed to create bin directory: %w", err)
21+
}
22+
if err := os.Mkdir(textDir, internal.PermDir); err != nil {
23+
return fmt.Errorf("failed to create text directory: %w", err)
24+
}
25+
26+
// Create benchmark subdirectories
27+
for _, benchmark := range benchmarks {
28+
if err := os.Mkdir(filepath.Join(binDir, benchmark), internal.PermDir); err != nil {
29+
return fmt.Errorf("failed to create bin subdirectory for %s: %w", benchmark, err)
30+
}
31+
if err := os.Mkdir(filepath.Join(textDir, benchmark), internal.PermDir); err != nil {
32+
return fmt.Errorf("failed to create text subdirectory for %s: %w", benchmark, err)
33+
}
34+
}
35+
36+
// Create description file
37+
if err := os.WriteFile(descFile, []byte(descritpionFileMessage), internal.PermFile); err != nil {
38+
return fmt.Errorf("failed to create description file: %w", err)
39+
}
40+
41+
slog.Info("Created directory structure", "dir", tagDir)
42+
return nil
43+
}
44+
45+
// createProfileFunctionDirectories creates the structure for the code line level data collection.
46+
func createProfileFunctionDirectories(tagDir string, profiles, benchmarks []string) error {
47+
for _, profileName := range profiles {
48+
profileDirPath := filepath.Join(tagDir, profileName+internal.FunctionsDirSuffix)
49+
if err := os.Mkdir(profileDirPath, internal.PermDir); err != nil {
50+
return fmt.Errorf("failed to create profile directory %s: %w", profileDirPath, err)
51+
}
52+
53+
for _, benchmark := range benchmarks {
54+
benchmarkDirPath := filepath.Join(profileDirPath, benchmark)
55+
if err := os.Mkdir(benchmarkDirPath, internal.PermDir); err != nil {
56+
return fmt.Errorf("failed to create benchmark directory %s: %w", benchmarkDirPath, err)
57+
}
58+
}
59+
}
60+
61+
slog.Info("Created profile function directories")
62+
return nil
63+
}
64+
65+
// SetupDirectories creates the structure of the library's output.
66+
func setupDirectories(tag string, benchmarks, profiles []string) error {
67+
currentDir, err := os.Getwd()
68+
if err != nil {
69+
return err
70+
}
71+
72+
tagDir := filepath.Join(currentDir, internal.MainDirOutput, tag)
73+
err = internal.CleanOrCreateTag(tagDir)
74+
if err != nil {
75+
return fmt.Errorf("CleanOrCreateTag failed: %w", err)
76+
}
77+
78+
if err = createBenchDirectories(tagDir, benchmarks); err != nil {
79+
return err
80+
}
81+
82+
return createProfileFunctionDirectories(tagDir, profiles, benchmarks)
83+
}

0 commit comments

Comments
 (0)