Skip to content

Commit

Permalink
add counters for negative and error DNS responses
Browse files Browse the repository at this point in the history
  • Loading branch information
Ondřej Benkovský committed Apr 21, 2024
1 parent 4b11762 commit 42020e6
Show file tree
Hide file tree
Showing 7 changed files with 469 additions and 40 deletions.
11 changes: 1 addition & 10 deletions cmd/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"sync"
"time"

"github.com/HdrHistogram/hdrhistogram-go"
"github.com/fatih/color"
"github.com/miekg/dns"
"github.com/quic-go/quic-go/http3"
Expand Down Expand Up @@ -343,16 +342,8 @@ func (b *Benchmark) Run(ctx context.Context) ([]*ResultStats, error) {
var wg sync.WaitGroup
var w uint32
for w = 0; w < b.Concurrency; w++ {
st := &ResultStats{Hist: hdrhistogram.New(b.HistMin.Nanoseconds(), b.HistMax.Nanoseconds(), b.HistPre)}
st := newResultStats(b)
stats[w] = st
if b.Rcodes {
st.Codes = make(map[int]int64)
}
st.Qtypes = make(map[string]int64)
if b.useDoH {
st.DoHStatusCodes = make(map[int]int64)
}
st.Counters = &Counters{}

var err error
wg.Add(1)
Expand Down
17 changes: 8 additions & 9 deletions cmd/jsonreporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ type histogramPoint struct {

type jsonResult struct {
TotalRequests int64 `json:"totalRequests"`
TotalSuccessCodes int64 `json:"totalSuccessCodes"`
TotalErrors int64 `json:"totalErrors"`
TotalSuccessResponses int64 `json:"totalSuccessResponses"`
TotalNegativeResponses int64 `json:"totalNegativeResponses"`
TotalErrorResponses int64 `json:"totalErrorResponses"`
TotalIOErrors int64 `json:"totalIOErrors"`
TotalIDmismatch int64 `json:"TotalIDmismatch"`
TotalTruncatedResponses int64 `json:"totalTruncatedResponses"`
ResponseRcodes map[string]int64 `json:"responseRcodes,omitempty"`
Expand All @@ -44,11 +46,6 @@ type jsonResult struct {
}

func (s *jsonReporter) print(params reportParameters) error {
sumerrs := int64(0)
for _, v := range params.topErrs.m {
sumerrs += int64(v)
}

codeTotalsMapped := make(map[string]int64)
if params.benchmark.Rcodes {
for k, v := range params.codeTotals {
Expand Down Expand Up @@ -86,8 +83,10 @@ func (s *jsonReporter) print(params reportParameters) error {

result := jsonResult{
TotalRequests: params.totalCounters.Total,
TotalSuccessCodes: params.totalCounters.Success,
TotalErrors: sumerrs,
TotalSuccessResponses: params.totalCounters.Success,
TotalNegativeResponses: params.totalCounters.Negative,
TotalErrorResponses: params.totalCounters.Error,
TotalIOErrors: params.totalCounters.IOError,
TotalIDmismatch: params.totalCounters.IDmismatch,
TotalTruncatedResponses: params.totalCounters.Truncated,
QueriesPerSecond: math.Round(float64(params.totalCounters.Total)/params.benchmarkDuration.Seconds()*100) / 100,
Expand Down
2 changes: 2 additions & 0 deletions cmd/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ func (b *Benchmark) PrintReport(w io.Writer, stats []*ResultStats, benchStart ti
Total: totalCounters.Total + s.Counters.Total,
IOError: totalCounters.IOError + s.Counters.IOError,
Success: totalCounters.Success + s.Counters.Success,
Negative: totalCounters.Negative + s.Counters.Negative,
Error: totalCounters.Error + s.Counters.Error,
IDmismatch: totalCounters.IDmismatch + s.Counters.IDmismatch,
Truncated: totalCounters.Truncated + s.Counters.Truncated,
}
Expand Down
36 changes: 22 additions & 14 deletions cmd/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ func ExampleBenchmark_PrintReport() {
b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: Total requests: 1
// Read/Write errors: 3
// ID mismatch errors: 6
// DNS success codes: 4
// Read/Write errors: 6
// ID mismatch errors: 10
// DNS success responses: 4
// DNS negative responses: 8
// DNS error responses: 9
// Truncated responses: 7
//
// DNS response codes:
Expand Down Expand Up @@ -55,9 +57,11 @@ func ExampleBenchmark_PrintReport_dnssec() {
b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: Total requests: 1
// Read/Write errors: 3
// ID mismatch errors: 6
// DNS success codes: 4
// Read/Write errors: 6
// ID mismatch errors: 10
// DNS success responses: 4
// DNS negative responses: 8
// DNS error responses: 9
// Truncated responses: 7
//
// DNS response codes:
Expand Down Expand Up @@ -98,9 +102,11 @@ func ExampleBenchmark_PrintReport_doh() {
b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: Total requests: 1
// Read/Write errors: 3
// ID mismatch errors: 6
// DNS success codes: 4
// Read/Write errors: 6
// ID mismatch errors: 10
// DNS success responses: 4
// DNS negative responses: 8
// DNS error responses: 9
// Truncated responses: 7
//
// DNS response codes:
Expand Down Expand Up @@ -141,7 +147,7 @@ func ExampleBenchmark_PrintReport_json() {

b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: {"totalRequests":1,"totalSuccessCodes":4,"totalErrors":6,"TotalIDmismatch":6,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}]}
// Output: {"totalRequests":1,"totalSuccessResponses":4,"totalNegativeResponses":8,"totalErrorResponses":9,"totalIOErrors":6,"TotalIDmismatch":10,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}]}
}

func ExampleBenchmark_PrintReport_json_dnssec() {
Expand All @@ -154,7 +160,7 @@ func ExampleBenchmark_PrintReport_json_dnssec() {

b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: {"totalRequests":1,"totalSuccessCodes":4,"totalErrors":6,"TotalIDmismatch":6,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"totalDNSSECSecuredDomains":1}
// Output: {"totalRequests":1,"totalSuccessResponses":4,"totalNegativeResponses":8,"totalErrorResponses":9,"totalIOErrors":6,"TotalIDmismatch":10,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"totalDNSSECSecuredDomains":1}
}

func ExampleBenchmark_PrintReport_json_doh() {
Expand All @@ -168,7 +174,7 @@ func ExampleBenchmark_PrintReport_json_doh() {

b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: {"totalRequests":1,"totalSuccessCodes":4,"totalErrors":6,"TotalIDmismatch":6,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"dohHTTPResponseStatusCodes":{"200":2}}
// Output: {"totalRequests":1,"totalSuccessResponses":4,"totalNegativeResponses":8,"totalErrorResponses":9,"totalIOErrors":6,"TotalIDmismatch":10,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"dohHTTPResponseStatusCodes":{"200":2}}
}

func ExampleBenchmark_PrintReport_server_dns_errors() {
Expand Down Expand Up @@ -223,10 +229,12 @@ func testReportData() (Benchmark, ResultStats) {
Timings: []Datapoint{d1, d2},
Counters: &Counters{
Total: 1,
IOError: 3,
IOError: 6,
Success: 4,
IDmismatch: 6,
IDmismatch: 10,
Truncated: 7,
Negative: 8,
Error: 9,
},
Errors: []ErrorDatapoint{
{Start: time.Unix(0, 0), Err: errors.New("test2")},
Expand Down
44 changes: 39 additions & 5 deletions cmd/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ import (

// Counters represents various counters of benchmark results.
type Counters struct {
Total int64
IOError int64
Success int64
// Total is counter of all requests.
Total int64
// IOError is counter of all requests for which there was no answer.
IOError int64
// Success is counter of all responses which were successful (NOERROR, but not NODATA!).
Success int64
// Negative is counter of all responses which were negative (NODATA/NXDOMAIN).
Negative int64
// Error is counter of all responses which were not negative (NODATA/NXDOMAIN) or success (NOERROR response).
Error int64
// IDmismatch is counter of all responses which ID mismatched the request ID.
IDmismatch int64
Truncated int64
// Truncated is counter of all responses which had truncated flag.
Truncated int64
}

// Datapoint one datapoint of benchmark (single DNS request).
Expand Down Expand Up @@ -43,6 +52,19 @@ type ResultStats struct {
DoHStatusCodes map[int]int64
}

func newResultStats(b *Benchmark) *ResultStats {
st := &ResultStats{Hist: hdrhistogram.New(b.HistMin.Nanoseconds(), b.HistMax.Nanoseconds(), b.HistPre)}
if b.Rcodes {
st.Codes = make(map[int]int64)
}
st.Qtypes = make(map[string]int64)
if b.useDoH {
st.DoHStatusCodes = make(map[int]int64)
}
st.Counters = &Counters{}
return st
}

func (rs *ResultStats) record(req *dns.Msg, resp *dns.Msg, err error, time time.Time, duration time.Duration) {
rs.Counters.Total++

Expand Down Expand Up @@ -75,7 +97,19 @@ func (rs *ResultStats) record(req *dns.Msg, resp *dns.Msg, err error, time time.
rs.Counters.IDmismatch++
return
}
rs.Counters.Success++
if len(resp.Answer) == 0 {
// NODATA negative response
rs.Counters.Negative++
} else {
rs.Counters.Success++
}
}
if resp.Rcode == dns.RcodeNameError {
rs.Counters.Negative++
}
if resp.Rcode != dns.RcodeSuccess && resp.Rcode != dns.RcodeNameError {
// assume every rcode not NOERROR or NXDOMAIN is error
rs.Counters.Error++
}

if rs.Codes != nil {
Expand Down
Loading

0 comments on commit 42020e6

Please sign in to comment.