diff --git a/bin/ffx.py b/bin/ffx.py index 0bc86ca..8c81b70 100755 --- a/bin/ffx.py +++ b/bin/ffx.py @@ -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("-o", "--output-directory", type=str, default='') @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, paths, label, output_directory, - subtitles_only): + subtitles_only, + nice, + cpu): existingSourcePaths = [p for p in paths if os.path.isfile(p)] ctx.obj['logger'].debug(f"\nUnmuxing {len(existingSourcePaths)} files") @@ -195,7 +199,7 @@ def unmux(ctx, if unmuxSequence: if not ctx.obj['dry_run']: 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: ctx.obj['logger'].error(f"Unmuxing of stream {trackDescriptor.getIndex()} failed with error ({rc}) {err}") else: @@ -314,6 +318,9 @@ def checkUniqueDispositions(context, mediaDescriptor: MediaDescriptor): @click.option("--no-signature", 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, paths, label, @@ -360,7 +367,10 @@ def convert(ctx, dont_pass_dispositions, no_prompt, no_signature, - keep_mkvmerge_metadata): + keep_mkvmerge_metadata, + + nice, + cpu): """Batch conversion of audiovideo files in format suitable for web playback, e.g. jellyfin Files found under PATHS will be converted according to parameters. @@ -387,6 +397,12 @@ def convert(ctx, context['no_signature'] = no_signature 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, strength = denoise_strength, patchSize = denoise_patch_size, diff --git a/bin/ffx/ffx_controller.py b/bin/ffx/ffx_controller.py index fed41e0..f1e28ba 100644 --- a/bin/ffx/ffx_controller.py +++ b/bin/ffx/ffx_controller.py @@ -43,6 +43,10 @@ class FfxController(): 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'] @@ -268,7 +272,7 @@ class FfxController(): self.__logger.debug(f"FfxController.runJob() commandSequence:{' '.join(commandSequence)}") if not self.__context['dry_run']: - executeProcess(commandSequence) + executeProcess(commandSequence, niceness=self.__niceness, cpu_percent=self.__cpuPercent) if videoEncoder == VideoEncoder.VP9: @@ -296,7 +300,7 @@ class FfxController(): os.remove(FfxController.TEMP_FILE_NAME) if not self.__context['dry_run']: - executeProcess(commandSequence1) + executeProcess(commandSequence1, niceness=self.__niceness, cpu_percent=self.__cpuPercent) commandSequence2 = (commandTokens + self.__targetMediaDescriptor.getImportFileTokens() @@ -318,7 +322,7 @@ class FfxController(): self.__logger.debug(f"FfxController.runJob() commandSequence2:{' '.join(commandSequence2)}") 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: raise click.ClickException(f"Command resulted in error: rc={rc} error={err}") @@ -345,4 +349,4 @@ class FfxController(): str(length), path] - out, err, rc = executeProcess(commandTokens) + out, err, rc = executeProcess(commandTokens, niceness=self.__niceness, cpu_percent=self.__cpuPercent) diff --git a/bin/ffx/process.py b/bin/ffx/process.py index 23e7802..805c4b1 100644 --- a/bin/ffx/process.py +++ b/bin/ffx/process.py @@ -1,9 +1,29 @@ -import subprocess +import subprocess, click from typing import List -def executeProcess(commandSequence: List[str], directory: str = None): - # 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) +def executeProcess(commandSequence: List[str], directory: str = None, niceness: int = 99, cpu_percent: int = 0): + """ + 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() - # return output.decode('utf-8'), error.decode('utf-8'), process.returncode + return output, error, process.returncode diff --git a/bin/ffx/test/scenario.py b/bin/ffx/test/scenario.py index 70f67ff..965e463 100644 --- a/bin/ffx/test/scenario.py +++ b/bin/ffx/test/scenario.py @@ -103,6 +103,10 @@ class Scenario(): self._testDbFilePath = os.path.join(self._testDirectory, 'test.db') 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): diff --git a/bin/ffx/test/scenario_1.py b/bin/ffx/test/scenario_1.py index 2aa0c1b..9778715 100644 --- a/bin/ffx/test/scenario_1.py +++ b/bin/ffx/test/scenario_1.py @@ -118,7 +118,7 @@ class Scenario1(Scenario): 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: self._logger.debug(f"{variantLabel}: Process output: {out}") diff --git a/bin/ffx/test/scenario_2.py b/bin/ffx/test/scenario_2.py index fd5964d..2045eb0 100644 --- a/bin/ffx/test/scenario_2.py +++ b/bin/ffx/test/scenario_2.py @@ -103,7 +103,7 @@ class Scenario2(Scenario): 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: self._logger.debug(f"{variantLabel}: Process output: {out}") diff --git a/bin/ffx/test/scenario_4.py b/bin/ffx/test/scenario_4.py index 48dc7f1..e21a620 100644 --- a/bin/ffx/test/scenario_4.py +++ b/bin/ffx/test/scenario_4.py @@ -187,7 +187,7 @@ class Scenario4(Scenario): 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: self._logger.debug(f"{variantLabel}: Process output: {out}")