#401 nice cpu limit

This commit is contained in:
Maveno
2024-11-12 20:55:30 +01:00
parent 8c7eee580d
commit 1d4507782b
7 changed files with 59 additions and 15 deletions

View File

@@ -153,11 +153,15 @@ def getUnmuxSequence(trackDescriptor: TrackDescriptor, sourcePath, targetPrefix,
@click.option('-l', '--label', type=str, default='', help='Label to be used as filename prefix') @click.option('-l', '--label', type=str, default='', help='Label to be used as filename prefix')
@click.option("-o", "--output-directory", type=str, default='') @click.option("-o", "--output-directory", type=str, default='')
@click.option("-s", "--subtitles-only", is_flag=True, default=False) @click.option("-s", "--subtitles-only", is_flag=True, default=False)
@click.option('--nice', type=int, default=99, help='Niceness of started processes')
@click.option('--cpu', type=int, default=0, help='Limit CPU for started processes to percent')
def unmux(ctx, def unmux(ctx,
paths, paths,
label, label,
output_directory, output_directory,
subtitles_only): subtitles_only,
nice,
cpu):
existingSourcePaths = [p for p in paths if os.path.isfile(p)] existingSourcePaths = [p for p in paths if os.path.isfile(p)]
ctx.obj['logger'].debug(f"\nUnmuxing {len(existingSourcePaths)} files") ctx.obj['logger'].debug(f"\nUnmuxing {len(existingSourcePaths)} files")
@@ -195,7 +199,7 @@ def unmux(ctx,
if unmuxSequence: if unmuxSequence:
if not ctx.obj['dry_run']: if not ctx.obj['dry_run']:
ctx.obj['logger'].debug(f"Executing unmuxing sequence: {' '.join(unmuxSequence)}") ctx.obj['logger'].debug(f"Executing unmuxing sequence: {' '.join(unmuxSequence)}")
out, err, rc = executeProcess(unmuxSequence) out, err, rc = executeProcess(unmuxSequence, niceness=nice, cpu_percent=cpu)
if rc: if rc:
ctx.obj['logger'].error(f"Unmuxing of stream {trackDescriptor.getIndex()} failed with error ({rc}) {err}") ctx.obj['logger'].error(f"Unmuxing of stream {trackDescriptor.getIndex()} failed with error ({rc}) {err}")
else: else:
@@ -314,6 +318,9 @@ def checkUniqueDispositions(context, mediaDescriptor: MediaDescriptor):
@click.option("--no-signature", is_flag=True, default=False) @click.option("--no-signature", is_flag=True, default=False)
@click.option("--keep-mkvmerge-metadata", is_flag=True, default=False) @click.option("--keep-mkvmerge-metadata", is_flag=True, default=False)
@click.option('--nice', type=int, default=99, help='Niceness of started processes')
@click.option('--cpu', type=int, default=0, help='Limit CPU for started processes to percent')
def convert(ctx, def convert(ctx,
paths, paths,
label, label,
@@ -360,7 +367,10 @@ def convert(ctx,
dont_pass_dispositions, dont_pass_dispositions,
no_prompt, no_prompt,
no_signature, no_signature,
keep_mkvmerge_metadata): keep_mkvmerge_metadata,
nice,
cpu):
"""Batch conversion of audiovideo files in format suitable for web playback, e.g. jellyfin """Batch conversion of audiovideo files in format suitable for web playback, e.g. jellyfin
Files found under PATHS will be converted according to parameters. Files found under PATHS will be converted according to parameters.
@@ -387,6 +397,12 @@ def convert(ctx,
context['no_signature'] = no_signature context['no_signature'] = no_signature
context['keep_mkvmerge_metadata'] = keep_mkvmerge_metadata context['keep_mkvmerge_metadata'] = keep_mkvmerge_metadata
context['resource_limits'] = {}
context['resource_limits']['niceness'] = nice
context['resource_limits']['cpu_percent'] = cpu
context['denoiser'] = NlmeansController(parameters = denoise, context['denoiser'] = NlmeansController(parameters = denoise,
strength = denoise_strength, strength = denoise_strength,
patchSize = denoise_patch_size, patchSize = denoise_patch_size,

View File

@@ -43,6 +43,10 @@ class FfxController():
self.__configurationData = self.__context['config'].getData() self.__configurationData = self.__context['config'].getData()
# Convenience
self.__niceness = self.__context['resource_limits']['niceness'] if 'resource_limits' in self.__context.keys() and 'niceness' in self.__context['resource_limits'].keys() else 99
self.__cpuPercent = self.__context['resource_limits']['cpu_percent'] if 'resource_limits' in self.__context.keys() and 'cpu_percent' in self.__context['resource_limits'].keys() else 0
self.__logger = context['logger'] self.__logger = context['logger']
@@ -268,7 +272,7 @@ class FfxController():
self.__logger.debug(f"FfxController.runJob() commandSequence:{' '.join(commandSequence)}") self.__logger.debug(f"FfxController.runJob() commandSequence:{' '.join(commandSequence)}")
if not self.__context['dry_run']: if not self.__context['dry_run']:
executeProcess(commandSequence) executeProcess(commandSequence, niceness=self.__niceness, cpu_percent=self.__cpuPercent)
if videoEncoder == VideoEncoder.VP9: if videoEncoder == VideoEncoder.VP9:
@@ -296,7 +300,7 @@ class FfxController():
os.remove(FfxController.TEMP_FILE_NAME) os.remove(FfxController.TEMP_FILE_NAME)
if not self.__context['dry_run']: if not self.__context['dry_run']:
executeProcess(commandSequence1) executeProcess(commandSequence1, niceness=self.__niceness, cpu_percent=self.__cpuPercent)
commandSequence2 = (commandTokens commandSequence2 = (commandTokens
+ self.__targetMediaDescriptor.getImportFileTokens() + self.__targetMediaDescriptor.getImportFileTokens()
@@ -318,7 +322,7 @@ class FfxController():
self.__logger.debug(f"FfxController.runJob() commandSequence2:{' '.join(commandSequence2)}") self.__logger.debug(f"FfxController.runJob() commandSequence2:{' '.join(commandSequence2)}")
if not self.__context['dry_run']: if not self.__context['dry_run']:
out, err, rc = executeProcess(commandSequence2) out, err, rc = executeProcess(commandSequence2, niceness=self.__niceness, cpu_percent=self.__cpuPercent)
if rc: if rc:
raise click.ClickException(f"Command resulted in error: rc={rc} error={err}") raise click.ClickException(f"Command resulted in error: rc={rc} error={err}")
@@ -345,4 +349,4 @@ class FfxController():
str(length), str(length),
path] path]
out, err, rc = executeProcess(commandTokens) out, err, rc = executeProcess(commandTokens, niceness=self.__niceness, cpu_percent=self.__cpuPercent)

View File

@@ -1,9 +1,29 @@
import subprocess import subprocess, click
from typing import List from typing import List
def executeProcess(commandSequence: List[str], directory: str = None): def executeProcess(commandSequence: List[str], directory: str = None, niceness: int = 99, cpu_percent: int = 0):
# process = subprocess.Popen([t.encode('utf-8') for t in commandSequence], stdout=subprocess.PIPE, stderr=subprocess.PIPE) """
process = subprocess.Popen(commandSequence, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8', cwd = directory) niceness -20 bis +19
cpu_percent: 1 bis 99
"""
nice = int(niceness)
cpu = int(cpu_percent)
click.echo(f"nice {nice} cpu {cpu}")
niceSequence = []
if nice >= -20 and nice <= 19:
niceSequence += ['nice', '-n', str(nice)]
if cpu >= 1 and cpu <= 99:
niceSequence += ['cpulimit', '-l', str(cpu), '--']
niceCommand = niceSequence + commandSequence
click.echo(f"executeProcess(): {' '.join(niceCommand)}")
process = subprocess.Popen(niceCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8', cwd = directory)
output, error = process.communicate() output, error = process.communicate()
# return output.decode('utf-8'), error.decode('utf-8'), process.returncode
return output, error, process.returncode return output, error, process.returncode

View File

@@ -103,6 +103,10 @@ class Scenario():
self._testDbFilePath = os.path.join(self._testDirectory, 'test.db') self._testDbFilePath = os.path.join(self._testDirectory, 'test.db')
self.createEmptyTestDatabase() self.createEmptyTestDatabase()
# Convenience
self._niceness = self._context['resource_limits']['niceness'] if 'resource_limits' in self._context.keys() and 'niceness' in self._context['resource_limits'].keys() else 99
self._cpuPercent = self._context['resource_limits']['cpu_percent'] if 'resource_limits' in self._context.keys() and 'cpu_percent' in self._context['resource_limits'].keys() else 99
def createEmptyTestDatabase(self): def createEmptyTestDatabase(self):

View File

@@ -118,7 +118,7 @@ class Scenario1(Scenario):
self._logger.debug(f"{variantLabel}: Test sequence: {commandSequence}") self._logger.debug(f"{variantLabel}: Test sequence: {commandSequence}")
out, err, rc = executeProcess(commandSequence, directory = self._testDirectory) out, err, rc = executeProcess(commandSequence, directory = self._testDirectory, niceness=self._niceness, cpu_percent=self._cpuPercent)
if out and self._context['verbosity'] >= 9: if out and self._context['verbosity'] >= 9:
self._logger.debug(f"{variantLabel}: Process output: {out}") self._logger.debug(f"{variantLabel}: Process output: {out}")

View File

@@ -103,7 +103,7 @@ class Scenario2(Scenario):
self._logger.debug(f"{variantLabel}: Test sequence: {commandSequence}") self._logger.debug(f"{variantLabel}: Test sequence: {commandSequence}")
out, err, rc = executeProcess(commandSequence, directory = self._testDirectory) out, err, rc = executeProcess(commandSequence, directory = self._testDirectory, niceness=self._niceness, cpu_percent=self._cpuPercent)
if out and self._context['verbosity'] >= 9: if out and self._context['verbosity'] >= 9:
self._logger.debug(f"{variantLabel}: Process output: {out}") self._logger.debug(f"{variantLabel}: Process output: {out}")

View File

@@ -187,7 +187,7 @@ class Scenario4(Scenario):
self._logger.debug(f"{variantLabel}: Test sequence: {commandSequence}") self._logger.debug(f"{variantLabel}: Test sequence: {commandSequence}")
out, err, rc = executeProcess(commandSequence, directory = self._testDirectory) out, err, rc = executeProcess(commandSequence, directory = self._testDirectory, niceness=self._niceness, cpu_percent=self._cpuPercent)
if out and self._context['verbosity'] >= 9: if out and self._context['verbosity'] >= 9:
self._logger.debug(f"{variantLabel}: Process output: {out}") self._logger.debug(f"{variantLabel}: Process output: {out}")