scheduler perf: add DynamicResourceAllocation test cases

The default scheduler configuration must be based on the v1 API where the
plugin is enabled by default. Then if (and only if) the
DynamicResourceAllocation feature gate for a test is set, the corresponding
API group also gets enabled.

The normal dynamic resource claim controller is started if needed to create
ResourceClaims from ResourceClaimTemplates.

Without the upcoming optimizations in the scheduler, scheduling with dynamic
resources is fairly slow. The new test cases take around 15 minutes wall clock
time on my desktop.
This commit is contained in:
Patrick Ohly
2023-01-24 17:45:57 +01:00
parent 47f1bd9f80
commit 034528a9f0
13 changed files with 518 additions and 15 deletions

View File

@@ -32,6 +32,7 @@ import (
"time"
v1 "k8s.io/api/core/v1"
resourcev1alpha2 "k8s.io/api/resource/v1alpha2"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -59,13 +60,17 @@ import (
type operationCode string
const (
createNodesOpcode operationCode = "createNodes"
createNamespacesOpcode operationCode = "createNamespaces"
createPodsOpcode operationCode = "createPods"
createPodSetsOpcode operationCode = "createPodSets"
churnOpcode operationCode = "churn"
barrierOpcode operationCode = "barrier"
sleepOpcode operationCode = "sleep"
createNodesOpcode operationCode = "createNodes"
createNamespacesOpcode operationCode = "createNamespaces"
createPodsOpcode operationCode = "createPods"
createPodSetsOpcode operationCode = "createPodSets"
createResourceClaimsOpcode operationCode = "createResourceClaims"
createResourceClaimTemplateOpcode operationCode = "createResourceClaimTemplate"
createResourceClassOpcode operationCode = "createResourceClass"
createResourceDriverOpcode operationCode = "createResourceDriver"
churnOpcode operationCode = "churn"
barrierOpcode operationCode = "barrier"
sleepOpcode operationCode = "sleep"
)
const (
@@ -227,6 +232,10 @@ func (op *op) UnmarshalJSON(b []byte) error {
&createNamespacesOp{},
&createPodsOp{},
&createPodSetsOp{},
&createResourceClaimsOp{},
&createOp[resourcev1alpha2.ResourceClaimTemplate, createResourceClaimTemplateOpType]{},
&createOp[resourcev1alpha2.ResourceClass, createResourceClassOpType]{},
&createResourceDriverOp{},
&churnOp{},
&barrierOp{},
&sleepOp{},
@@ -265,6 +274,18 @@ type realOp interface {
patchParams(w *workload) (realOp, error)
}
// runnableOp is an interface implemented by some operations. It makes it posssible
// to execute the operation without having to add separate code into runWorkload.
type runnableOp interface {
realOp
// requiredNamespaces returns all namespaces that runWorkload must create
// before running the operation.
requiredNamespaces() []string
// run executes the steps provided by the operation.
run(context.Context, testing.TB, clientset.Interface)
}
func isValidParameterizable(val string) bool {
return strings.HasPrefix(val, "$")
}
@@ -760,7 +781,7 @@ func runWorkload(ctx context.Context, b *testing.B, tc *testCase, w *workload) [
b.Fatalf("validate scheduler config file failed: %v", err)
}
}
informerFactory, client, dynClient := mustSetupScheduler(ctx, b, cfg)
informerFactory, client, dynClient := mustSetupScheduler(ctx, b, cfg, tc.FeatureGates)
// Additional informers needed for testing. The pod informer was
// already created before (scheduler.NewInformerFactory) and the
@@ -1014,7 +1035,14 @@ func runWorkload(ctx context.Context, b *testing.B, tc *testCase, w *workload) [
case <-time.After(concreteOp.Duration):
}
default:
b.Fatalf("op %d: invalid op %v", opIndex, concreteOp)
runable, ok := concreteOp.(runnableOp)
if !ok {
b.Fatalf("op %d: invalid op %v", opIndex, concreteOp)
}
for _, namespace := range runable.requiredNamespaces() {
createNamespaceIfNotPresent(ctx, b, client, namespace, &numPodsScheduledPerNamespace)
}
runable.run(ctx, b, client)
}
}