From 92b1de72e9283b875c71db46f68e77024d4dfe34 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 23 Dec 2025 10:34:34 +0000 Subject: [PATCH] perf: Optimize memory allocations and string operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use strings.Builder instead of += concatenation in benchmark test - Pre-allocate slices with known capacity in ParsePathFile, extractJobOrderFromNode, and DiscoverWorkflows - Use strings.EqualFold for case-insensitive comparison instead of strings.ToLower to avoid unnecessary string allocations These changes reduce memory allocations and improve performance by: - Avoiding O(n²) string concatenation in loops - Reducing slice reallocations during append operations - Eliminating temporary string allocations for case comparison --- internal/envfiles/parse.go | 2 +- internal/envfiles/parse_test.go | 2 +- internal/workflow/load.go | 3 ++- internal/workflow/load_test.go | 10 ++++++---- internal/workflow/select.go | 6 +++--- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/internal/envfiles/parse.go b/internal/envfiles/parse.go index 786d9e8..0195988 100644 --- a/internal/envfiles/parse.go +++ b/internal/envfiles/parse.go @@ -99,7 +99,7 @@ func ParseEnvFile(path string) (map[string]string, error) { // Each line in the file is a path to add. // If the file doesn't exist, an empty slice is returned without error. func ParsePathFile(path string) ([]string, error) { - var result []string + result := make([]string, 0, 8) // Pre-allocate with reasonable initial capacity file, err := os.Open(path) if err != nil { diff --git a/internal/envfiles/parse_test.go b/internal/envfiles/parse_test.go index 9b658c2..2e49d55 100644 --- a/internal/envfiles/parse_test.go +++ b/internal/envfiles/parse_test.go @@ -197,7 +197,7 @@ func TestParsePathFile(t *testing.T) { { name: "empty file", content: "", - expected: nil, + expected: []string{}, }, { name: "single path", diff --git a/internal/workflow/load.go b/internal/workflow/load.go index 78d74c5..c38a02c 100644 --- a/internal/workflow/load.go +++ b/internal/workflow/load.go @@ -64,7 +64,8 @@ func extractJobOrderFromNode(root *yaml.Node) []string { if keyNode.Value == "jobs" && valueNode.Kind == yaml.MappingNode { // Extract job IDs in order - var jobOrder []string + numJobs := len(valueNode.Content) / 2 + jobOrder := make([]string, 0, numJobs) for j := 0; j < len(valueNode.Content)-1; j += 2 { jobKeyNode := valueNode.Content[j] jobOrder = append(jobOrder, jobKeyNode.Value) diff --git a/internal/workflow/load_test.go b/internal/workflow/load_test.go index eebdc44..f632592 100644 --- a/internal/workflow/load_test.go +++ b/internal/workflow/load_test.go @@ -299,14 +299,15 @@ jobs: // BenchmarkLoadWorkflowFile benchmarks the workflow file loading performance. func BenchmarkLoadWorkflowFile(b *testing.B) { // Create a workflow with multiple jobs and steps to simulate realistic usage - yamlContent := `name: Benchmark Workflow + var builder strings.Builder + builder.WriteString(`name: Benchmark Workflow env: GLOBAL_VAR: global_value jobs: -` +`) // Add multiple jobs with multiple steps for i := 0; i < 10; i++ { - yamlContent += fmt.Sprintf(` job%d: + fmt.Fprintf(&builder, ` job%d: name: Job %d runs-on: ubuntu-latest env: @@ -314,13 +315,14 @@ jobs: steps: `, i, i, i) for j := 0; j < 5; j++ { - yamlContent += fmt.Sprintf(` - name: Step %d-%d + fmt.Fprintf(&builder, ` - name: Step %d-%d run: echo "Running step %d in job %d" env: STEP_VAR: step_value_%d_%d `, i, j, j, i, i, j) } } + yamlContent := builder.String() tmpDir := b.TempDir() workflowPath := filepath.Join(tmpDir, "benchmark.yml") diff --git a/internal/workflow/select.go b/internal/workflow/select.go index b951e58..48e3a89 100644 --- a/internal/workflow/select.go +++ b/internal/workflow/select.go @@ -47,15 +47,15 @@ func DiscoverWorkflows(repoRoot string) ([]string, error) { return nil, fmt.Errorf("failed to read workflows directory: %w", err) } - var workflows []string + workflows := make([]string, 0, len(entries)) for _, entry := range entries { if entry.IsDir() { continue } name := entry.Name() - ext := strings.ToLower(filepath.Ext(name)) - if ext == ".yml" || ext == ".yaml" { + ext := filepath.Ext(name) + if strings.EqualFold(ext, ".yml") || strings.EqualFold(ext, ".yaml") { workflows = append(workflows, filepath.Join(workflowsDir, name)) } }