mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 19:23:40 +00:00
Merge pull request #124578 from sanposhiho/scheduler_perf_scheduler_plugin_execution_duration_seconds
support `scheduler_plugin_execution_duration_seconds` in scheduler_perf
This commit is contained in:
commit
ade0d2140a
@ -38,7 +38,24 @@ const (
|
|||||||
Binding = "binding"
|
Binding = "binding"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Below are possible values for the extension_point label.
|
// ExtentionPoints is a list of possible values for the extension_point label.
|
||||||
|
var ExtentionPoints = []string{
|
||||||
|
PreFilter,
|
||||||
|
Filter,
|
||||||
|
PreFilterExtensionAddPod,
|
||||||
|
PreFilterExtensionRemovePod,
|
||||||
|
PostFilter,
|
||||||
|
PreScore,
|
||||||
|
Score,
|
||||||
|
ScoreExtensionNormalize,
|
||||||
|
PreBind,
|
||||||
|
Bind,
|
||||||
|
PostBind,
|
||||||
|
Reserve,
|
||||||
|
Unreserve,
|
||||||
|
Permit,
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PreFilter = "PreFilter"
|
PreFilter = "PreFilter"
|
||||||
Filter = "Filter"
|
Filter = "Filter"
|
||||||
|
@ -53,6 +53,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/metrics"
|
"k8s.io/kubernetes/pkg/scheduler/metrics"
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
@ -90,23 +91,65 @@ const (
|
|||||||
configFile = "config/performance-config.yaml"
|
configFile = "config/performance-config.yaml"
|
||||||
extensionPointsLabelName = "extension_point"
|
extensionPointsLabelName = "extension_point"
|
||||||
resultLabelName = "result"
|
resultLabelName = "result"
|
||||||
|
pluginLabelName = "plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultMetricsCollectorConfig = metricsCollectorConfig{
|
defaultMetricsCollectorConfig = metricsCollectorConfig{
|
||||||
Metrics: map[string]*labelValues{
|
Metrics: map[string][]*labelValues{
|
||||||
"scheduler_framework_extension_point_duration_seconds": {
|
"scheduler_framework_extension_point_duration_seconds": {
|
||||||
label: extensionPointsLabelName,
|
{
|
||||||
values: []string{"Filter", "Score"},
|
label: extensionPointsLabelName,
|
||||||
|
values: metrics.ExtentionPoints,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"scheduler_scheduling_attempt_duration_seconds": {
|
"scheduler_scheduling_attempt_duration_seconds": {
|
||||||
label: resultLabelName,
|
{
|
||||||
values: []string{metrics.ScheduledResult, metrics.UnschedulableResult, metrics.ErrorResult},
|
label: resultLabelName,
|
||||||
|
values: []string{metrics.ScheduledResult, metrics.UnschedulableResult, metrics.ErrorResult},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"scheduler_pod_scheduling_duration_seconds": nil,
|
||||||
|
"scheduler_plugin_execution_duration_seconds": {
|
||||||
|
{
|
||||||
|
label: pluginLabelName,
|
||||||
|
values: PluginNames,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: extensionPointsLabelName,
|
||||||
|
values: metrics.ExtentionPoints,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"scheduler_pod_scheduling_duration_seconds": nil,
|
|
||||||
"scheduler_pod_scheduling_sli_duration_seconds": nil,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PluginNames is the names of the plugins that scheduler_perf collects metrics for.
|
||||||
|
// We export this variable because people outside k/k may want to put their custom plugins.
|
||||||
|
PluginNames = []string{
|
||||||
|
names.PrioritySort,
|
||||||
|
names.DefaultBinder,
|
||||||
|
names.DefaultPreemption,
|
||||||
|
names.DynamicResources,
|
||||||
|
names.ImageLocality,
|
||||||
|
names.InterPodAffinity,
|
||||||
|
names.NodeAffinity,
|
||||||
|
names.NodeName,
|
||||||
|
names.NodePorts,
|
||||||
|
names.NodeResourcesBalancedAllocation,
|
||||||
|
names.NodeResourcesFit,
|
||||||
|
names.NodeUnschedulable,
|
||||||
|
names.NodeVolumeLimits,
|
||||||
|
names.AzureDiskLimits,
|
||||||
|
names.CinderLimits,
|
||||||
|
names.EBSLimits,
|
||||||
|
names.GCEPDLimits,
|
||||||
|
names.PodTopologySpread,
|
||||||
|
names.SchedulingGates,
|
||||||
|
names.TaintToleration,
|
||||||
|
names.VolumeBinding,
|
||||||
|
names.VolumeRestrictions,
|
||||||
|
names.VolumeZone,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// testCase defines a set of test cases that intends to test the performance of
|
// testCase defines a set of test cases that intends to test the performance of
|
||||||
@ -668,7 +711,9 @@ func withCleanup(tCtx ktesting.TContext, enabled bool) ktesting.TContext {
|
|||||||
var perfSchedulingLabelFilter = flag.String("perf-scheduling-label-filter", "performance", "comma-separated list of labels which a testcase must have (no prefix or +) or must not have (-), used by BenchmarkPerfScheduling")
|
var perfSchedulingLabelFilter = flag.String("perf-scheduling-label-filter", "performance", "comma-separated list of labels which a testcase must have (no prefix or +) or must not have (-), used by BenchmarkPerfScheduling")
|
||||||
|
|
||||||
// RunBenchmarkPerfScheduling runs the scheduler performance tests.
|
// RunBenchmarkPerfScheduling runs the scheduler performance tests.
|
||||||
// Optionally, you can pass your own scheduler plugin via outOfTreePluginRegistry.
|
//
|
||||||
|
// You can pass your own scheduler plugins via outOfTreePluginRegistry.
|
||||||
|
// Also, you may want to put your plugins in PluginNames variable in this package.
|
||||||
func RunBenchmarkPerfScheduling(b *testing.B, outOfTreePluginRegistry frameworkruntime.Registry) {
|
func RunBenchmarkPerfScheduling(b *testing.B, outOfTreePluginRegistry frameworkruntime.Registry) {
|
||||||
testCases, err := getTestCases(configFile)
|
testCases, err := getTestCases(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -247,7 +247,7 @@ type labelValues struct {
|
|||||||
// metricsCollectorConfig is the config to be marshalled to YAML config file.
|
// metricsCollectorConfig is the config to be marshalled to YAML config file.
|
||||||
// NOTE: The mapping here means only one filter is supported, either value in the list of `values` is able to be collected.
|
// NOTE: The mapping here means only one filter is supported, either value in the list of `values` is able to be collected.
|
||||||
type metricsCollectorConfig struct {
|
type metricsCollectorConfig struct {
|
||||||
Metrics map[string]*labelValues
|
Metrics map[string][]*labelValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// metricsCollector collects metrics from legacyregistry.DefaultGatherer.Gather() endpoint.
|
// metricsCollector collects metrics from legacyregistry.DefaultGatherer.Gather() endpoint.
|
||||||
@ -270,17 +270,15 @@ func (*metricsCollector) run(tCtx ktesting.TContext) {
|
|||||||
|
|
||||||
func (pc *metricsCollector) collect() []DataItem {
|
func (pc *metricsCollector) collect() []DataItem {
|
||||||
var dataItems []DataItem
|
var dataItems []DataItem
|
||||||
for metric, labelVals := range pc.Metrics {
|
for metric, labelValsSlice := range pc.Metrics {
|
||||||
// no filter is specified, aggregate all the metrics within the same metricFamily.
|
// no filter is specified, aggregate all the metrics within the same metricFamily.
|
||||||
if labelVals == nil {
|
if labelValsSlice == nil {
|
||||||
dataItem := collectHistogramVec(metric, pc.labels, nil)
|
dataItem := collectHistogramVec(metric, pc.labels, nil)
|
||||||
if dataItem != nil {
|
if dataItem != nil {
|
||||||
dataItems = append(dataItems, *dataItem)
|
dataItems = append(dataItems, *dataItem)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// fetch the metric from metricFamily which match each of the lvMap.
|
for _, lvMap := range uniqueLVCombos(labelValsSlice) {
|
||||||
for _, value := range labelVals.values {
|
|
||||||
lvMap := map[string]string{labelVals.label: value}
|
|
||||||
dataItem := collectHistogramVec(metric, pc.labels, lvMap)
|
dataItem := collectHistogramVec(metric, pc.labels, lvMap)
|
||||||
if dataItem != nil {
|
if dataItem != nil {
|
||||||
dataItems = append(dataItems, *dataItem)
|
dataItems = append(dataItems, *dataItem)
|
||||||
@ -291,6 +289,32 @@ func (pc *metricsCollector) collect() []DataItem {
|
|||||||
return dataItems
|
return dataItems
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uniqueLVCombos lists up all possible label values combinations.
|
||||||
|
// e.g., if there are 3 labelValues, each of which has 2 values,
|
||||||
|
// the result would be {A: a1, B: b1, C: c1}, {A: a2, B: b1, C: c1}, {A: a1, B: b2, C: c1}, ... (2^3 = 8 combinations).
|
||||||
|
func uniqueLVCombos(lvs []*labelValues) []map[string]string {
|
||||||
|
if len(lvs) == 0 {
|
||||||
|
return []map[string]string{{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingCombos := uniqueLVCombos(lvs[1:])
|
||||||
|
|
||||||
|
results := make([]map[string]string, 0)
|
||||||
|
|
||||||
|
current := lvs[0]
|
||||||
|
for _, value := range current.values {
|
||||||
|
for _, combo := range remainingCombos {
|
||||||
|
newCombo := make(map[string]string, len(combo)+1)
|
||||||
|
for k, v := range combo {
|
||||||
|
newCombo[k] = v
|
||||||
|
}
|
||||||
|
newCombo[current.label] = value
|
||||||
|
results = append(results, newCombo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
func collectHistogramVec(metric string, labels map[string]string, lvMap map[string]string) *DataItem {
|
func collectHistogramVec(metric string, labels map[string]string, lvMap map[string]string) *DataItem {
|
||||||
vec, err := testutil.GetHistogramVecFromGatherer(legacyregistry.DefaultGatherer, metric, lvMap)
|
vec, err := testutil.GetHistogramVecFromGatherer(legacyregistry.DefaultGatherer, metric, lvMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
87
test/integration/scheduler_perf/util_test.go
Normal file
87
test/integration/scheduler_perf/util_test.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors.
|
||||||
|
|
||||||
|
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 benchmark
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_uniqueLVCombos(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
lvs []*labelValues
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want []map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty input",
|
||||||
|
args: args{
|
||||||
|
lvs: []*labelValues{},
|
||||||
|
},
|
||||||
|
want: []map[string]string{{}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single label, multiple values",
|
||||||
|
args: args{
|
||||||
|
lvs: []*labelValues{
|
||||||
|
{"A", []string{"a1", "a2"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: []map[string]string{
|
||||||
|
{"A": "a1"},
|
||||||
|
{"A": "a2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple labels, single value each",
|
||||||
|
args: args{
|
||||||
|
lvs: []*labelValues{
|
||||||
|
{"A", []string{"a1"}},
|
||||||
|
{"B", []string{"b1"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: []map[string]string{
|
||||||
|
{"A": "a1", "B": "b1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple labels, multiple values",
|
||||||
|
args: args{
|
||||||
|
lvs: []*labelValues{
|
||||||
|
{"A", []string{"a1", "a2"}},
|
||||||
|
{"B", []string{"b1", "b2"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: []map[string]string{
|
||||||
|
{"A": "a1", "B": "b1"},
|
||||||
|
{"A": "a1", "B": "b2"},
|
||||||
|
{"A": "a2", "B": "b1"},
|
||||||
|
{"A": "a2", "B": "b2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := uniqueLVCombos(tt.args.lvs); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("uniqueLVCombos() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user