summaryrefslogtreecommitdiff
path: root/rpm/calculations.go
blob: 5387aa7bdb7ca93bfebbce346f6aa7d2a0848687 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * This file is part of Go Responsiveness.
 *
 * Go Responsiveness is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software Foundation,
 * either version 2 of the License, or (at your option) any later version.
 * Go Responsiveness 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with Go Responsiveness. If not, see <https://www.gnu.org/licenses/>.
 */

package rpm

import (
	"fmt"

	"github.com/network-quality/goresponsiveness/ms"
)

type Rpm struct {
	SelfRttsTotal       int
	ForeignRttsTotal    int
	SelfRttsTrimmed     int
	ForeignRttsTrimmed  int
	SelfProbeRttPN      float64
	ForeignProbeRttPN   float64
	SelfProbeRttMean    float64
	ForeignProbeRttMean float64
	PNRpm               float64
	MeanRpm             float64
}

func CalculateRpm(selfRtts ms.MathematicalSeries[float64], foreignRtts ms.MathematicalSeries[float64], trimming uint, percentile int) Rpm {
	// First, let's do a double-sided trim of the top/bottom 10% of our measurements.
	selfRttsTotalCount := selfRtts.Len()
	foreignRttsTotalCount := foreignRtts.Len()

	selfRttsTrimmed := selfRtts.DoubleSidedTrim(trimming)
	foreignRttsTrimmed := foreignRtts.DoubleSidedTrim(trimming)

	selfRttsTrimmedCount := selfRttsTrimmed.Len()
	foreignRttsTrimmedCount := foreignRttsTrimmed.Len()

	// Then, let's take the mean of those ...
	selfProbeRoundTripTimeMean := selfRttsTrimmed.CalculateAverage()
	foreignProbeRoundTripTimeMean := foreignRttsTrimmed.CalculateAverage()

	// Second, let's do the P90 calculations.
	selfProbeRoundTripTimePN := selfRtts.Percentile(percentile)
	foreignProbeRoundTripTimePN := foreignRtts.Percentile(percentile)

	// Note: The specification indicates that we want to calculate the foreign probes as such:
	// 1/3*tcp_foreign + 1/3*tls_foreign + 1/3*http_foreign
	// where tcp_foreign, tls_foreign, http_foreign are the P90 RTTs for the connection
	// of the tcp, tls and http connections, respectively. However, we cannot break out
	// the individual RTTs so we assume that they are roughly equal.

	// This is 60 because we measure in seconds not ms
	pnRpm := 60.0 / (float64(selfProbeRoundTripTimePN+foreignProbeRoundTripTimePN) / 2.0)
	meanRpm := 60.0 / (float64(selfProbeRoundTripTimeMean+foreignProbeRoundTripTimeMean) / 2.0)

	return Rpm{
		SelfRttsTotal: selfRttsTotalCount, ForeignRttsTotal: foreignRttsTotalCount,
		SelfRttsTrimmed: selfRttsTrimmedCount, ForeignRttsTrimmed: foreignRttsTrimmedCount,
		SelfProbeRttPN: selfProbeRoundTripTimePN, ForeignProbeRttPN: foreignProbeRoundTripTimePN,
		SelfProbeRttMean: selfProbeRoundTripTimeMean, ForeignProbeRttMean: foreignProbeRoundTripTimeMean,
		PNRpm: pnRpm, MeanRpm: meanRpm,
	}
}

func (rpm *Rpm) ToString() string {
	return fmt.Sprintf(
		`Total Self Probes:            %d
Total Foreign Probes:         %d
Trimmed Self Probes Count:    %d
Trimmed Foreign Probes Count: %d
P90 Self RTT:                 %f
P90 Foreign RTT:              %f
Trimmed Mean Self RTT:        %f
Trimmed Mean Foreign RTT:     %f
`,
		rpm.SelfRttsTotal,
		rpm.ForeignRttsTotal,
		rpm.SelfRttsTrimmed,
		rpm.ForeignRttsTrimmed,
		rpm.SelfProbeRttPN,
		rpm.ForeignProbeRttPN,
		rpm.SelfProbeRttMean,
		rpm.ForeignProbeRttMean,
	)
}