From 6988669b4493be9acbcf1665c77106f35a8e9b9d Mon Sep 17 00:00:00 2001 From: AlexanderGomes Date: Tue, 26 Aug 2025 11:45:29 -0700 Subject: [PATCH 1/2] parser package organization --- parser/apiv2.go | 135 +------------------------------------------- parser/helpersv2.go | 111 ++++++++++++++++++++++++++++++++++++ parser/types.go | 31 ++++++++++ 3 files changed, 143 insertions(+), 134 deletions(-) create mode 100644 parser/types.go diff --git a/parser/apiv2.go b/parser/apiv2.go index 711ffea..9e3b095 100644 --- a/parser/apiv2.go +++ b/parser/apiv2.go @@ -1,22 +1,9 @@ package parser import ( - "fmt" - "sort" - "strings" - "github.com/AlexsanderHamir/prof/internal" ) -type LineObj struct { - FnName string - Flat float64 - FlatPercentage float64 - SumPercentage float64 - Cum float64 - CumPercentage float64 -} - // TurnLinesIntoObjectsV2 turn profile data from a .pprof file into line objects. func TurnLinesIntoObjectsV2(profilePath string) ([]*LineObj, error) { profileData, err := extractProfileData(profilePath) @@ -129,6 +116,7 @@ func OrganizeProfileByPackageV2(profilePath string, filter internal.FunctionFilt FlatPercentage: profileData.FlatPercentages[fn], Cum: float64(profileData.Cum[fn]), CumPercentage: profileData.CumPercentages[fn], + SumPercentage: profileData.SumPercentages[fn], } packageGroups[packageName].Functions = append(packageGroups[packageName].Functions, funcInfo) @@ -149,124 +137,3 @@ func OrganizeProfileByPackageV2(profilePath string, filter internal.FunctionFilt // Generate formatted output return formatPackageReport(sortedPackages), nil } - -// PackageGroup represents a group of functions from the same package -type PackageGroup struct { - Name string - Functions []*FunctionInfo - TotalFlat float64 - TotalCum float64 - FlatPercentage float64 - CumPercentage float64 -} - -// FunctionInfo represents a function with its performance metrics -type FunctionInfo struct { - Name string - FullName string - Flat float64 - FlatPercentage float64 - Cum float64 - CumPercentage float64 -} - -// extractPackageName extracts the package name from a full function path -func extractPackageName(fullPath string) string { - // Handle cases like "github.com/user/pkg.(*Type).Method" => "github.com/user/pkg" - // or "sync/atomic.CompareAndSwapPointer" => "sync/atomic" - - // Split by dots - parts := strings.Split(fullPath, ".") - if len(parts) < 2 { - return "" - } - - // Check if it's a standard library package (like "sync/atomic") - if !strings.Contains(parts[0], "/") && len(parts) >= 2 { - // Standard library package - if len(parts) >= 3 && strings.Contains(parts[1], "/") { - return parts[0] + "." + parts[1] - } - return parts[0] - } - - // Check if it's a GitHub-style package - if strings.Contains(parts[0], "github.com") || strings.Contains(parts[0], "golang.org") { - // For GitHub packages, take up to the third part (github.com/user/pkg) - if len(parts) >= 3 { - return strings.Join(parts[:3], ".") - } - return strings.Join(parts[:2], ".") - } - - // For other cases, take the first part - return parts[0] -} - -// sortPackagesByFlatPercentage sorts packages by their flat percentage in descending order -func sortPackagesByFlatPercentage(packageGroups map[string]*PackageGroup) []*PackageGroup { - var packages []*PackageGroup - for _, pkg := range packageGroups { - packages = append(packages, pkg) - } - - sort.Slice(packages, func(i, j int) bool { - return packages[i].FlatPercentage > packages[j].FlatPercentage - }) - - return packages -} - -// formatPackageReport formats the package groups into a readable report -func formatPackageReport(packages []*PackageGroup) string { - var result strings.Builder - - for i, pkg := range packages { - if i > 0 { - result.WriteString("\n\n") - } - - // Package header - result.WriteString(fmt.Sprintf("#### **%s**\n", pkg.Name)) - - // Sort functions by flat percentage (descending) - sort.Slice(pkg.Functions, func(i, j int) bool { - return pkg.Functions[i].FlatPercentage > pkg.Functions[j].FlatPercentage - }) - - // List functions - for _, fn := range pkg.Functions { - if fn.Flat > 0 { - // Show only function name and percentage - result.WriteString(fmt.Sprintf("- `%s` → %.2f%%\n", - fn.Name, fn.FlatPercentage)) - } else if fn.Cum > 0 { - // Function with only cumulative time - result.WriteString(fmt.Sprintf("- `%s` → 0%% (cum %.2f%%)\n", - fn.Name, fn.CumPercentage)) - } - } - - // Package subtotal - result.WriteString(fmt.Sprintf("\n**Subtotal (%s)**: ≈%.1f%%", - extractShortPackageName(pkg.Name), pkg.FlatPercentage)) - } - - return result.String() -} - -// extractShortPackageName extracts a shorter version of the package name for display -func extractShortPackageName(fullPackageName string) string { - parts := strings.Split(fullPackageName, ".") - if len(parts) == 0 { - return fullPackageName - } - - // For GitHub packages, show just the last part - if strings.Contains(fullPackageName, "github.com") { - return parts[len(parts)-1] - } - - // For standard library, show the full name - return fullPackageName -} diff --git a/parser/helpersv2.go b/parser/helpersv2.go index 0ea61f6..187b447 100644 --- a/parser/helpersv2.go +++ b/parser/helpersv2.go @@ -223,3 +223,114 @@ func getFilterSets(ignoreFunctions []string) map[string]struct{} { return ignoreSet } + +// extractPackageName extracts the package name from a full function path +func extractPackageName(fullPath string) string { + // Handle cases like "github.com/user/pkg.(*Type).Method" => "github.com/user/pkg" + // or "sync/atomic.CompareAndSwapPointer" => "sync/atomic" + + // Split by dots + parts := strings.Split(fullPath, ".") + if len(parts) < 2 { + return "" + } + + // Check if it's a standard library package (like "sync/atomic") + if !strings.Contains(parts[0], "/") && len(parts) >= 2 { + // Standard library package + if len(parts) >= 3 && strings.Contains(parts[1], "/") { + return parts[0] + "." + parts[1] + } + return parts[0] + } + + // Check if it's a GitHub-style package + if strings.Contains(parts[0], "github.com") || strings.Contains(parts[0], "golang.org") { + // For GitHub packages, take up to the third part (github.com/user/pkg) + if len(parts) >= 3 { + return strings.Join(parts[:3], ".") + } + return strings.Join(parts[:2], ".") + } + + // For other cases, take the first part + return parts[0] +} + +// sortPackagesByFlatPercentage sorts packages by their flat percentage in descending order +func sortPackagesByFlatPercentage(packageGroups map[string]*PackageGroup) []*PackageGroup { + var packages []*PackageGroup + for _, pkg := range packageGroups { + packages = append(packages, pkg) + } + + sort.Slice(packages, func(i, j int) bool { + return packages[i].FlatPercentage > packages[j].FlatPercentage + }) + + return packages +} + +// formatPackageReport formats the package groups into a readable report +func formatPackageReport(packages []*PackageGroup) string { + var result strings.Builder + + for i, pkg := range packages { + if i > 0 { + result.WriteString("\n\n") + } + + // Package header + result.WriteString(fmt.Sprintf("#### **%s**\n", pkg.Name)) + + // Sort functions by flat percentage (descending) + sort.Slice(pkg.Functions, func(i, j int) bool { + return pkg.Functions[i].FlatPercentage > pkg.Functions[j].FlatPercentage + }) + + // List functions + for _, fn := range pkg.Functions { + if pkg.Name == "unknown" { + // For unknown package, show full prof-style output + if fn.Flat > 0 { + result.WriteString(fmt.Sprintf("- `%s` → flat: %.2f, flat%%: %.2f%%, sum%%: %.2f%%, cum: %.2f, cum%%: %.2f%%\n", + fn.Name, fn.Flat, fn.FlatPercentage, fn.SumPercentage, fn.Cum, fn.CumPercentage)) + } else if fn.Cum > 0 { + result.WriteString(fmt.Sprintf("- `%s` → flat: 0, flat%%: 0%%, sum%%: 0%%, cum: %.2f, cum%%: %.2f%%\n", + fn.Name, fn.Cum, fn.CumPercentage)) + } + } else { + // For known packages, show simplified format + if fn.Flat > 0 { + result.WriteString(fmt.Sprintf("- `%s` → %.2f%%\n", + fn.Name, fn.FlatPercentage)) + } else if fn.Cum > 0 { + result.WriteString(fmt.Sprintf("- `%s` → 0%% (cum %.2f%%)\n", + fn.Name, fn.CumPercentage)) + } + } + } + + // Package subtotal + result.WriteString(fmt.Sprintf("\n**Subtotal (%s)**: ≈%.1f%%", + extractShortPackageName(pkg.Name), pkg.FlatPercentage)) + } + + return result.String() +} + +// extractShortPackageName extracts a shorter version of the package name for display +func extractShortPackageName(fullPackageName string) string { + parts := strings.Split(fullPackageName, ".") + if len(parts) == 0 { + return fullPackageName + } + + // For GitHub packages, show just the last part + if strings.Contains(fullPackageName, "github.com") { + return parts[len(parts)-1] + } + + // For standard library, show the full name + return fullPackageName +} diff --git a/parser/types.go b/parser/types.go new file mode 100644 index 0000000..9cf386a --- /dev/null +++ b/parser/types.go @@ -0,0 +1,31 @@ +package parser + +type LineObj struct { + FnName string + Flat float64 + FlatPercentage float64 + SumPercentage float64 + Cum float64 + CumPercentage float64 +} + +// PackageGroup represents a group of functions from the same package +type PackageGroup struct { + Name string + Functions []*FunctionInfo + TotalFlat float64 + TotalCum float64 + FlatPercentage float64 + CumPercentage float64 +} + +// FunctionInfo represents a function with its performance metrics +type FunctionInfo struct { + Name string + FullName string + Flat float64 + FlatPercentage float64 + Cum float64 + CumPercentage float64 + SumPercentage float64 +} From 56d65041c14d07b25bf62ec315d78aed2e9b410a Mon Sep 17 00:00:00 2001 From: AlexanderGomes Date: Tue, 26 Aug 2025 11:48:53 -0700 Subject: [PATCH 2/2] simplified branch condition --- parser/helpersv2.go | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/parser/helpersv2.go b/parser/helpersv2.go index 187b447..936c3b4 100644 --- a/parser/helpersv2.go +++ b/parser/helpersv2.go @@ -271,6 +271,18 @@ func sortPackagesByFlatPercentage(packageGroups map[string]*PackageGroup) []*Pac return packages } +// formatFunctionOutput formats a single function's output based on package type +func formatFunctionOutput(fn *FunctionInfo, isUnknownPackage bool) string { + if isUnknownPackage { + // For unknown package, show full prof-style output + return fmt.Sprintf("- `%s` → flat: %.2f, flat%%: %.2f%%, sum%%: %.2f%%, cum: %.2f, cum%%: %.2f%%\n", + fn.Name, fn.Flat, fn.FlatPercentage, fn.SumPercentage, fn.Cum, fn.CumPercentage) + } + + // For known packages, show simplified format + return fmt.Sprintf("- `%s` → %.2f%%\n", fn.Name, fn.FlatPercentage) +} + // formatPackageReport formats the package groups into a readable report func formatPackageReport(packages []*PackageGroup) string { var result strings.Builder @@ -289,26 +301,9 @@ func formatPackageReport(packages []*PackageGroup) string { }) // List functions + isUnknownPackage := pkg.Name == "unknown" for _, fn := range pkg.Functions { - if pkg.Name == "unknown" { - // For unknown package, show full prof-style output - if fn.Flat > 0 { - result.WriteString(fmt.Sprintf("- `%s` → flat: %.2f, flat%%: %.2f%%, sum%%: %.2f%%, cum: %.2f, cum%%: %.2f%%\n", - fn.Name, fn.Flat, fn.FlatPercentage, fn.SumPercentage, fn.Cum, fn.CumPercentage)) - } else if fn.Cum > 0 { - result.WriteString(fmt.Sprintf("- `%s` → flat: 0, flat%%: 0%%, sum%%: 0%%, cum: %.2f, cum%%: %.2f%%\n", - fn.Name, fn.Cum, fn.CumPercentage)) - } - } else { - // For known packages, show simplified format - if fn.Flat > 0 { - result.WriteString(fmt.Sprintf("- `%s` → %.2f%%\n", - fn.Name, fn.FlatPercentage)) - } else if fn.Cum > 0 { - result.WriteString(fmt.Sprintf("- `%s` → 0%% (cum %.2f%%)\n", - fn.Name, fn.CumPercentage)) - } - } + result.WriteString(formatFunctionOutput(fn, isUnknownPackage)) } // Package subtotal