Add option to disable CPU throttling

This commit is contained in:
Ingo Oppermann
2025-06-24 16:52:51 +02:00
parent 2189c4c36c
commit 55314e35a8
12 changed files with 47 additions and 9 deletions

View File

@@ -513,6 +513,7 @@ func (a *api) start(ctx context.Context) error {
Portrange: portrange,
Collector: a.sessions.Collector("ffmpeg"),
Resource: a.resources,
Throttling: !cfg.FFmpeg.DisableThrottling,
})
if err != nil {
return fmt.Errorf("unable to create ffmpeg: %w", err)

View File

@@ -1922,6 +1922,9 @@ const docTemplateClusterAPI = `{
"binary": {
"type": "string"
},
"disable_throttling": {
"type": "boolean"
},
"log": {
"type": "object",
"properties": {

View File

@@ -1915,6 +1915,9 @@
"binary": {
"type": "string"
},
"disable_throttling": {
"type": "boolean"
},
"log": {
"type": "object",
"properties": {

View File

@@ -429,6 +429,8 @@ definitions:
type: object
binary:
type: string
disable_throttling:
type: boolean
log:
properties:
max_history:

View File

@@ -283,6 +283,7 @@ func (d *Config) init() {
// FFmpeg
d.vars.Register(value.NewExec(&d.FFmpeg.Binary, "ffmpeg", d.fs), "ffmpeg.binary", "CORE_FFMPEG_BINARY", nil, "Path to ffmpeg binary", true, false)
d.vars.Register(value.NewInt64(&d.FFmpeg.MaxProcesses, 0), "ffmpeg.max_processes", "CORE_FFMPEG_MAXPROCESSES", nil, "Max. allowed simultaneously running ffmpeg instances, 0 for unlimited", false, false)
d.vars.Register(value.NewBool(&d.FFmpeg.DisableThrottling, false), "ffmpeg.disable_throttling", "CORE_FFMPEG_DISABLE_THROTTLING", nil, "Disable CPU throttling", false, false)
d.vars.Register(value.NewStringList(&d.FFmpeg.Access.Input.Allow, []string{}, " "), "ffmpeg.access.input.allow", "CORE_FFMPEG_ACCESS_INPUT_ALLOW", nil, "List of allowed expression to match against the input addresses", false, false)
d.vars.Register(value.NewStringList(&d.FFmpeg.Access.Input.Block, []string{}, " "), "ffmpeg.access.input.block", "CORE_FFMPEG_ACCESS_INPUT_BLOCK", nil, "List of blocked expression to match against the input addresses", false, false)
d.vars.Register(value.NewStringList(&d.FFmpeg.Access.Output.Allow, []string{}, " "), "ffmpeg.access.output.allow", "CORE_FFMPEG_ACCESS_OUTPUT_ALLOW", nil, "List of allowed expression to match against the output addresses", false, false)

View File

@@ -127,9 +127,10 @@ type Data struct {
} `json:"log"`
} `json:"srt"`
FFmpeg struct {
Binary string `json:"binary"`
MaxProcesses int64 `json:"max_processes" format:"int64"`
Access struct {
Binary string `json:"binary"`
MaxProcesses int64 `json:"max_processes" format:"int64"`
DisableThrottling bool `json:"disable_throttling"`
Access struct {
Input struct {
Allow []string `json:"allow"`
Block []string `json:"block"`

View File

@@ -6077,6 +6077,9 @@ const docTemplate = `{
"binary": {
"type": "string"
},
"disable_throttling": {
"type": "boolean"
},
"log": {
"type": "object",
"properties": {
@@ -8628,6 +8631,9 @@ const docTemplate = `{
"binary": {
"type": "string"
},
"disable_throttling": {
"type": "boolean"
},
"log": {
"type": "object",
"properties": {

View File

@@ -6070,6 +6070,9 @@
"binary": {
"type": "string"
},
"disable_throttling": {
"type": "boolean"
},
"log": {
"type": "object",
"properties": {
@@ -8621,6 +8624,9 @@
"binary": {
"type": "string"
},
"disable_throttling": {
"type": "boolean"
},
"log": {
"type": "object",
"properties": {

View File

@@ -572,6 +572,8 @@ definitions:
type: object
binary:
type: string
disable_throttling:
type: boolean
log:
properties:
max_history:
@@ -2363,6 +2365,8 @@ definitions:
type: object
binary:
type: string
disable_throttling:
type: boolean
log:
properties:
max_history:

View File

@@ -65,7 +65,8 @@ type Config struct {
ValidatorOutput Validator
Portrange net.Portranger
Collector session.Collector
Resource resources.Resources
Resource resources.Resources // Resource observer
Throttling bool // Whether to allow CPU throttling
}
type ffmpeg struct {
@@ -84,7 +85,8 @@ type ffmpeg struct {
states process.States
statesLock sync.RWMutex
resources resources.Resources
resources resources.Resources
throttling bool
}
func New(config Config) (FFmpeg, error) {
@@ -95,6 +97,7 @@ func New(config Config) (FFmpeg, error) {
}
f.resources = config.Resource
f.throttling = config.Throttling
binary, err := exec.LookPath(config.Binary)
if err != nil {
@@ -164,6 +167,7 @@ func (f *ffmpeg) New(config ProcessConfig) (process.Process, error) {
StaleTimeout: config.StaleTimeout,
Timeout: config.Timeout,
LimitCPU: config.LimitCPU,
Throttling: f.throttling,
LimitMemory: config.LimitMemory,
LimitGPUUsage: config.LimitGPUUsage,
LimitGPUEncoder: config.LimitGPUEncoder,

View File

@@ -86,6 +86,7 @@ type LimiterConfig struct {
OnLimit LimitFunc // Function to be triggered if limits are exceeded.
Mode LimitMode // How to limit CPU usage.
NCPU float64 // Number of available CPU
Throttling bool // Whether to allow CPU throttling
Logger log.Logger
}
@@ -236,8 +237,9 @@ type limiter struct {
lastUsage Usage
lastUsageLock sync.RWMutex
cpu metric[float64] // CPU limit
cpuThrottling bool // Whether CPU throttling is currently active (soft limiter mode)
cpu metric[float64] // CPU limit
cpuThrottling bool // Whether CPU throttling is currently active (soft limiter mode)
cpuEnableThrottling bool // Whether to enable CPU throttling
memory metric[uint64] // Memory limit (bytes)
@@ -269,7 +271,10 @@ func NewLimiter(config LimiterConfig) (Limiter, error) {
}
l.cpu.SetLimit(config.CPU / 100)
l.cpuEnableThrottling = config.Throttling
l.memory.SetLimit(config.Memory)
l.gpu.memory.SetLimit(config.GPUMemory)
l.gpu.usage.SetLimit(config.GPUUsage / 100)
l.gpu.encoder.SetLimit(config.GPUEncoder / 100)
@@ -342,7 +347,7 @@ func (l *limiter) Start(process resources.Process) error {
go l.ticker(ctx, time.Second)
if l.mode == LimitModeSoft {
if l.mode == LimitModeSoft && l.cpuEnableThrottling {
go l.limitCPU(ctx, l.cpu.Limit(), time.Second)
}
@@ -407,7 +412,7 @@ func (l *limiter) collect() {
isLimitExceeded := false
if l.mode == LimitModeHard {
if l.mode == LimitModeHard || !l.cpuEnableThrottling {
if l.cpu.IsExceeded(l.waitFor, l.mode) {
l.logger.Warn().Log("CPU limit exceeded")
isLimitExceeded = true

View File

@@ -58,6 +58,7 @@ type Config struct {
StaleTimeout time.Duration // Kill the process after this duration if it doesn't produce any output.
Timeout time.Duration // Kill the process after this duration.
LimitCPU float64 // Kill the process if the CPU usage in percent is above this value, in percent 0-100 in hard mode, 0-100*ncpu in soft mode.
Throttling bool // Whether to allow CPU throttling
LimitMemory uint64 // Kill the process if the memory consumption in bytes is above this value.
LimitGPUUsage float64 // Kill the process if the GPU usage in percent is above this value, in percent 0-100.
LimitGPUEncoder float64 // Kill the process if the GPU encoder usage in percent is above this value, in percent 0-100.
@@ -312,6 +313,7 @@ func New(config Config) (Process, error) {
limits, err := NewLimiter(LimiterConfig{
CPU: config.LimitCPU,
Throttling: config.Throttling,
NCPU: ncpu,
Memory: config.LimitMemory,
GPUUsage: config.LimitGPUUsage,