diff --git a/plugin/gthulhu/gthulhu.go b/plugin/gthulhu/gthulhu.go index 8ab0fb6..779f859 100644 --- a/plugin/gthulhu/gthulhu.go +++ b/plugin/gthulhu/gthulhu.go @@ -8,6 +8,7 @@ import ( "github.com/Gthulhu/plugin/models" reg "github.com/Gthulhu/plugin/plugin/internal/registry" + "github.com/Gthulhu/plugin/plugin/util" ) func init() { @@ -65,8 +66,11 @@ type GthulhuPlugin struct { minVruntime uint64 // Strategy map for PID-based scheduling strategies - strategyMap map[int32]SchedulingStrategy - strategyMu sync.RWMutex + oldStrategyMap map[int32]util.SchedulingStrategy + strategyMap map[int32]util.SchedulingStrategy + newStrategy []util.SchedulingStrategy + removedStrategy []util.SchedulingStrategy + strategyMu sync.RWMutex // JWT client for API authentication jwtClient *JWTClient @@ -82,7 +86,7 @@ func NewGthulhuPlugin(sliceNsDefault, sliceNsMin uint64) *GthulhuPlugin { taskPool: make([]Task, taskPoolSize), taskPoolCount: 0, minVruntime: 0, - strategyMap: make(map[int32]SchedulingStrategy), + strategyMap: make(map[int32]util.SchedulingStrategy), } // Override defaults if provided @@ -348,7 +352,7 @@ func (g *GthulhuPlugin) GetSchedulerConfig() (uint64, uint64) { } // FetchSchedulingStrategies fetches scheduling strategies from the API server -func (g *GthulhuPlugin) FetchSchedulingStrategies(apiUrl string) ([]SchedulingStrategy, error) { +func (g *GthulhuPlugin) FetchSchedulingStrategies(apiUrl string) ([]util.SchedulingStrategy, error) { if g.jwtClient == nil { return nil, nil // Silently skip if JWT client not initialized } @@ -356,9 +360,9 @@ func (g *GthulhuPlugin) FetchSchedulingStrategies(apiUrl string) ([]SchedulingSt } // UpdateStrategyMap updates the strategy map from a slice of strategies -func (g *GthulhuPlugin) UpdateStrategyMap(strategies []SchedulingStrategy) { +func (g *GthulhuPlugin) UpdateStrategyMap(strategies []util.SchedulingStrategy) { // Create a new map to avoid concurrent access issues - newMap := make(map[int32]SchedulingStrategy) + newMap := make(map[int32]util.SchedulingStrategy) for _, strategy := range strategies { newMap[int32(strategy.PID)] = strategy @@ -366,6 +370,45 @@ func (g *GthulhuPlugin) UpdateStrategyMap(strategies []SchedulingStrategy) { // Replace the old map with the new one g.strategyMu.Lock() + g.oldStrategyMap = g.strategyMap g.strategyMap = newMap + changed, removed := g.caculateChangedStrategies() + g.newStrategy = append(g.newStrategy, changed...) + g.removedStrategy = append(g.removedStrategy, removed...) g.strategyMu.Unlock() } + +// Campare g.oldStrategyMap and g.strategyMap and return the list of SchedulingStrategy that have changed strategies +func (g *GthulhuPlugin) caculateChangedStrategies() ([]util.SchedulingStrategy, []util.SchedulingStrategy) { + changed := []util.SchedulingStrategy{} + removed := []util.SchedulingStrategy{} + + // Check for removed strategies + for pid, oldStrategy := range g.oldStrategyMap { + _, exists := g.strategyMap[pid] + if !exists { + removed = append(removed, oldStrategy) + } + } + + // Check for changed or new strategies + for pid, newStrategy := range g.strategyMap { + oldStrategy, exists := g.oldStrategyMap[pid] + if !exists || oldStrategy != newStrategy { + changed = append(changed, newStrategy) + } + } + return changed, removed +} + +// Campare g.oldStrategyMap and g.strategyMap and return the list of SchedulingStrategy that have changed strategies +func (g *GthulhuPlugin) GetChangedStrategies() ([]util.SchedulingStrategy, []util.SchedulingStrategy) { + changed := []util.SchedulingStrategy{} + g.strategyMu.RLock() + defer g.strategyMu.RUnlock() + + // copy g.newStrategy to changed and clear g.newStrategy + changed = append(changed, g.newStrategy...) + g.newStrategy = []util.SchedulingStrategy{} + return changed, nil +} diff --git a/plugin/gthulhu/gthulhu_test.go b/plugin/gthulhu/gthulhu_test.go index 671a863..a0150d2 100644 --- a/plugin/gthulhu/gthulhu_test.go +++ b/plugin/gthulhu/gthulhu_test.go @@ -5,6 +5,7 @@ import ( "github.com/Gthulhu/plugin/models" reg "github.com/Gthulhu/plugin/plugin/internal/registry" + "github.com/Gthulhu/plugin/plugin/util" ) // TestGthulhuPluginInstanceIsolation verifies that multiple GthulhuPlugin instances maintain independent state @@ -103,7 +104,7 @@ func TestGthulhuPluginUpdateStrategyMap(t *testing.T) { gthulhuPlugin := NewGthulhuPlugin(0, 0) // Create test strategies - strategies := []SchedulingStrategy{ + strategies := []util.SchedulingStrategy{ {PID: 100, Priority: true, ExecutionTime: 10000}, {PID: 200, Priority: false, ExecutionTime: 20000}, } @@ -359,7 +360,7 @@ func TestGthulhuPluginRuntimeSimulation(t *testing.T) { gthulhuPlugin = NewGthulhuPlugin(5000*1000, 500*1000) // Reset plugin // Set up scheduling strategies - strategies := []SchedulingStrategy{ + strategies := []util.SchedulingStrategy{ {PID: 100, Priority: true, ExecutionTime: 10000000}, // 10ms {PID: 200, Priority: false, ExecutionTime: 20000000}, // 20ms } diff --git a/plugin/gthulhu/strategy.go b/plugin/gthulhu/strategy.go index 1eab8b3..9cbb9c4 100644 --- a/plugin/gthulhu/strategy.go +++ b/plugin/gthulhu/strategy.go @@ -7,27 +7,14 @@ import ( "io" "log" "time" -) - -// SchedulingStrategy represents a strategy for process scheduling -type SchedulingStrategy struct { - Priority bool `json:"priority"` // If true, set vtime to minimum vtime - ExecutionTime uint64 `json:"execution_time"` // Time slice for this process in nanoseconds - PID int `json:"pid"` // Process ID to apply this strategy to -} -// SchedulingStrategiesResponse represents the response structure from the API -type SchedulingStrategiesResponse struct { - Success bool `json:"success"` - Message string `json:"message"` - Timestamp string `json:"timestamp"` - Scheduling []SchedulingStrategy `json:"scheduling"` -} + "github.com/Gthulhu/plugin/plugin/util" +) const SCX_ENQ_PREEMPT = 1 << 32 // fetchSchedulingStrategies fetches scheduling strategies from the API server with JWT authentication -func fetchSchedulingStrategies(jwtClient *JWTClient, apiUrl string) ([]SchedulingStrategy, error) { +func fetchSchedulingStrategies(jwtClient *JWTClient, apiUrl string) ([]util.SchedulingStrategy, error) { if jwtClient == nil { return nil, fmt.Errorf("JWT client not initialized") } @@ -47,7 +34,7 @@ func fetchSchedulingStrategies(jwtClient *JWTClient, apiUrl string) ([]Schedulin return nil, err } - var response SchedulingStrategiesResponse + var response util.SchedulingStrategiesResponse if err := json.Unmarshal(body, &response); err != nil { return nil, err } diff --git a/plugin/internal/registry/registry.go b/plugin/internal/registry/registry.go index fb1bdce..f4e29b7 100644 --- a/plugin/internal/registry/registry.go +++ b/plugin/internal/registry/registry.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/Gthulhu/plugin/models" + "github.com/Gthulhu/plugin/plugin/util" ) type Sched interface { @@ -27,6 +28,8 @@ type CustomScheduler interface { GetPoolCount() uint64 // SendMetrics sends custom metrics to the monitoring system SendMetrics(interface{}) + // GetChangedStrategies returns the list of scheduling strategies that have changed since the last call + GetChangedStrategies() ([]util.SchedulingStrategy, []util.SchedulingStrategy) } type Scheduler struct { diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go index 295dbf2..428c54b 100644 --- a/plugin/plugin_test.go +++ b/plugin/plugin_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/Gthulhu/plugin/models" + "github.com/Gthulhu/plugin/plugin/util" ) // TestRegisterNewPlugin tests the plugin registration functionality @@ -360,3 +361,7 @@ func (m *mockScheduler) DetermineTimeSlice(s Sched, t *models.QueuedTask) uint64 func (m *mockScheduler) GetPoolCount() uint64 { return 0 } + +func (m *mockScheduler) GetChangedStrategies() ([]util.SchedulingStrategy, []util.SchedulingStrategy) { + return nil, nil +} diff --git a/plugin/simple/simple.go b/plugin/simple/simple.go index 95e72bc..fbe999e 100644 --- a/plugin/simple/simple.go +++ b/plugin/simple/simple.go @@ -5,6 +5,7 @@ import ( "github.com/Gthulhu/plugin/models" reg "github.com/Gthulhu/plugin/plugin/internal/registry" + "github.com/Gthulhu/plugin/plugin/util" ) func init() { @@ -144,12 +145,10 @@ func (s *SimplePlugin) enqueueTask(queuedTask *models.QueuedTask) Task { // Weighted vtime scheduling logic if !s.fifoMode { - // Limit the amount of budget that an idling task can accumulate to one slice if vtime < saturatingSub(s.vtimeNow, s.sliceDefault) { vtime = saturatingSub(s.vtimeNow, s.sliceDefault) } - } // Ensure vtime is never 0 - use minimum value of 1 if needed @@ -289,3 +288,7 @@ func (s *SimplePlugin) GetPoolStatus() (head, tail, count, capacity int) { // For slice implementation: head=0, tail=len, count=len, capacity=cap return 0, len(s.taskPool), len(s.taskPool), cap(s.taskPool) } + +func (s *SimplePlugin) GetChangedStrategies() ([]util.SchedulingStrategy, []util.SchedulingStrategy) { + return nil, nil +} diff --git a/plugin/util/util.go b/plugin/util/util.go index eda2dd5..c62fe98 100644 --- a/plugin/util/util.go +++ b/plugin/util/util.go @@ -2,6 +2,21 @@ package util import "time" +// SchedulingStrategy represents a strategy for process scheduling +type SchedulingStrategy struct { + Priority bool `json:"priority"` // If true, set vtime to minimum vtime + ExecutionTime uint64 `json:"execution_time"` // Time slice for this process in nanoseconds + PID int `json:"pid"` // Process ID to apply this strategy to +} + +// SchedulingStrategiesResponse represents the response structure from the API +type SchedulingStrategiesResponse struct { + Success bool `json:"success"` + Message string `json:"message"` + Timestamp string `json:"timestamp"` + Scheduling []SchedulingStrategy `json:"scheduling"` +} + func Now() uint64 { return uint64(time.Now().UnixNano()) }