Pages : 1
#1 Le 30/01/2009, à 21:13
- Totor
Tirer partie de ses coeurs
A la recherche d'un moyen d'affecter (en bash) un processus à l'un des 4 coeurs de mon processeur (AMD Phenom 9950) pour ré-encoder plusieurs fichiers avi au format mp4 en même temps. J'ai "plus ou moins" trouvé la solution à la lecture de cette page. Il me semble judicieux de la lire pour comprendre la suite.
"plus ou moins" : oui car il en découle qu'un processus n'est affecté qu'à un cœur. Non, car je ne peux pas choisir le coeur.
Toujours est-il que le principe de cet article m'a plu mais il m'a semblait perfectible. En effet, le principe de la meilleure solution proposée est de lancer 2 scripts de ré-encodage en parallèle (car 2 coeurs). Le premier réencodant les fichiers en position impaire passés en argument d'un script principale. Le 2nd script, réencodant les fichiers en position paire passés en argument du script principale.
A y réfléchir, le traitement des fichiers "paires" peut-être bien plus long que le réencodage des fichiers "impaires". Et vice-versa. En conséquence, l'un des 2 coeurs, sera plus utilisé que l'autre.
C'est pourquoi la solution est perfectible. Et pour cela il suffirait de lancer autant de processus de ré-encodage qu'il y a de coeurs et dès que l'un de ces processus est terminé, lancer un nouveau processus avec le fichier suivant passé en argument du script.
J'ai donc écris ce script "paralleliseur.sh" que je vous fais partager car je pense qu'il pourra vous être utile.
Attention, la moindre modification pour avoir un impacte important sur le rôle qu'il doit jouer !
#!/bin/bash
set -mb
export commence=0
function lanceur
{
"${1}" "${2}"
}
function fin_process
{
if [[ ${num_args} -le ${#args[*]} && ${commence} -eq 1 ]]; then
lanceur "${tache}" "${args[${num_args}]}" &
num_args=$((num_args+1))
fi
}
nb_proc=$(grep -c 'processor[[:blank:]]*:.*' /proc/cpuinfo)
export tache="$1"
export num_args=1
for ((index=2;index<=$#;index++))
do
args[$((index-1))]=${!index}
done
export args
trap "fin_process" SIGCHLD
# on lance autant de process qu'il y a de processeur/coeur
for(( num_proc=1 ; num_proc <= ${nb_proc} ; num_proc++))
do
if [ $num_args -le ${#args[@]} ]; then
commence=1
lanceur "${tache}" "${args[${num_args}]}" &
num_args=$((num_args+1))
fi
done
wait
Son utilisation :
$1 : Script à paralléliser
$2.....$i : liste des arguments à traiter
Pour example :
paralleliseur.sh reencoder.sh ~/divx/album1/saison1/*.avi
script "reencoder.sh" :
#!/bin/bash
source="$1"
debut="$(date +"%k:%M:%S")"
debut_s=$(date +%s)
ffmpeg -threads 4 -y -i "${source}" -r 29.97 -vcodec libxvid -s 640x480 -aspect 16:9 -maxrate 1500k -b 1250k -qmin 3 -qmax 5 -bufsize 4096 -mbd 2 -flags +4mv+trell -aic 2 -cmp 2 -subcmp 2 -g 300 -acodec libfaac -ar 48000 -ab 80k -ac 2 -s 320x240 "${source%.*}.mp4" </dev/null &>/dev/null
fin_s=$(date +%s)
fin="$(date +"%k:%M:%S")"
echo "traitement de ${source} en $((fin_s-debut_s)) secondes (${debut} - ${fin})."
Note : le gain n'est pas en temps de traitement unitaire... mais globale !.
-- Lucid Lynx --
Hors ligne
#2 Le 01/02/2009, à 14:59
- Totor
Re : Tirer partie de ses coeurs
Bonjour,
Ayant trouvé la réponse à ma question initiale qui était : Comment faire tourner une tâche sur un seul processeur, j'ai modifié et amélioré le script.
Pour information, il existe un outil pour changer l'affinité d'un processus avec un processeur : schedtool
#!/bin/bash
#*************************************************************************************************************************
# Nom : paralleliseur.sh *
# Objet : Parallélise en traitement en fonction du nombre de processeur/coeur *
# La tâche à parraléliser est en position 1 des arguments du script. *
# Les arguments > 1 seront successivement passés aux tâches exécutées. Mais un argument ne sera utilisé qu'une seule fois*
# Le principe d'utilisation est à l'identique de xargs à l'exception près : les arguments ne peuvent être lus de l'entrée*
# standard. *
# Ce script est utile lorsq'il est question de traitements lourds à exécuter successivement et lorsque la machine possède*
# au moins 2 processeurs/coeurs. *
#*************************************************************************************************************************
# Version Date Objet *
# 1.0 30/01/2009 Création *
# 1.1 01/02/2009 Utilisation de l'utilitaire schedtool, permettant de positionner les affinités *
#*************************************************************************************************************************
# Dépendances : *
# - schedtool (http://freequaos.host.sk/schedtool/). (V.1.3.0) *
#*************************************************************************************************************************
set -mb
#*************************************************************************************************************************
# Nom : lanceur *
# Objet : exécute la tâche donnée avec l'argument suivant *
#*************************************************************************************************************************
# Version Date Objet *
# 1.0 01/02/2009 Création *
#*************************************************************************************************************************
# paramètres : *
#*************************************************************************************************************************
function lanceur
{
schedtool -a ${no_proc} -e "${tache}" "${args[${num_args}]}" &
# sauvegarde du PID dans le tableau à l'indice du No du processeur avec lequel l'affinité est positionnée
lstPID[${no_proc}]=$!
# incrémentation du No d'argument
num_args=$((num_args+1))
}
#*************************************************************************************************************************
# Nom : fin_process *
# Objet : fonction exécutée lorsqu'un process est terminé dans l'environnement d'exécution en cours. *
#*************************************************************************************************************************
# Version Date Objet *
# 1.0 01/02/2009 Création *
#*************************************************************************************************************************
# paramètres : *
#*************************************************************************************************************************
function fin_process
{
if [[ ${num_args} -le ${#args[@]} && ${commence} -eq 1 ]]; then
# recherche du processeur avec lequel le processus avait une affinité. Si non trouvé, on affecte à tous les processeurs
no_proc="0xf"
for((num_proc=0;num_proc<${nb_proc};num_proc++))
do
if [ -z "$(ps -o state --pid ${lstPID[${num_proc}]} --no-headers)" ]; then
# ce process n'existe plus, avec l'indice no_proc, on en déduit le processeur avec lequel il avait une affinité
no_proc=${num_proc}
fi
done
# on relance avec l'argument suivant
lanceur
fi
}
# précautions d'usage
[ $# -lt 2 ] && { echo "Nombre d'argument incorrecte : $(basename "$0") <tâche> <arg1> <arg2> ... <argn>"; exit 1; }
# recherche du nombre de coeurs/processeurs
nb_proc=$(grep -c 'processor[[:blank:]]*:.*' /proc/cpuinfo)
# sauvegarde des paramétres
for ((index=2;index<=$#;index++))
do
args[$((index-1))]=${!index}
done
export tache="$1"
export num_args=1
export args
export lstPID=
export commence=0
trap "fin_process" SIGCHLD
# on lance autant de process qu'il y a de processeur/coeur
for(( num_proc=1 ; num_proc <= ${nb_proc} ; num_proc++))
do
if [ $num_args -le ${#args[@]} ]; then
# calcul du No du processeur avec lequel l'affinité sera positionnée
no_proc=$((num_proc-1))
# on indique que l'on a commencé à lancer des jobs
commence=1
# exécution de la tâche
lanceur
fi
done
# on attend la fin de tous les processus lancés
wait
Dernière modification par Totor (Le 01/02/2009, à 15:37)
-- Lucid Lynx --
Hors ligne
#3 Le 02/02/2009, à 20:26
- Totor
Re : Tirer partie de ses coeurs
Bon, en fait, la version initiale du script est à mettre à la poubelle
En effet, l'option -P de xargs est là pour ça
...mais l'affinité n'est pas gérer ....
-- Lucid Lynx --
Hors ligne
Pages : 1