mirror of
https://github.com/httprunner/httprunner.git
synced 2026-06-09 09:49:33 +08:00
fix: improve RPS accuracy
This commit is contained in:
@@ -99,6 +99,9 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rend
|
|||||||
parametersIterator := caseRunner.parametersIterator
|
parametersIterator := caseRunner.parametersIterator
|
||||||
parametersIterator.SetUnlimitedMode()
|
parametersIterator.SetUnlimitedMode()
|
||||||
|
|
||||||
|
// reset start time only once
|
||||||
|
once := sync.Once{}
|
||||||
|
|
||||||
return &boomer.Task{
|
return &boomer.Task{
|
||||||
Name: testcase.Config.Name,
|
Name: testcase.Config.Name,
|
||||||
Weight: testcase.Config.Weight,
|
Weight: testcase.Config.Weight,
|
||||||
@@ -115,6 +118,10 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rend
|
|||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
for _, step := range testcase.TestSteps {
|
for _, step := range testcase.TestSteps {
|
||||||
|
// reset start time only once before step
|
||||||
|
once.Do(func() {
|
||||||
|
b.Boomer.ResetStartTime()
|
||||||
|
})
|
||||||
stepResult, err := step.Run(sessionRunner)
|
stepResult, err := step.Run(sessionRunner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// step failed
|
// step failed
|
||||||
|
|||||||
@@ -170,3 +170,7 @@ func (b *Boomer) GetSpawnDoneChan() chan struct{} {
|
|||||||
func (b *Boomer) GetSpawnCount() int {
|
func (b *Boomer) GetSpawnCount() int {
|
||||||
return b.localRunner.spawnCount
|
return b.localRunner.spawnCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Boomer) ResetStartTime() {
|
||||||
|
b.localRunner.stats.total.resetStartTime()
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/push"
|
"github.com/prometheus/client_golang/prometheus/push"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@@ -264,10 +265,9 @@ func deserializeStatsEntry(stat interface{}) (entryOutput *statsEntryOutput, err
|
|||||||
|
|
||||||
var duration float64
|
var duration float64
|
||||||
if entry.Name == "Total" {
|
if entry.Name == "Total" {
|
||||||
duration = float64(entry.LastRequestTimestamp - entry.StartTime)
|
duration = float64(entry.LastRequestTimestamp-entry.StartTime) / 1e3
|
||||||
// fix: avoid divide by zero
|
if duration == 0 {
|
||||||
if duration < 1 {
|
return nil, errors.New("no step specified")
|
||||||
duration = 1
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
duration = float64(reportStatsInterval / time.Second)
|
duration = float64(reportStatsInterval / time.Second)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -154,7 +153,7 @@ func (r *runner) reportTestResult() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
duration := time.Duration(entryTotalOutput.LastRequestTimestamp-entryTotalOutput.StartTime) * time.Second
|
duration := time.Duration(entryTotalOutput.LastRequestTimestamp-entryTotalOutput.StartTime) * time.Millisecond
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
println(fmt.Sprint("=========================================== Statistics Summary =========================================="))
|
println(fmt.Sprint("=========================================== Statistics Summary =========================================="))
|
||||||
println(fmt.Sprintf("Current time: %s, Users: %v, Duration: %v, Accumulated Transactions: %d Passed, %d Failed",
|
println(fmt.Sprintf("Current time: %s, Users: %v, Duration: %v, Accumulated Transactions: %d Passed, %d Failed",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package boomer
|
package boomer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/hrp/internal/json"
|
"github.com/httprunner/httprunner/hrp/internal/json"
|
||||||
@@ -101,8 +102,6 @@ func (s *requestStats) get(name string, method string) (entry *statsEntry) {
|
|||||||
newEntry := &statsEntry{
|
newEntry := &statsEntry{
|
||||||
Name: name,
|
Name: name,
|
||||||
Method: method,
|
Method: method,
|
||||||
NumReqsPerSec: make(map[int64]int64),
|
|
||||||
NumFailPerSec: make(map[int64]int64),
|
|
||||||
ResponseTimes: make(map[int64]int64),
|
ResponseTimes: make(map[int64]int64),
|
||||||
}
|
}
|
||||||
s.entries[name+method] = newEntry
|
s.entries[name+method] = newEntry
|
||||||
@@ -171,10 +170,6 @@ type statsEntry struct {
|
|||||||
MinResponseTime int64 `json:"min_response_time"`
|
MinResponseTime int64 `json:"min_response_time"`
|
||||||
// Maximum response time
|
// Maximum response time
|
||||||
MaxResponseTime int64 `json:"max_response_time"`
|
MaxResponseTime int64 `json:"max_response_time"`
|
||||||
// A {second => request_count} dict that holds the number of requests made per second
|
|
||||||
NumReqsPerSec map[int64]int64 `json:"num_reqs_per_sec"`
|
|
||||||
// A (second => failure_count) dict that hold the number of failures per second
|
|
||||||
NumFailPerSec map[int64]int64 `json:"num_fail_per_sec"`
|
|
||||||
// A {response_time => count} dict that holds the response time distribution of all the requests
|
// A {response_time => count} dict that holds the response time distribution of all the requests
|
||||||
// The keys (the response time in ms) are rounded to store 1, 2, ... 9, 10, 20. .. 90,
|
// The keys (the response time in ms) are rounded to store 1, 2, ... 9, 10, 20. .. 90,
|
||||||
// 100, 200 .. 900, 1000, 2000 ... 9000, in order to save memory.
|
// 100, 200 .. 900, 1000, 2000 ... 9000, in order to save memory.
|
||||||
@@ -191,17 +186,19 @@ type statsEntry struct {
|
|||||||
NumNoneRequests int64 `json:"num_none_requests"`
|
NumNoneRequests int64 `json:"num_none_requests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *statsEntry) resetStartTime() {
|
||||||
|
atomic.StoreInt64(&s.StartTime, time.Duration(time.Now().UnixNano()).Milliseconds())
|
||||||
|
}
|
||||||
|
|
||||||
func (s *statsEntry) reset() {
|
func (s *statsEntry) reset() {
|
||||||
s.StartTime = time.Now().Unix()
|
atomic.StoreInt64(&s.StartTime, time.Duration(time.Now().UnixNano()).Milliseconds())
|
||||||
s.NumRequests = 0
|
s.NumRequests = 0
|
||||||
s.NumFailures = 0
|
s.NumFailures = 0
|
||||||
s.TotalResponseTime = 0
|
s.TotalResponseTime = 0
|
||||||
s.ResponseTimes = make(map[int64]int64)
|
s.ResponseTimes = make(map[int64]int64)
|
||||||
s.MinResponseTime = 0
|
s.MinResponseTime = 0
|
||||||
s.MaxResponseTime = 0
|
s.MaxResponseTime = 0
|
||||||
s.LastRequestTimestamp = time.Now().Unix()
|
s.LastRequestTimestamp = time.Duration(time.Now().UnixNano()).Milliseconds()
|
||||||
s.NumReqsPerSec = make(map[int64]int64)
|
|
||||||
s.NumFailPerSec = make(map[int64]int64)
|
|
||||||
s.TotalContentLength = 0
|
s.TotalContentLength = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,15 +212,7 @@ func (s *statsEntry) log(responseTime int64, contentLength int64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *statsEntry) logTimeOfRequest() {
|
func (s *statsEntry) logTimeOfRequest() {
|
||||||
key := time.Now().Unix()
|
s.LastRequestTimestamp = time.Duration(time.Now().UnixNano()).Milliseconds()
|
||||||
_, ok := s.NumReqsPerSec[key]
|
|
||||||
if !ok {
|
|
||||||
s.NumReqsPerSec[key] = 1
|
|
||||||
} else {
|
|
||||||
s.NumReqsPerSec[key]++
|
|
||||||
}
|
|
||||||
|
|
||||||
s.LastRequestTimestamp = key
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *statsEntry) logResponseTime(responseTime int64) {
|
func (s *statsEntry) logResponseTime(responseTime int64) {
|
||||||
@@ -267,13 +256,6 @@ func (s *statsEntry) logResponseTime(responseTime int64) {
|
|||||||
|
|
||||||
func (s *statsEntry) logFailures() {
|
func (s *statsEntry) logFailures() {
|
||||||
s.NumFailures++
|
s.NumFailures++
|
||||||
key := time.Now().Unix()
|
|
||||||
_, ok := s.NumFailPerSec[key]
|
|
||||||
if !ok {
|
|
||||||
s.NumFailPerSec[key] = 1
|
|
||||||
} else {
|
|
||||||
s.NumFailPerSec[key]++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *statsEntry) serialize() map[string]interface{} {
|
func (s *statsEntry) serialize() map[string]interface{} {
|
||||||
|
|||||||
Reference in New Issue
Block a user