summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/time/sampler_test.go
diff options
context:
space:
mode:
authorGoogler <noreply@google.com>2018-04-27 10:37:02 -0700
committerAdin Scannell <ascannell@google.com>2018-04-28 01:44:26 -0400
commitd02b74a5dcfed4bfc8f2f8e545bca4d2afabb296 (patch)
tree54f95eef73aee6bacbfc736fffc631be2605ed53 /pkg/sentry/time/sampler_test.go
parentf70210e742919f40aa2f0934a22f1c9ba6dada62 (diff)
Check in gVisor.
PiperOrigin-RevId: 194583126 Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463
Diffstat (limited to 'pkg/sentry/time/sampler_test.go')
-rw-r--r--pkg/sentry/time/sampler_test.go183
1 files changed, 183 insertions, 0 deletions
diff --git a/pkg/sentry/time/sampler_test.go b/pkg/sentry/time/sampler_test.go
new file mode 100644
index 000000000..caf7e5c53
--- /dev/null
+++ b/pkg/sentry/time/sampler_test.go
@@ -0,0 +1,183 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package time
+
+import (
+ "errors"
+ "testing"
+)
+
+// errNoSamples is returned when testReferenceClocks runs out of samples.
+var errNoSamples = errors.New("no samples available")
+
+// testReferenceClocks returns a preset list of samples and cycle counts.
+type testReferenceClocks struct {
+ samples []sample
+ cycles []TSCValue
+}
+
+// Sample implements referenceClocks.Sample, returning the next sample in the list.
+func (t *testReferenceClocks) Sample(_ ClockID) (sample, error) {
+ if len(t.samples) == 0 {
+ return sample{}, errNoSamples
+ }
+
+ s := t.samples[0]
+ if len(t.samples) == 1 {
+ t.samples = nil
+ } else {
+ t.samples = t.samples[1:]
+ }
+
+ return s, nil
+}
+
+// Cycles implements referenceClocks.Cycles, returning the next TSCValue in the list.
+func (t *testReferenceClocks) Cycles() TSCValue {
+ if len(t.cycles) == 0 {
+ return 0
+ }
+
+ c := t.cycles[0]
+ if len(t.cycles) == 1 {
+ t.cycles = nil
+ } else {
+ t.cycles = t.cycles[1:]
+ }
+
+ return c
+}
+
+// newTestSampler returns a sampler that collects samples from
+// the given sample list and cycle counts from the given cycle list.
+func newTestSampler(samples []sample, cycles []TSCValue) *sampler {
+ return &sampler{
+ clocks: &testReferenceClocks{
+ samples: samples,
+ cycles: cycles,
+ },
+ overhead: defaultOverheadCycles,
+ }
+}
+
+// generateSamples generates n samples with the given overhead.
+func generateSamples(n int, overhead TSCValue) []sample {
+ samples := []sample{{before: 1000000, after: 1000000 + overhead, ref: 100}}
+ for i := 0; i < n-1; i++ {
+ prev := samples[len(samples)-1]
+ samples = append(samples, sample{
+ before: prev.before + 1000000,
+ after: prev.after + 1000000,
+ ref: prev.ref + 100,
+ })
+ }
+ return samples
+}
+
+// TestSample ensures that samples can be collected.
+func TestSample(t *testing.T) {
+ testCases := []struct {
+ name string
+ samples []sample
+ err error
+ }{
+ {
+ name: "basic",
+ samples: []sample{
+ {before: 100000, after: 100000 + defaultOverheadCycles, ref: 100},
+ },
+ err: nil,
+ },
+ {
+ // Sample with backwards TSC ignored.
+ // referenceClock should retry and get errNoSamples.
+ name: "backwards-tsc-ignored",
+ samples: []sample{
+ {before: 100000, after: 90000, ref: 100},
+ },
+ err: errNoSamples,
+ },
+ {
+ // Sample far above overhead skipped.
+ // referenceClock should retry and get errNoSamples.
+ name: "reject-overhead",
+ samples: []sample{
+ {before: 100000, after: 100000 + 5*defaultOverheadCycles, ref: 100},
+ },
+ err: errNoSamples,
+ },
+ {
+ // Maximum overhead allowed is bounded.
+ name: "over-max-overhead",
+ // Generate a bunch of samples. The reference clock
+ // needs a while to ramp up its expected overhead.
+ samples: generateSamples(100, 2*maxOverheadCycles),
+ err: errOverheadTooHigh,
+ },
+ {
+ // Overhead at maximum overhead is allowed.
+ name: "max-overhead",
+ // Generate a bunch of samples. The reference clock
+ // needs a while to ramp up its expected overhead.
+ samples: generateSamples(100, maxOverheadCycles),
+ err: nil,
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ s := newTestSampler(tc.samples, nil)
+ err := s.Sample()
+ if err != tc.err {
+ t.Errorf("Sample err got %v want %v", err, tc.err)
+ }
+ })
+ }
+}
+
+// TestOutliersIgnored tests that referenceClock ignores samples with very high
+// overhead.
+func TestOutliersIgnored(t *testing.T) {
+ s := newTestSampler([]sample{
+ {before: 100000, after: 100000 + defaultOverheadCycles, ref: 100},
+ {before: 200000, after: 200000 + defaultOverheadCycles, ref: 200},
+ {before: 300000, after: 300000 + defaultOverheadCycles, ref: 300},
+ {before: 400000, after: 400000 + defaultOverheadCycles, ref: 400},
+ {before: 500000, after: 500000 + 5*defaultOverheadCycles, ref: 500}, // Ignored
+ {before: 600000, after: 600000 + defaultOverheadCycles, ref: 600},
+ {before: 700000, after: 700000 + defaultOverheadCycles, ref: 700},
+ }, nil)
+
+ // Collect 5 samples.
+ for i := 0; i < 5; i++ {
+ err := s.Sample()
+ if err != nil {
+ t.Fatalf("Unexpected error while sampling: %v", err)
+ }
+ }
+
+ oldest, newest, ok := s.Range()
+ if !ok {
+ t.Fatalf("Range not ok")
+ }
+
+ if oldest.ref != 100 {
+ t.Errorf("oldest.ref got %v want %v", oldest.ref, 100)
+ }
+
+ // We skipped the high-overhead sample.
+ if newest.ref != 600 {
+ t.Errorf("newest.ref got %v want %v", newest.ref, 600)
+ }
+}