in perf-tools/scenarios/node_fairness.go [69:214]
func (nfs *NodeFairnessScenario) Run(results *utils.Results) {
scenarioResults := results.CreateScenarioResults(nfs.GetName())
maxWaitTime := time.Duration(nfs.commonConf.MaxWaitSeconds) * time.Second
var appManager framework.AppManager
var appInfo *framework.AppInfo
// make sure app is cleaned up when error occurred
defer func() {
CleanupApp(appManager, appInfo, maxWaitTime)
}()
// init node analyzer and calculate allocated resource for nodes
nodeAnalyzer := framework.NewNodeAnalyzer(nfs.kubeClient, nfs.commonConf.NodeSelector)
err := nodeAnalyzer.InitNodeInfosBeforeTesting()
if err != nil {
utils.Logger.Error("failed to init nodes", zap.Error(err))
scenarioResults.AddVerification("init nodes", err.Error(), utils.FAILED)
return
}
utils.Logger.Info("[Prepare] init nodes", zap.Int("numNodes", len(nodeAnalyzer.GetAllocatableNodes())))
nodeAnalyzer.CalculateAllocatedResource()
for caseIndex, testCase := range nfs.scenarioConf.Cases {
verGroupName := fmt.Sprintf("Case-%d", caseIndex)
verGroupDescription := fmt.Sprintf("%+v", testCase)
caseVerification := scenarioResults.AddVerificationGroup(verGroupName, verGroupDescription)
utils.Logger.Info("add verification group", zap.String("name", verGroupName),
zap.String("description", verGroupDescription))
nodeAnalyzer.ClearApps()
totalAllocatableResource := nodeAnalyzer.GetTotalAllocatableResource()
var resourceUnit string
ykResourceName := testCase.ResourceName
if testCase.ResourceName == v1.ResourceMemory.String() {
resourceUnit = "Mi"
} else if testCase.ResourceName == v1.ResourceCPU.String() {
resourceUnit = "m"
ykResourceName = resources.VCORE
}
totalAllocatableResourceValue, ok := totalAllocatableResource.Resources[ykResourceName]
if !ok {
caseVerification.AddSubVerification("Unknown resource name",
fmt.Sprintf("resourceName=%s, totalAllocatableResource=%v",
ykResourceName, totalAllocatableResource), utils.FAILED)
return
}
// init expected number of pods
allocatableNodes := nodeAnalyzer.GetAllocatableNodes()
expectedNumPods := testCase.NumPodsPerNode * len(allocatableNodes)
expectedPodResource := int64(totalAllocatableResourceValue) * int64(testCase.AllocatePercentage) /
int64(expectedNumPods*100)
requestResources := make(map[string]string)
requestResources[testCase.ResourceName] = fmt.Sprintf("%d"+resourceUnit, expectedPodResource)
utils.Logger.Info("start testing",
zap.Int("numAllocatableNodes", len(allocatableNodes)),
zap.Int("expectedNumPods", expectedNumPods),
zap.Any("requestResources", requestResources))
// init app info & app manager
requestInfo := framework.NewRequestInfo(int32(expectedNumPods), "", requestResources, nil)
appInfo = framework.NewAppInfo(nfs.commonConf.Namespace, NodeFairnessScenarioName, nfs.commonConf.Queue,
[]*framework.RequestInfo{requestInfo}, nfs.commonConf.PodTemplateSpec, nfs.commonConf.PodSpec)
appManager = framework.NewDeploymentsAppManager(nfs.kubeClient)
appAnalyzer := framework.NewAppAnalyzer(appInfo)
// test for different schedulers
for _, schedulerName := range nfs.scenarioConf.SchedulerNames {
utils.Logger.Info("start testing for scheduler " + schedulerName)
schedulerVerification := caseVerification.AddSubVerificationGroup(
fmt.Sprintf("test for %s", schedulerName), verGroupDescription)
// prepare nodes
nodeAnalyzer.ClearApps()
utils.Logger.Info("[Prepare] init nodes", zap.Int("numNodes", len(nodeAnalyzer.GetAllocatableNodes())))
// create app and wait for it to be running
utils.Logger.Info("create an app and wait for it to be running, refresh tasks status at last",
zap.String("appID", appInfo.AppID))
beginTime := time.Now().Truncate(time.Second)
err = appManager.CreateWaitAndRefreshTasksStatus(schedulerName, appInfo, maxWaitTime)
if err != nil {
utils.Logger.Error("failed to create/wait/refresh app", zap.Error(err))
schedulerVerification.AddSubVerification("test app", err.Error(), utils.FAILED)
return
}
utils.Logger.Info("all requirements of this app are satisfied", zap.String("appID", appInfo.AppID),
zap.Duration("elapseTime", time.Since(beginTime)))
// analyze
nodeDistribution := nodeAnalyzer.GetNodeResourceDistribution(
appAnalyzer.GetTasksDistribution(framework.PodScheduled), ykResourceName)
table := parseTableFromNodeDistribution(nodeDistribution)
tableFilePath := fmt.Sprintf("%s/%s-case%d-node-distribution.txt",
nfs.commonConf.OutputPath, nfs.GetName(), caseIndex)
tableOutputName := "output node distribution timeline table"
utils.Logger.Info(tableOutputName)
table.Print()
if err := table.Output(tableFilePath); err != nil {
schedulerVerification.AddSubVerification(tableOutputName,
fmt.Sprintf("failed to output node distribution timeline table: %s", err.Error()),
utils.FAILED)
return
}
schedulerVerification.AddSubVerification(tableOutputName, tableFilePath, utils.SUCCEEDED)
// prepare line points
var linePoints []interface{}
for i, v := range nodeDistribution {
typeName := "bucket-" + strconv.Itoa(i)
linePoints = append(linePoints, typeName, utils.GetPointsFromSlice(v))
}
// draw chart
chartFileName := fmt.Sprintf("%s-case%d-%s-%d-%d", nfs.GetName(), caseIndex, schedulerName,
testCase.NumPodsPerNode, testCase.AllocatePercentage)
chart := &utils.Chart{
Title: "Node Fairness",
XLabel: "Seconds",
YLabel: "Number of Nodes",
Width: constants.ChartWidth,
Height: constants.ChartHeight,
LinePoints: linePoints,
SvgFile: nfs.commonConf.OutputPath + "/" + chartFileName + constants.ChartFileSuffix,
}
err = utils.DrawChart(chart)
outputName := "output node distribution timeline chart"
if err != nil {
schedulerVerification.AddSubVerification(outputName,
fmt.Sprintf("failed to draw chart: %s", err.Error()),
utils.FAILED)
return
}
schedulerVerification.AddSubVerification(outputName, chart.SvgFile, utils.SUCCEEDED)
// delete this app and wait for it to be cleaned up
utils.Logger.Info("delete this app then wait for it to be cleaned up",
zap.String("appID", appInfo.AppID))
err = appManager.DeleteWait(appInfo, maxWaitTime)
if err != nil {
utils.Logger.Error("failed to delete/wait app", zap.Error(err))
schedulerVerification.AddSubVerification("cleanup app", err.Error(), utils.FAILED)
return
}
}
}
}