//go:build benchmark // +build benchmark /* Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments Copyright (C) ITsysCOM GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see */ package sessions import ( "flag" "fmt" "log" "path" "sync" "testing" "time" "github.com/cgrates/birpc" "github.com/cgrates/birpc/context" "github.com/cgrates/birpc/jsonrpc" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" ) var ( sBenchCfg *config.CGRConfig sBenchRPC *birpc.Client connOnce sync.Once initRuns = flag.Int("runs", 25000, "number of loops to run in init") cps = flag.Int("cps", 2000, "number of loops to run in init") maxCps = make(chan struct{}, *cps) ) func startRPC() { var err error sBenchCfg, err = config.NewCGRConfigFromPath( path.Join(*utils.DataDir, "conf", "samples", "tutmongo")) if err != nil { log.Fatal(err) } if sBenchRPC, err = jsonrpc.Dial(utils.TCP, sBenchCfg.ListenCfg().RPCJSONListen); err != nil { log.Fatalf("Error at dialing rcp client:%v\n", err) } } func loadTP() { for i := 0; i < *cps; i++ { // init CPS limitation maxCps <- struct{}{} } if err := engine.InitDataDB(sBenchCfg); err != nil { log.Fatal(err) } attrs := &utils.AttrLoadTpFromFolder{ FolderPath: path.Join(*utils.DataDir, "tariffplans", "tutorial")} var tpLoadInst utils.LoadInstance if err := sBenchRPC.Call(context.Background(), utils.APIerSv2LoadTariffPlanFromFolder, attrs, &tpLoadInst); err != nil { log.Fatal(err) } time.Sleep(100 * time.Millisecond) // Give time for scheduler to execute topups } func addBalance(sBenchRPC *birpc.Client, sraccount string) { attrSetBalance := utils.AttrSetBalance{ Tenant: "cgrates.org", Account: sraccount, BalanceType: utils.MetaVoice, Value: 5 * float64(time.Hour), Balance: map[string]any{ utils.ID: "TestDynamicDebitBalance", }, } var reply string if err := sBenchRPC.Call(context.Background(), utils.APIerSv2SetBalance, attrSetBalance, &reply); err != nil { log.Fatal(err) } } func addAccouns() { var wg sync.WaitGroup for i := 0; i < *initRuns; i++ { wg.Add(1) go func(i int) { oneCps := <-maxCps // queue here for maxCps defer func() { maxCps <- oneCps }() addBalance(sBenchRPC, fmt.Sprintf("1001%v", i)) wg.Done() }(i) } wg.Wait() } func initSession(i int) { oneCps := <-maxCps // queue here for maxCps defer func() { maxCps <- oneCps }() initArgs := &V1InitSessionArgs{ InitSession: true, CGREvent: &utils.CGREvent{ Tenant: "cgrates.org", ID: "", Event: map[string]any{ utils.EventName: "TEST_EVENT", utils.ToR: utils.MetaVoice, utils.Category: "call", utils.Tenant: "cgrates.org", utils.RequestType: utils.MetaPrepaid, utils.AnswerTime: time.Date(2016, time.January, 5, 18, 31, 05, 0, time.UTC), }, }, } initArgs.ID = utils.UUIDSha1Prefix() initArgs.Event[utils.OriginID] = utils.UUIDSha1Prefix() initArgs.Event[utils.AccountField] = fmt.Sprintf("1001%v", i) initArgs.Event[utils.Subject] = "1001" //initArgs.Event[utils.AccountField] initArgs.Event[utils.Destination] = fmt.Sprintf("1002%v", i) var initRpl *V1InitSessionReply if err := sBenchRPC.Call(context.Background(), utils.SessionSv1InitiateSession, initArgs, &initRpl); err != nil { // log.Fatal(err) } } func sendInitx10(r int) { var wg sync.WaitGroup for i := r; i < r+10; i++ { wg.Add(1) go func(i int) { initSession(i) wg.Done() }(i) } wg.Wait() } func sendInit() { var wg sync.WaitGroup for i := 0; i < *initRuns; i++ { wg.Add(1) go func(i int) { initSession(i) wg.Done() }(i) } wg.Wait() } func getCount() int { var count int if err := sBenchRPC.Call(context.Background(), utils.SessionSv1GetActiveSessionsCount, utils.SessionFilter{ Filters: []string{"*string:~*req.ToR:*voice"}, }, &count); err != nil { log.Fatal(err) } return count } func BenchmarkSendInitSession(b *testing.B) { connOnce.Do(func() { startRPC() loadTP() addAccouns() sendInit() // time.Sleep(3 * time.Minute) }) b.ResetTimer() for i := 0; i < b.N; i++ { _ = getCount() } } func BenchmarkEncodingJSON(b *testing.B) { maxCps = make(chan struct{}, *cps) for i := 0; i < *cps; i++ { // init CPS limitation maxCps <- struct{}{} } var err error sBenchCfg, err = config.NewCGRConfigFromPath( path.Join(*utils.DataDir, "conf", "samples", "tutmongo")) if err != nil { log.Fatal(err) } if sBenchRPC, err = jsonrpc.Dial(utils.TCP, sBenchCfg.ListenCfg().RPCJSONListen); err != nil { log.Fatalf("Error at dialing rcp client:%v\n", err) } b.ResetTimer() for i := 0; i < b.N; i++ { initSession(i) } } func BenchmarkEncodingGOB(b *testing.B) { maxCps = make(chan struct{}, *cps) for i := 0; i < *cps; i++ { // init CPS limitation maxCps <- struct{}{} } var err error sBenchCfg, err = config.NewCGRConfigFromPath( path.Join(*utils.DataDir, "conf", "samples", "tutmongo")) if err != nil { log.Fatal(err) } if sBenchRPC, err = birpc.Dial(utils.TCP, sBenchCfg.ListenCfg().RPCGOBListen); err != nil { log.Fatalf("Error at dialing rcp client:%v\n", err) } b.ResetTimer() for i := 0; i < b.N; i++ { initSession(i) } } func benchmarkSendInitSessionx10(b *testing.B) { connOnce.Do(func() { startRPC() loadTP() addAccouns() // time.Sleep(3 * time.Minute) }) b.ResetTimer() for i := 0; i < *initRuns/10; i++ { sendInitx10(i * 10) tStart := time.Now() _ = getCount() if tDur := time.Now().Sub(tStart); tDur > 100*time.Millisecond && tDur < time.Second { fmt.Printf("Expected answer in less than %v receved answer after %v for %v sessions\n", 100*time.Millisecond, tDur, i*10+10) } else if tDur >= time.Second { b.Fatalf("Fatal:Expected answer in less than %v receved answer after %v for %v sessions", time.Second, tDur, i*10+10) } } }