The prewarm's single big read (a ~14 min sequential pass over a 60GB remux to demux subtitles) shares the same disk/NFS as live streaming. Lower the prewarm ffmpeg processes to the Linux IDLE I/O class (ioprio_set) so that background read yields bandwidth to a user who's actually watching — the prewarm slows down under contention instead of starving playback, and runs full speed when the disk is idle. Applied only to the prewarm-only extractors (ExtractSubtitlesVTTMulti, ExtractThumbnailJPEG) via Start → setIdleIOPriority(pid) → Wait; the on-demand /sub + /thumbnail handlers keep normal priority (a user is waiting on those). Linux-only syscall behind a build tag; a no-op stub elsewhere. Best-effort — errors ignored, never required for correctness. Verified: the prewarm ffmpeg shows 'idle' under ionice -p; on-demand stays normal.
25 lines
1 KiB
Go
25 lines
1 KiB
Go
//go:build linux
|
|
|
|
package mediainfo
|
|
|
|
import "syscall"
|
|
|
|
// Linux I/O priority (ioprio) constants. The 16-bit ioprio value packs a class
|
|
// in the top 3 bits (shift 13) and a class-data nibble below it; the IDLE class
|
|
// takes no data.
|
|
const (
|
|
ioprioWhoProcess = 1 // IOPRIO_WHO_PROCESS
|
|
ioprioClassIdle = 3 // IOPRIO_CLASS_IDLE
|
|
ioprioClassShift = 13
|
|
)
|
|
|
|
// setIdleIOPriority best-effort lowers a process's I/O scheduling class to IDLE,
|
|
// so a long background read (the subtitle prewarm of a huge remux — a single
|
|
// ~14 min sequential read of a 60GB file over NFS) yields disk/NFS bandwidth to
|
|
// foreground work like live streaming. Linux-only; on kernels or filesystems
|
|
// that don't honor ioprio this simply has no effect. Errors are intentionally
|
|
// ignored — it's an optimization, never required for correctness.
|
|
func setIdleIOPriority(pid int) {
|
|
ioprio := ioprioClassIdle << ioprioClassShift // IDLE class, data 0
|
|
_, _, _ = syscall.Syscall(syscall.SYS_IOPRIO_SET, uintptr(ioprioWhoProcess), uintptr(pid), uintptr(ioprio))
|
|
}
|