mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 10:06:24 +05:00
Revise CPU Profiling implementation
cgr-engine.go:
- use filepath.Join instead of path.Join
- handle *CoreService.StopCPUProfiling error inside deferred function
- same with the error from *os.File.Close()
cores/core.go:
- StartCPUProfile now returns an io.Closer (as opposed to an io.WriteCloser)
- handle pprof.StartCPUProfile error and ensure file is closed before returning
- log file close error as a warning if it occurs
- return missing mandatory error with correct path field name ('DirPath')
- no need to check if fileCPU is nil for profiling status
- pprof.StartCPUProfiling will return an error if profiling is already started
- os.File.Close() will return ErrClosed if profiling is already stopped
- differentiate between calling StopCPUProfiling when profiling hasn't started
and when it was already stopped by returning appropriate errors
- improved comments and error messages
This commit is contained in:
committed by
Dan Christian Bogos
parent
6f4d2144a6
commit
9d4561f79c
@@ -60,9 +60,11 @@ type CoreService struct {
|
||||
stopMemPrf chan struct{}
|
||||
shdChan *utils.SyncedChan
|
||||
fileMEM string
|
||||
fileCPU io.Closer
|
||||
fileMx sync.Mutex
|
||||
caps *engine.Caps
|
||||
|
||||
fileMux sync.Mutex
|
||||
fileCPU io.Closer
|
||||
|
||||
caps *engine.Caps
|
||||
}
|
||||
|
||||
// Shutdown is called to shutdown the service
|
||||
@@ -82,13 +84,21 @@ func (cS *CoreService) StopChanMemProf() {
|
||||
}
|
||||
}
|
||||
|
||||
func StartCPUProfiling(path string) (file io.WriteCloser, err error) {
|
||||
file, err = os.Create(path)
|
||||
// StartCPUProfiling creates a file and passes it to pprof.StartCPUProfile. It returns the file
|
||||
// as an io.Closer to be able to close it later when stopping the CPU profiling.
|
||||
func StartCPUProfiling(path string) (io.Closer, error) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create CPU profile: %v", err)
|
||||
}
|
||||
err = pprof.StartCPUProfile(file)
|
||||
return
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
if err := f.Close(); err != nil {
|
||||
utils.Logger.Warning(fmt.Sprintf(
|
||||
"<%s> could not close file %q: %v", utils.CoreS, f.Name(), err))
|
||||
}
|
||||
return nil, fmt.Errorf("could not start CPU profile: %v", err)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func MemProfFile(memProfPath string) bool {
|
||||
@@ -153,31 +163,32 @@ func (cS *CoreService) V1Status(_ *context.Context, _ *utils.TenantWithAPIOpts,
|
||||
return
|
||||
}
|
||||
|
||||
// StartCPUProfiling is used to start CPUProfiling in the given path
|
||||
func (cS *CoreService) StartCPUProfiling(argPath string) (err error) {
|
||||
cS.fileMx.Lock()
|
||||
defer cS.fileMx.Unlock()
|
||||
if cS.fileCPU != nil {
|
||||
return fmt.Errorf("CPU profiling already started")
|
||||
// StartCPUProfiling starts CPU profiling and saves the profile to the specified path.
|
||||
func (cS *CoreService) StartCPUProfiling(path string) (err error) {
|
||||
if path == utils.EmptyString {
|
||||
return utils.NewErrMandatoryIeMissing("DirPath")
|
||||
}
|
||||
if argPath == utils.EmptyString {
|
||||
return utils.NewErrMandatoryIeMissing("Path")
|
||||
}
|
||||
cS.fileCPU, err = StartCPUProfiling(argPath)
|
||||
cS.fileMux.Lock()
|
||||
defer cS.fileMux.Unlock()
|
||||
cS.fileCPU, err = StartCPUProfiling(path)
|
||||
return
|
||||
}
|
||||
|
||||
// StopCPUProfiling is used to stop CPUProfiling in the given path
|
||||
func (cS *CoreService) StopCPUProfiling() (err error) {
|
||||
cS.fileMx.Lock()
|
||||
defer cS.fileMx.Unlock()
|
||||
if cS.fileCPU != nil {
|
||||
pprof.StopCPUProfile()
|
||||
err = cS.fileCPU.Close()
|
||||
cS.fileCPU = nil
|
||||
return
|
||||
// StopCPUProfiling stops CPU profiling and closes the profile file.
|
||||
func (cS *CoreService) StopCPUProfiling() error {
|
||||
cS.fileMux.Lock()
|
||||
defer cS.fileMux.Unlock()
|
||||
pprof.StopCPUProfile()
|
||||
if cS.fileCPU == nil {
|
||||
return errors.New("CPU profiling has not been started")
|
||||
}
|
||||
return fmt.Errorf(" cannot stop because CPUProfiling is not active")
|
||||
if err := cS.fileCPU.Close(); err != nil {
|
||||
if errors.Is(err, os.ErrClosed) {
|
||||
return errors.New("CPU profiling has already been stopped")
|
||||
}
|
||||
return fmt.Errorf("could not close profile file: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartMemoryProfiling is used to start MemoryProfiling in the given path
|
||||
|
||||
Reference in New Issue
Block a user