You are viewing a plain text version of this content. The canonical link for it is here.
Posted to reviews@yunikorn.apache.org by "craigcondit (via GitHub)" <gi...@apache.org> on 2023/05/11 21:40:30 UTC

[GitHub] [yunikorn-k8shim] craigcondit commented on a diff in pull request #587: [YUNIKORN-1724] Improve the performance of shim side scheduling cycle

craigcondit commented on code in PR #587:
URL: https://github.com/apache/yunikorn-k8shim/pull/587#discussion_r1191705692


##########
pkg/cache/application.go:
##########
@@ -62,6 +63,68 @@ type Application struct {
 	placeholderTimeoutInSec    int64
 	schedulingStyle            string
 	originatingTask            interfaces.ManagedTask // Original Pod which creates the requests
+
+	newTasks *newTasksTracker
+}
+
+// For performance reasons, we track tasks with "New" state for quick retrieval.
+// Application.GetNewTasks (and getTasks() in general) must not be used on critical paths because it
+// uses a read lock inside fsm.FSM which becomes a bottleneck with large number of pods.
+type newTasksTracker struct {
+	sortedTasks *btree.BTree
+	sync.Mutex

Review Comment:
   Shouldn't we use an RWMutex here as reads are likely to (significantly) outstrip writes?



##########
pkg/cache/application_test.go:
##########
@@ -1343,3 +1343,64 @@ func (ctx *Context) addApplication(app *Application) {
 	defer ctx.lock.Unlock()
 	ctx.applications[app.applicationID] = app
 }
+
+func TestNewTaskTracker(t *testing.T) {
+	context := initContextForTest()
+	ms := newMockSchedulerAPI()
+	app := NewApplication(appID, "root.abc", "testuser", testGroups, map[string]string{}, ms)
+	tasks := []*Task{
+		NewTask("task01", app, context,
+			&v1.Pod{
+				ObjectMeta: apis.ObjectMeta{
+					CreationTimestamp: apis.Time{Time: time.Unix(100, 0)},
+				},
+			},
+		),
+		NewTask("task02", app, context,
+			&v1.Pod{
+				ObjectMeta: apis.ObjectMeta{
+					CreationTimestamp: apis.Time{Time: time.Unix(11, 0)},
+				},
+			},
+		),
+		NewTask("task03", app, context,
+			&v1.Pod{
+				ObjectMeta: apis.ObjectMeta{
+					CreationTimestamp: apis.Time{Time: time.Unix(22, 0)},
+				},
+			},
+		),
+		NewTask("task04", app, context,
+			&v1.Pod{
+				ObjectMeta: apis.ObjectMeta{
+					CreationTimestamp: apis.Time{Time: time.Unix(50, 0)},
+				},
+			},
+		),
+		NewTask("task05", app, context,
+			&v1.Pod{
+				ObjectMeta: apis.ObjectMeta{
+					CreationTimestamp: apis.Time{Time: time.Unix(1, 0)},
+				},
+			},
+		),
+	}
+
+	for _, task := range tasks {
+		app.addTask(task)
+	}
+	verifyNewTaskOrding(t, app)
+	app.removeTask("task04")
+	app.removeTask("task05")
+	verifyNewTaskOrding(t, app)
+	assert.Equal(t, 3, app.newTasks.count())
+}
+
+func verifyNewTaskOrding(t *testing.T, app *Application) {
+	newTasks := app.GetNewTasks()

Review Comment:
   I think app.GetNewTasks() should be refactored to use the new method. There's no point in leaving the old mechanism around. We can add an `app.HasNewTasks() bool` method as well for quickly determining if the list is empty.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: reviews-unsubscribe@yunikorn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org