Skip to content

Commit 710413f

Browse files
committed
feat(profiler): add CPU and memory profiling support
Introduce a new profiler package to handle CPU and memory profiling. This allows developers to analyze performance bottlenecks by enabling profiling flags in the main application. The profiler outputs profiles to a specified directory, with timestamps for unique file naming. Added the `profiles` directory to .gitignore to exclude profiling outputs from version control.
1 parent 8b3cb7f commit 710413f

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
vendor
22
local
33

4-
bin
4+
bin
5+
6+
# dev
7+
profiles

main.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,46 @@
11
package main
22

33
import (
4+
"flag"
5+
46
"github.com/vldcreation/helpme/cmd"
7+
"github.com/vldcreation/helpme/pkg/profiler"
58
"github.com/vldcreation/helpme/util"
69
)
710

811
func main() {
12+
// Setup profiling flags
13+
cpuProfile := flag.String("cpuprofile", "", "write cpu profile to file")
14+
memProfile := flag.String("memprofile", "", "write memory profile to file")
15+
flag.Parse()
16+
17+
// Initialize profiler if profiling is enabled
18+
if *cpuProfile != "" || *memProfile != "" {
19+
prof, err := profiler.New("./profiles")
20+
if err != nil {
21+
util.PrintlnRed(err.Error())
22+
return
23+
}
24+
25+
// Start CPU profiling if requested
26+
if *cpuProfile != "" {
27+
if err := prof.StartCPUProfile(); err != nil {
28+
util.PrintlnRed(err.Error())
29+
return
30+
}
31+
defer prof.StopCPUProfile()
32+
}
33+
34+
// Write memory profile at exit if requested
35+
if *memProfile != "" {
36+
defer func() {
37+
if err := prof.WriteHeapProfile(); err != nil {
38+
util.PrintlnRed(err.Error())
39+
}
40+
}()
41+
}
42+
}
43+
944
if err := cmd.NewApp().Execute(); err != nil {
1045
util.PrintlnRed(err.Error())
1146
}

pkg/profiler/profiler.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package profiler
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"runtime/pprof"
8+
"time"
9+
)
10+
11+
// Profiler handles CPU and memory profiling
12+
type Profiler struct {
13+
cpuFile *os.File
14+
memFile *os.File
15+
outputDir string
16+
}
17+
18+
// New creates a new profiler instance
19+
func New(outputDir string) (*Profiler, error) {
20+
if outputDir == "" {
21+
outputDir = "."
22+
}
23+
24+
if err := os.MkdirAll(outputDir, 0755); err != nil {
25+
return nil, fmt.Errorf("failed to create output directory: %w", err)
26+
}
27+
28+
return &Profiler{outputDir: outputDir}, nil
29+
}
30+
31+
// StartCPUProfile starts CPU profiling
32+
func (p *Profiler) StartCPUProfile() error {
33+
timestamp := time.Now().Format("20060102-150405")
34+
cpuFile := filepath.Join(p.outputDir, fmt.Sprintf("cpu-%s.prof", timestamp))
35+
36+
f, err := os.Create(cpuFile)
37+
if err != nil {
38+
return fmt.Errorf("could not create CPU profile: %w", err)
39+
}
40+
41+
if err := pprof.StartCPUProfile(f); err != nil {
42+
f.Close()
43+
return fmt.Errorf("could not start CPU profile: %w", err)
44+
}
45+
46+
p.cpuFile = f
47+
return nil
48+
}
49+
50+
// StopCPUProfile stops CPU profiling
51+
func (p *Profiler) StopCPUProfile() {
52+
if p.cpuFile != nil {
53+
pprof.StopCPUProfile()
54+
p.cpuFile.Close()
55+
p.cpuFile = nil
56+
}
57+
}
58+
59+
// WriteHeapProfile writes memory profile
60+
func (p *Profiler) WriteHeapProfile() error {
61+
timestamp := time.Now().Format("20060102-150405")
62+
memFile := filepath.Join(p.outputDir, fmt.Sprintf("mem-%s.prof", timestamp))
63+
64+
f, err := os.Create(memFile)
65+
if err != nil {
66+
return fmt.Errorf("could not create memory profile: %w", err)
67+
}
68+
defer f.Close()
69+
70+
if err := pprof.WriteHeapProfile(f); err != nil {
71+
return fmt.Errorf("could not write memory profile: %w", err)
72+
}
73+
74+
return nil
75+
}

0 commit comments

Comments
 (0)