Skip to content

Conversation

@learner0810
Copy link
Contributor

What type of PR is this?
/kind cleanup

What this PR does / why we need it:

Merge shuffle score pods logic

Which issue(s) this PR fixes:

Fixes #

Does this PR introduce a user-facing change?:


@k8s-ci-robot k8s-ci-robot added the kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. label Sep 9, 2025
@netlify
Copy link

netlify bot commented Sep 9, 2025

Deploy Preview for gateway-api-inference-extension ready!

Name Link
🔨 Latest commit 6ac1fe4
🔍 Latest deploy log https://app.netlify.com/projects/gateway-api-inference-extension/deploys/68bfe268baae590007b1f4dc
😎 Deploy Preview https://deploy-preview-1552--gateway-api-inference-extension.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Sep 9, 2025
@k8s-ci-robot k8s-ci-robot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Sep 9, 2025
@k8s-ci-robot
Copy link
Contributor

Hi @learner0810. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Sep 9, 2025
@learner0810 learner0810 force-pushed the merge-shuffle-scored-pods-logic branch from 5ade12d to 6ac1fe4 Compare September 9, 2025 08:16
@elevran
Copy link
Contributor

elevran commented Sep 9, 2025

/ok-to-test

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Sep 9, 2025
@kfswain
Copy link
Collaborator

kfswain commented Sep 10, 2025

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Sep 10, 2025
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: kfswain, learner0810

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 10, 2025
@k8s-ci-robot k8s-ci-robot merged commit e95d8e8 into kubernetes-sigs:main Sep 10, 2025
10 checks passed
func shuffleScoredPods(scoredPods []*types.ScoredPod) {
// Rand package is not safe for concurrent use, so we create a new instance.
// Source: https://pkg.go.dev/math/rand/v2#pkg-overview
randomGenerator := rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), 0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you compared using sync.Pool vs creating a new random source every time?
I don't expect much latency difference but a sync.Pool would reduce GC pressure as these are created and collected per request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func shuffleScoredPods(scoredPods []*types.ScoredPod) {
	// Rand package is not safe for concurrent use, so we create a new instance.
	// Source: https://pkg.go.dev/math/rand/v2#pkg-overview
	randomGenerator := rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), 0))

	// Shuffle in-place
	randomGenerator.Shuffle(len(scoredPods), func(i, j int) {
		scoredPods[i], scoredPods[j] = scoredPods[j], scoredPods[i]
	})
}

var randPool = sync.Pool{
	New: func() interface{} {
		return rand.New(rand.NewPCG(uint64(time.Now().UnixNano()), 0))
	},
}

func shuffleScoredPodsWithPool(scoredPods []*types.ScoredPod) {
	randomGenerator := randPool.Get().(*rand.Rand)
	defer randPool.Put(randomGenerator) 

	// Shuffle in-place
	randomGenerator.Shuffle(len(scoredPods), func(i, j int) {
		scoredPods[i], scoredPods[j] = scoredPods[j], scoredPods[i]
	})
}
func createTestScoredPods(count int) []*types.ScoredPod {
	pods := make([]*types.ScoredPod, count)
	for i := 0; i < count; i++ {
		pods[i] = &types.ScoredPod{
			Pod: &types.PodMetrics{
				Pod: &backend.Pod{
					NamespacedName: k8stypes.NamespacedName{
						Name:      "pod-" + strconv.Itoa(i),
						Namespace: "namespace-" + strconv.Itoa(i),
					},
				},
			},
			Score: float64(i),
		}
	}
	return pods
}

func BenchmarkShuffleScoredPods(b *testing.B) {
	testPods := createTestScoredPods(100)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		podsCopy := make([]*types.ScoredPod, len(testPods))
		copy(podsCopy, testPods)

		shuffleScoredPods(podsCopy)
	}
}

func BenchmarkShuffleScoredPodsWithPool(b *testing.B) {
	testPods := createTestScoredPods(100)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		podsCopy := make([]*types.ScoredPod, len(testPods))
		copy(podsCopy, testPods)

		shuffleScoredPodsWithPool(podsCopy)
	}
}

func BenchmarkShuffleScoredPods_Small(b *testing.B) {
	testPods := createTestScoredPods(10)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		podsCopy := make([]*types.ScoredPod, len(testPods))
		copy(podsCopy, testPods)

		shuffleScoredPods(podsCopy)
	}
}

func BenchmarkShuffleScoredPodsWithPool_Small(b *testing.B) {
	testPods := createTestScoredPods(10)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		podsCopy := make([]*types.ScoredPod, len(testPods))
		copy(podsCopy, testPods)

		shuffleScoredPodsWithPool(podsCopy)
	}
}

func BenchmarkShuffleScoredPods_Large(b *testing.B) {
	testPods := createTestScoredPods(1000)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		podsCopy := make([]*types.ScoredPod, len(testPods))
		copy(podsCopy, testPods)

		shuffleScoredPods(podsCopy)
	}
}

func BenchmarkShuffleScoredPodsWithPool_Large(b *testing.B) {
	testPods := createTestScoredPods(1000)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		podsCopy := make([]*types.ScoredPod, len(testPods))
		copy(podsCopy, testPods)

		shuffleScoredPodsWithPool(podsCopy)
	}
}

I have tested it locally and the test result is as follows. If there is any problem, please point it out. If the test results are accurate, do you think it needs to be optimized?

host@hostdeMacBook-Pro picker % go test -bench=. -benchmem
goos: darwin
goarch: amd64
pkg: sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework/plugins/picker
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkShuffleScoredPods-8                      911576              1245 ns/op             912 B/op          2 allocs/op
BenchmarkShuffleScoredPodsWithPool-8             1000000              1130 ns/op             896 B/op          1 allocs/op
BenchmarkShuffleScoredPods_Small-8               4351080               247.4 ns/op            96 B/op          2 allocs/op
BenchmarkShuffleScoredPodsWithPool_Small-8       7934428               139.8 ns/op            80 B/op          1 allocs/op
BenchmarkShuffleScoredPods_Large-8                115184             10405 ns/op            8208 B/op          2 allocs/op
BenchmarkShuffleScoredPodsWithPool_Large-8        115098             10628 ns/op            8195 B/op          1 allocs/op
PASS
ok      sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/framework/plugins/picker 7.652s

"time"

"sigs.k8s.io/controller-runtime/pkg/log"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please keep import groups separated and not combine controller-runtime (3rd-party/ external) with gateway-api-inference-extension (local/internal)

"time"

"sigs.k8s.io/controller-runtime/pkg/log"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@learner0810 learner0810 mentioned this pull request Sep 10, 2025
@learner0810 learner0810 deleted the merge-shuffle-scored-pods-logic branch September 26, 2025 03:30
BenjaminBraunDev pushed a commit to BenjaminBraunDev/gateway-api-inference-extension that referenced this pull request Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants