mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 10:06:24 +05:00
Ensure reference fileCPU is not overwritten
Would previously happen if memory profiling was already started. Now using os.File.Stat beforehand to check if a handler of the file is already active and confirm the status of profiling. This required changing the type of the reference fileCPU from io.Closer to *os.File. Asserting the type would have worked as well.
This commit is contained in:
committed by
Dan Christian Bogos
parent
1c490a9020
commit
218ad92635
@@ -21,7 +21,6 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -354,7 +353,7 @@ func main() {
|
||||
go singnalHandler(shdWg, shdChan)
|
||||
|
||||
var cS *cores.CoreService
|
||||
var cpuProf io.Closer
|
||||
var cpuProf *os.File
|
||||
if *cpuProfDir != utils.EmptyString {
|
||||
cpuPath := filepath.Join(*cpuProfDir, utils.CpuPathCgr)
|
||||
cpuProf, err = cores.StartCPUProfiling(cpuPath)
|
||||
@@ -371,7 +370,7 @@ func main() {
|
||||
}
|
||||
pprof.StopCPUProfile()
|
||||
if err := cpuProf.Close(); err != nil {
|
||||
log.Printf("could not close file %q: %v", cpuProf.(*os.File).Name(), err)
|
||||
log.Print(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ package cores
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -36,7 +35,7 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, fileCPU io.Closer, stopChan chan struct{},
|
||||
func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, fileCPU *os.File, stopChan chan struct{},
|
||||
shdWg *sync.WaitGroup, shdChan *utils.SyncedChan) *CoreService {
|
||||
var st *engine.CapsStats
|
||||
if caps.IsLimited() && cfg.CoreSCfg().CapsStatsInterval != 0 {
|
||||
@@ -63,7 +62,7 @@ type CoreService struct {
|
||||
stopMemProf chan struct{} // signal end of memory profiling
|
||||
|
||||
fileCPUMux sync.Mutex
|
||||
fileCPU io.Closer
|
||||
fileCPU *os.File
|
||||
|
||||
caps *engine.Caps
|
||||
}
|
||||
@@ -76,27 +75,38 @@ func (cS *CoreService) Shutdown() {
|
||||
}
|
||||
|
||||
// StartCPUProfiling starts CPU profiling and saves the profile to the specified path.
|
||||
func (cS *CoreService) StartCPUProfiling(path string) (err error) {
|
||||
func (cS *CoreService) StartCPUProfiling(path string) error {
|
||||
if path == utils.EmptyString {
|
||||
return utils.NewErrMandatoryIeMissing("DirPath")
|
||||
}
|
||||
cS.fileCPUMux.Lock()
|
||||
defer cS.fileCPUMux.Unlock()
|
||||
cS.fileCPU, err = StartCPUProfiling(path)
|
||||
return
|
||||
|
||||
if cS.fileCPU != nil {
|
||||
// Check if the profiling is already active by calling Stat() on the file handle.
|
||||
// If Stat() returns nil, it means profiling is already active.
|
||||
if _, err := cS.fileCPU.Stat(); err == nil {
|
||||
return errors.New("start CPU profiling: already started")
|
||||
}
|
||||
}
|
||||
file, err := StartCPUProfiling(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cS.fileCPU = file
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// to be able to verify the status of profiling and close it after profiling is stopped.
|
||||
func StartCPUProfiling(path string) (*os.File, error) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create CPU profile: %v", err)
|
||||
}
|
||||
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))
|
||||
utils.Logger.Warning(fmt.Sprintf("<%s> %v", utils.CoreS, err))
|
||||
}
|
||||
return nil, fmt.Errorf("could not start CPU profile: %v", err)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/cgrates/birpc"
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
// NewCoreService returns the Core Service
|
||||
func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, server *cores.Server,
|
||||
internalCoreSChan chan birpc.ClientConnector, anz *AnalyzerService,
|
||||
fileCpu io.Closer, shdWg *sync.WaitGroup, shdChan *utils.SyncedChan,
|
||||
fileCPU *os.File, shdWg *sync.WaitGroup, shdChan *utils.SyncedChan,
|
||||
srvDep map[string]*sync.WaitGroup) *CoreService {
|
||||
return &CoreService{
|
||||
shdChan: shdChan,
|
||||
@@ -41,7 +41,7 @@ func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, server *cores.Serv
|
||||
connChan: internalCoreSChan,
|
||||
cfg: cfg,
|
||||
caps: caps,
|
||||
fileCpu: fileCpu,
|
||||
fileCPU: fileCPU,
|
||||
server: server,
|
||||
anz: anz,
|
||||
srvDep: srvDep,
|
||||
@@ -57,7 +57,7 @@ type CoreService struct {
|
||||
stopChan chan struct{}
|
||||
shdWg *sync.WaitGroup
|
||||
shdChan *utils.SyncedChan
|
||||
fileCpu io.Closer
|
||||
fileCPU *os.File
|
||||
cS *cores.CoreService
|
||||
connChan chan birpc.ClientConnector
|
||||
anz *AnalyzerService
|
||||
@@ -74,7 +74,7 @@ func (cS *CoreService) Start() error {
|
||||
defer cS.Unlock()
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> starting <%s> subsystem", utils.CoreS, utils.CoreS))
|
||||
cS.stopChan = make(chan struct{})
|
||||
cS.cS = cores.NewCoreService(cS.cfg, cS.caps, cS.fileCpu, cS.stopChan, cS.shdWg, cS.shdChan)
|
||||
cS.cS = cores.NewCoreService(cS.cfg, cS.caps, cS.fileCPU, cS.stopChan, cS.shdWg, cS.shdChan)
|
||||
srv, err := engine.NewServiceWithName(cS.cS, utils.CoreS, true)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user