diff --git a/docs/docs.go b/docs/docs.go index 7415bd78..5ac06bf8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -6147,6 +6147,9 @@ const docTemplate = `{ "last_logline": { "type": "string" }, + "limit_mode": { + "type": "string" + }, "memory_bytes": { "description": "deprecated, use Resources.CPU.Current", "type": "integer", @@ -6199,6 +6202,9 @@ const docTemplate = `{ }, "ncpu": { "type": "number" + }, + "throttling": { + "type": "boolean" } } }, diff --git a/docs/swagger.json b/docs/swagger.json index a53f8044..fff31f09 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -6139,6 +6139,9 @@ "last_logline": { "type": "string" }, + "limit_mode": { + "type": "string" + }, "memory_bytes": { "description": "deprecated, use Resources.CPU.Current", "type": "integer", @@ -6191,6 +6194,9 @@ }, "ncpu": { "type": "number" + }, + "throttling": { + "type": "boolean" } } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 917f0ed1..74094d81 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1220,6 +1220,8 @@ definitions: type: string last_logline: type: string + limit_mode: + type: string memory_bytes: description: deprecated, use Resources.CPU.Current format: uint64 @@ -1256,6 +1258,8 @@ definitions: type: number ncpu: type: number + throttling: + type: boolean type: object api.ProcessUsageMemory: properties: diff --git a/http/api/process.go b/http/api/process.go index 24349ee6..6f9939bc 100644 --- a/http/api/process.go +++ b/http/api/process.go @@ -227,6 +227,7 @@ type ProcessState struct { Progress *Progress `json:"progress"` Memory uint64 `json:"memory_bytes" format:"uint64"` // deprecated, use Resources.CPU.Current CPU json.Number `json:"cpu_usage" swaggertype:"number" jsonschema:"type=number"` // deprecated, use Resources.Memory.Current + LimitMode string `json:"limit_mode"` Resources ProcessUsage `json:"resources"` Command []string `json:"command"` } @@ -245,12 +246,14 @@ func (s *ProcessState) Unmarshal(state *app.State) { s.Progress = &Progress{} s.Memory = state.Memory s.CPU = ToNumber(state.CPU) + s.LimitMode = state.LimitMode s.Resources.CPU = ProcessUsageCPU{ - NCPU: ToNumber(state.Resources.CPU.NCPU), - Current: ToNumber(state.Resources.CPU.Current), - Average: ToNumber(state.Resources.CPU.Average), - Max: ToNumber(state.Resources.CPU.Max), - Limit: ToNumber(state.Resources.CPU.Limit), + NCPU: ToNumber(state.Resources.CPU.NCPU), + Current: ToNumber(state.Resources.CPU.Current), + Average: ToNumber(state.Resources.CPU.Average), + Max: ToNumber(state.Resources.CPU.Max), + Limit: ToNumber(state.Resources.CPU.Limit), + IsThrottling: state.Resources.CPU.IsThrottling, } s.Resources.Memory = ProcessUsageMemory{ Current: state.Resources.Memory.Current, @@ -264,11 +267,12 @@ func (s *ProcessState) Unmarshal(state *app.State) { } type ProcessUsageCPU struct { - NCPU json.Number `json:"ncpu" swaggertype:"number" jsonschema:"type=number"` - Current json.Number `json:"cur" swaggertype:"number" jsonschema:"type=number"` - Average json.Number `json:"avg" swaggertype:"number" jsonschema:"type=number"` - Max json.Number `json:"max" swaggertype:"number" jsonschema:"type=number"` - Limit json.Number `json:"limit" swaggertype:"number" jsonschema:"type=number"` + NCPU json.Number `json:"ncpu" swaggertype:"number" jsonschema:"type=number"` + Current json.Number `json:"cur" swaggertype:"number" jsonschema:"type=number"` + Average json.Number `json:"avg" swaggertype:"number" jsonschema:"type=number"` + Max json.Number `json:"max" swaggertype:"number" jsonschema:"type=number"` + Limit json.Number `json:"limit" swaggertype:"number" jsonschema:"type=number"` + IsThrottling bool `json:"throttling"` } type ProcessUsageMemory struct { diff --git a/process/limiter.go b/process/limiter.go index cffa7733..5a11869c 100644 --- a/process/limiter.go +++ b/process/limiter.go @@ -12,11 +12,12 @@ import ( type Usage struct { CPU struct { - NCPU float64 // number of logical processors - Current float64 // percent 0-100*ncpu - Average float64 // percent 0-100*ncpu - Max float64 // percent 0-100*ncpu - Limit float64 // percent 0-100*ncpu + NCPU float64 // number of logical processors + Current float64 // percent 0-100*ncpu + Average float64 // percent 0-100*ncpu + Max float64 // percent 0-100*ncpu + Limit float64 // percent 0-100*ncpu + IsThrottling bool } Memory struct { Current uint64 // bytes @@ -79,6 +80,9 @@ type Limiter interface { // Limit enables or disables the throttling of the CPU or killing because of to much // memory consumption. Limit(cpu, memory bool) error + + // Mode returns in which mode the limiter is running in. + Mode() LimitMode } type limiter struct { @@ -99,7 +103,8 @@ type limiter struct { cpuAvg float64 // Average CPU load of this process cpuAvgCounter uint64 // Counter for average calculation cpuLimitSince time.Time // Time when the CPU limit has been reached (hard limiter mode) - cpuLimitEnable bool // Whether CPU limiting is enabled (soft limiter mode) + cpuLimitEnable bool // Whether CPU throttling is enabled (soft limiter mode) + cpuThrottling bool // Whether CPU throttling is currently active (soft limiter mode) memory uint64 // Memory limit (bytes) memoryCurrent uint64 // Current memory usage @@ -177,6 +182,7 @@ func (l *limiter) reset() { l.cpuMax = 0 l.cpuTop = 0 l.cpuLimitEnable = false + l.cpuThrottling = false l.memoryCurrent = 0 l.memoryLast = 0 @@ -399,6 +405,7 @@ func (l *limiter) limitCPU(ctx context.Context, limit float64, interval time.Dur if l.proc != nil { l.proc.Resume() } + l.cpuThrottling = false l.lock.Unlock() l.logger.Debug().Log("CPU throttler disabled") @@ -426,6 +433,7 @@ func (l *limiter) limitCPU(ctx context.Context, limit float64, interval time.Dur if l.proc != nil { l.proc.Resume() } + l.cpuThrottling = false l.lock.Unlock() time.Sleep(100 * time.Millisecond) continue @@ -433,6 +441,7 @@ func (l *limiter) limitCPU(ctx context.Context, limit float64, interval time.Dur } else { factorTopLimit = 100 topLimit = l.cpuTop - limit + l.cpuThrottling = true } lim := limit @@ -509,6 +518,7 @@ func (l *limiter) Usage() Usage { usage.CPU.Current = l.cpuCurrent * l.ncpu * 100 usage.CPU.Average = l.cpuAvg * l.ncpu * 100 usage.CPU.Max = l.cpuMax * l.ncpu * 100 + usage.CPU.IsThrottling = l.cpuThrottling usage.Memory.Limit = l.memory usage.Memory.Current = l.memoryCurrent @@ -521,3 +531,7 @@ func (l *limiter) Usage() Usage { func (l *limiter) Limits() (cpu float64, memory uint64) { return l.cpu * 100, l.memory } + +func (l *limiter) Mode() LimitMode { + return l.mode +} diff --git a/process/process.go b/process/process.go index 14079b59..f727a325 100644 --- a/process/process.go +++ b/process/process.go @@ -80,12 +80,14 @@ type Status struct { Duration time.Duration // Duration is the time since the last change of the state Time time.Time // Time is the time of the last change of the state CommandArgs []string // Currently running command arguments + LimitMode string // The limiting mode CPU struct { - NCPU float64 // Number of logical CPUs - Current float64 // Currently consumed CPU in percent - Average float64 // Average consumed CPU in percent - Max float64 // Max. consumed CPU in percent - Limit float64 // Usage limit in percent + NCPU float64 // Number of logical CPUs + Current float64 // Currently consumed CPU in percent + Average float64 // Average consumed CPU in percent + Max float64 // Max. consumed CPU in percent + Limit float64 // Usage limit in percent + IsThrottling bool // Whether the CPU is currently limited } // Used CPU in percent Memory struct { Current uint64 // Currently consumed memory in bytes @@ -461,6 +463,7 @@ func (p *process) Status() Status { Reconnect: time.Duration(-1), Duration: time.Since(stateTime), Time: stateTime, + LimitMode: p.limits.Mode().String(), CPU: usage.CPU, Memory: usage.Memory, } diff --git a/restream/app/process.go b/restream/app/process.go index 8663a3da..97876821 100644 --- a/restream/app/process.go +++ b/restream/app/process.go @@ -248,16 +248,18 @@ type State struct { Progress Progress // Progress data of the process Memory uint64 // Current memory consumption in bytes CPU float64 // Current CPU consumption in percent + LimitMode string // How the process is limited (hard or soft) Resources ProcessUsage // Current resource usage, include CPU and memory consumption Command []string // ffmpeg command line parameters } type ProcessUsageCPU struct { - NCPU float64 // Number of logical CPUs - Current float64 // percent 0-100*ncpu - Average float64 // percent 0-100*ncpu - Max float64 // percent 0-100*ncpu - Limit float64 // percent 0-100*ncpu + NCPU float64 // Number of logical CPUs + Current float64 // percent 0-100*ncpu + Average float64 // percent 0-100*ncpu + Max float64 // percent 0-100*ncpu + Limit float64 // percent 0-100*ncpu + IsThrottling bool } type ProcessUsageMemory struct { diff --git a/restream/restream.go b/restream/restream.go index 20857361..71191e0a 100644 --- a/restream/restream.go +++ b/restream/restream.go @@ -1576,6 +1576,7 @@ func (r *restream) GetProcessState(id app.ProcessID) (*app.State, error) { state.Time = status.Time.Unix() state.Memory = status.Memory.Current state.CPU = status.CPU.Current / status.CPU.NCPU + state.LimitMode = status.LimitMode state.Resources.CPU = status.CPU state.Resources.Memory = status.Memory state.Duration = status.Duration.Round(10 * time.Millisecond).Seconds()