// createBatchPodSequential creats pods back-to-back in sequence. func createBatchPodSequential(f *framework.Framework, pods []*api.Pod) (time.Duration, []framework.PodLatencyData) { batchStartTime := unversioned.Now() e2eLags := make([]framework.PodLatencyData, 0) for _, pod := range pods { create := unversioned.Now() f.PodClient().CreateSync(pod) e2eLags = append(e2eLags, framework.PodLatencyData{Name: pod.Name, Latency: unversioned.Now().Time.Sub(create.Time)}) } batchLag := unversioned.Now().Time.Sub(batchStartTime.Time) sort.Sort(framework.LatencySlice(e2eLags)) return batchLag, e2eLags }
Expect(ok).To(Equal(true)) run, ok := runTimes[name] Expect(ok).To(Equal(true)) watch, ok := watchTimes[name] Expect(ok).To(Equal(true)) node, ok := nodes[name] Expect(ok).To(Equal(true)) scheduleLag = append(scheduleLag, framework.PodLatencyData{Name: name, Node: node, Latency: sched.Time.Sub(create.Time)}) startupLag = append(startupLag, framework.PodLatencyData{Name: name, Node: node, Latency: run.Time.Sub(sched.Time)}) watchLag = append(watchLag, framework.PodLatencyData{Name: name, Node: node, Latency: watch.Time.Sub(run.Time)}) schedToWatchLag = append(schedToWatchLag, framework.PodLatencyData{Name: name, Node: node, Latency: watch.Time.Sub(sched.Time)}) e2eLag = append(e2eLag, framework.PodLatencyData{Name: name, Node: node, Latency: watch.Time.Sub(create.Time)}) } sort.Sort(framework.LatencySlice(scheduleLag)) sort.Sort(framework.LatencySlice(startupLag)) sort.Sort(framework.LatencySlice(watchLag)) sort.Sort(framework.LatencySlice(schedToWatchLag)) sort.Sort(framework.LatencySlice(e2eLag)) framework.PrintLatencies(scheduleLag, "worst schedule latencies") framework.PrintLatencies(startupLag, "worst run-after-schedule latencies") framework.PrintLatencies(watchLag, "worst watch latencies") framework.PrintLatencies(schedToWatchLag, "worst scheduled-to-end total latencies") framework.PrintLatencies(e2eLag, "worst e2e total latencies") // Test whether e2e pod startup time is acceptable. podStartupLatency := framework.PodStartupLatency{Latency: framework.ExtractLatencyMetrics(e2eLag)} framework.ExpectNoError(framework.VerifyPodStartupLatency(podStartupLatency))
// runDensityBatchTest runs the density batch pod creation test func runDensityBatchTest(f *framework.Framework, rc *ResourceCollector, testArg densityTest, isLogTimeSeries bool) (time.Duration, []framework.PodLatencyData) { const ( podType = "density_test_pod" sleepBeforeCreatePods = 30 * time.Second ) var ( mutex = &sync.Mutex{} watchTimes = make(map[string]unversioned.Time, 0) stopCh = make(chan struct{}) ) // create test pod data structure pods := newTestPods(testArg.podsNr, ImageRegistry[pauseImage], podType) // the controller watches the change of pod status controller := newInformerWatchPod(f, mutex, watchTimes, podType) go controller.Run(stopCh) defer close(stopCh) // TODO(coufon): in the test we found kubelet starts while it is busy on something, as a result 'syncLoop' // does not response to pod creation immediately. Creating the first pod has a delay around 5s. // The node status has already been 'ready' so `wait and check node being ready does not help here. // Now wait here for a grace period to let 'syncLoop' be ready time.Sleep(sleepBeforeCreatePods) rc.Start() // Explicitly delete pods to prevent namespace controller cleanning up timeout defer deletePodsSync(f, append(pods, getCadvisorPod())) defer rc.Stop() By("Creating a batch of pods") // It returns a map['pod name']'creation time' containing the creation timestamps createTimes := createBatchPodWithRateControl(f, pods, testArg.interval) By("Waiting for all Pods to be observed by the watch...") Eventually(func() bool { return len(watchTimes) == testArg.podsNr }, 10*time.Minute, 10*time.Second).Should(BeTrue()) if len(watchTimes) < testArg.podsNr { framework.Failf("Timeout reached waiting for all Pods to be observed by the watch.") } // Analyze results var ( firstCreate unversioned.Time lastRunning unversioned.Time init = true e2eLags = make([]framework.PodLatencyData, 0) ) for name, create := range createTimes { watch, ok := watchTimes[name] Expect(ok).To(Equal(true)) e2eLags = append(e2eLags, framework.PodLatencyData{Name: name, Latency: watch.Time.Sub(create.Time)}) if !init { if firstCreate.Time.After(create.Time) { firstCreate = create } if lastRunning.Time.Before(watch.Time) { lastRunning = watch } } else { init = false firstCreate, lastRunning = create, watch } } sort.Sort(framework.LatencySlice(e2eLags)) batchLag := lastRunning.Time.Sub(firstCreate.Time) testName := testArg.getTestName() // Log time series data. if isLogTimeSeries { logDensityTimeSeries(rc, createTimes, watchTimes, testName) } // Log throughput data. logPodCreateThroughput(batchLag, e2eLags, testArg.podsNr, testName) return batchLag, e2eLags }
framework.PodLatencyData{Name: name, Latency: watch.Time.Sub(create.Time)}) if !init { if firstCreate.Time.After(create.Time) { firstCreate = create } if lastRunning.Time.Before(watch.Time) { lastRunning = watch } } else { init = false firstCreate, lastRunning = create, watch } } sort.Sort(framework.LatencySlice(e2eLags)) // verify latency By("Verifying latency") verifyLatency(lastRunning.Time.Sub(firstCreate.Time), e2eLags, itArg) // verify resource By("Verifying resource") verifyResource(f, itArg.cpuLimits, itArg.memLimits, rc) }) } }) Context("create a sequence of pods", func() { // TODO(coufon): add more tests and the values are generous, set more precise limits after benchmark dTests := []densityTest{