Skip to content

Commit 77fdfe0

Browse files
Tracker Changes
Now the tool offers manual and auto modes, because of that the tracker needs to change as well since it was built only with the auto mode in mind
1 parent af46887 commit 77fdfe0

File tree

4 files changed

+115
-23
lines changed

4 files changed

+115
-23
lines changed

cli/api.go

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,31 @@ func createRunCmd() *cobra.Command {
9494

9595
// createTrackCmd creates the track subcommand
9696
func createTrackCmd() *cobra.Command {
97+
shortExplanation := "Compare performance between two benchmark runs to detect regressions and improvements"
98+
cmd := &cobra.Command{
99+
Use: "track",
100+
Short: shortExplanation,
101+
}
102+
103+
cmd.AddCommand(createTrackAutoCmd())
104+
cmd.AddCommand(createTrackManualCmd())
105+
106+
return cmd
107+
}
108+
109+
func createTrackAutoCmd() *cobra.Command {
97110
baseTagFlag := "base-tag"
98111
currentTagFlag := "current-tag"
99112
benchNameFlag := "bench-name"
100113
profileTypeFlag := "profile-type"
101114
outputFormatFlag := "output-format"
102-
example := fmt.Sprintf(`prof track --%s "tag1" --%s "tag2" --%s "cpu" --%s "BenchmarkGenPool" --%s "summary"`, baseTagFlag, currentTagFlag, profileTypeFlag, benchNameFlag, outputFormatFlag)
103-
shortExplanation := "Compare performance between two benchmark runs to detect regressions and improvements"
104-
longExplanation := "This command only works if the run command was used to collect and organize the benchmark and profile data, as it expects a specific directory structure generated by that process."
115+
example := fmt.Sprintf(`prof track auto --%s "tag1" --%s "tag2" --%s "cpu" --%s "BenchmarkGenPool" --%s "summary"`, baseTagFlag, currentTagFlag, profileTypeFlag, benchNameFlag, outputFormatFlag)
116+
longExplanation := fmt.Sprintf("This command only works if the %s command was used to collect and organize the benchmark and profile data, as it expects a specific directory structure generated by that process.", shared.AUTOCMD)
105117

106118
cmd := &cobra.Command{
107-
Use: "track",
108-
Short: shortExplanation,
119+
Use: shared.TrackAutoCMD,
109120
Long: longExplanation,
110-
RunE: runTrack,
121+
RunE: runTrackAuto,
111122
Example: example,
112123
}
113124

@@ -125,6 +136,30 @@ func createTrackCmd() *cobra.Command {
125136
return cmd
126137
}
127138

139+
func createTrackManualCmd() *cobra.Command {
140+
baseFlag := "base"
141+
currentFlag := "current"
142+
outputFormatFlag := "output-format"
143+
example := fmt.Sprintf(`prof track %s --%s "path/to/profile_file.txt" --%s "path/to/profile_file.txt" --%s "summary"`, shared.TrackManualCMD, baseFlag, currentFlag, outputFormatFlag)
144+
145+
cmd := &cobra.Command{
146+
Use: shared.TrackManualCMD,
147+
Short: "Manually specify the paths to the profile text files you want to compare.",
148+
RunE: runTrackManual,
149+
Example: example,
150+
}
151+
152+
cmd.Flags().StringVar(&baselineTag, baseFlag, "", "Name of the baseline tag")
153+
cmd.Flags().StringVar(&currentTag, currentFlag, "", "Name of the current tag")
154+
cmd.Flags().StringVar(&outputFormat, outputFormatFlag, "", "Output format choice choice")
155+
156+
_ = cmd.MarkFlagRequired(baseFlag)
157+
_ = cmd.MarkFlagRequired(currentFlag)
158+
_ = cmd.MarkFlagRequired(outputFormatFlag)
159+
160+
return cmd
161+
}
162+
128163
func createVersionCmd() *cobra.Command {
129164
cmd := &cobra.Command{
130165
Use: "version",
@@ -201,7 +236,7 @@ func runSetup(_ *cobra.Command, _ []string) error {
201236
}
202237

203238
// runTrack handles the track command execution
204-
func runTrack(_ *cobra.Command, _ []string) error {
239+
func runTrackAuto(_ *cobra.Command, _ []string) error {
205240
validFormats := map[string]bool{
206241
"summary": true,
207242
"detailed": true,
@@ -231,3 +266,33 @@ func runTrack(_ *cobra.Command, _ []string) error {
231266

232267
return nil
233268
}
269+
270+
func runTrackManual(_ *cobra.Command, _ []string) error {
271+
validFormats := map[string]bool{
272+
"summary": true,
273+
"detailed": true,
274+
}
275+
276+
if !validFormats[outputFormat] {
277+
return fmt.Errorf("invalid output format '%s'. Valid formats: summary, detailed", outputFormat)
278+
}
279+
280+
report, err := tracker.CheckPerformanceDifferencesManual(baselineTag, currentTag)
281+
if err != nil {
282+
return fmt.Errorf("failed to track performance differences: %w", err)
283+
}
284+
285+
noFunctionChanges := len(report.FunctionChanges) == 0
286+
if noFunctionChanges {
287+
slog.Info("No function changes detected between the two runs")
288+
return nil
289+
}
290+
291+
switch outputFormat {
292+
case "summary":
293+
printSummary(report)
294+
case "detailed":
295+
printDetailedReport(report)
296+
}
297+
return nil
298+
}

parser/api.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ func TurnLinesIntoObjects(profilePath, profileType string) ([]*LineObj, error) {
6161
}
6262
defer file.Close()
6363

64-
shouldRemove := true
65-
CollectOrRemoveHeader(scanner, profileType, &lines, shouldRemove)
64+
CollectOrRemoveHeader(scanner, profileType)
6665

6766
GetAllProfileLines(scanner, &lines)
6867

@@ -152,18 +151,11 @@ func GetAllProfileLines(scanner *bufio.Scanner, lines *[]string) {
152151
}
153152
}
154153

155-
func CollectOrRemoveHeader(scanner *bufio.Scanner, profileType string, lines *[]string, shouldRemove bool) {
156-
lineCount := 0
157-
158-
headerIndex := 6
159-
if profileType != "cpu" {
160-
headerIndex = 5
161-
}
162-
163-
for lineCount < headerIndex && scanner.Scan() {
164-
if !shouldRemove {
165-
*lines = append(*lines, scanner.Text())
154+
func CollectOrRemoveHeader(scanner *bufio.Scanner, profileType string) {
155+
for scanner.Scan() {
156+
line := scanner.Text()
157+
if strings.Contains(line, header) {
158+
break
166159
}
167-
lineCount++
168160
}
169161
}

shared/utils.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import (
99

1010
// CLI Commands
1111
const (
12-
AUTOCMD = "auto"
13-
MANUALCMD = "manual"
12+
AUTOCMD = "auto"
13+
MANUALCMD = "manual"
14+
TrackAutoCMD = AUTOCMD
15+
TrackManualCMD = MANUALCMD
1416
)
1517

1618
const (

tracker/api.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,36 @@ func CheckPerformanceDifferences(baselineTag, currentTag, benchName, profileType
4444

4545
return pgp, nil
4646
}
47+
48+
// CheckPerformanceDifferences creates the profile report by comparing data from prof's auto run.
49+
func CheckPerformanceDifferencesManual(baselineProfile, currentProfile string) (*ProfileChangeReport, error) {
50+
lineObjsBaseline, err := parser.TurnLinesIntoObjects(baselineProfile, "")
51+
if err != nil {
52+
return nil, fmt.Errorf("couldn't get objs for path: %s, error: %w", baselineProfile, err)
53+
}
54+
55+
lineObjsCurrent, err := parser.TurnLinesIntoObjects(currentProfile, "")
56+
if err != nil {
57+
return nil, fmt.Errorf("couldn't get objs for path: %s, error: %w", currentProfile, err)
58+
}
59+
60+
matchingMap := createHashFromLineObjects(lineObjsBaseline)
61+
62+
pgp := &ProfileChangeReport{}
63+
for _, currentObj := range lineObjsCurrent {
64+
baseLineObj, matchNotFound := matchingMap[currentObj.FnName]
65+
if !matchNotFound {
66+
continue
67+
}
68+
69+
var changeResult *FunctionChangeResult
70+
changeResult, err = DetectChange(baseLineObj, currentObj)
71+
if err != nil {
72+
return nil, fmt.Errorf("DetectChange failed: %w", err)
73+
}
74+
75+
pgp.FunctionChanges = append(pgp.FunctionChanges, changeResult)
76+
}
77+
78+
return pgp, nil
79+
}

0 commit comments

Comments
 (0)