Mostrando entradas con la etiqueta paralelización. Mostrar todas las entradas
Mostrando entradas con la etiqueta paralelización. Mostrar todas las entradas

viernes, 3 de julio de 2009

Copias Subversion - Paralelizando procesos

Hace unos días comenté algo acerca del procesamiento paralelo en bash.


Hoy he tenido que hacer un pequeño script para realizar unos dump de subversion, y al medir tiempos por temas de ventanas de copias, me he encontrado con que el proceso de realizar las copias de todos mis repos consumía un tiempo de aproximadamente 2.30h, lo cual me ha dejado un poco mosca al irme a casa.


No se pero se me había metido en la cabeza que podía ser más rápido, y una cosa a llevado a la otra y al final he acabado pensando en la posibilidad de lanzar estos scripts en paralelo, lo cual tiene gracia ya que la máquina en cuestión tiene un solo core ;) (Por lo que la ganancia sería 0) pero bueno me ha dado por darle vueltas al tema.


Así que me he puesto y al final he hecho otro script, en el que si tengo presente el número de cores disponibles.


No he podido probarlo, pero intentaré hacerlo en breve montando alguna maquena en VirtualBox. (Cuando tenga tiempo y ganas ;))


Estos son los scripts que repito. No se si funciona el segundo de ellos, pero como ejemplo del anterior post creo que es valido.


Script sin paralelización:

#Definimos el array que contendrá los repos

typeset -a A_REPOS

#Obtenemos el numero de repos (Directorios, sin el directorio de copias ni el "." o el "..")

let NUM_REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1|wc -l`

#Obtenemos una lista de los repos

REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1`

let num=1


#Llenamos el array con los elementos de la lista de repos

while [ $num -le $NUM_REPOS ]; do

A_REPOS[$num]=`echo $REPOS|tr -s ' ' |cut -d ' ' -f $num`

let num=num+1

done


num=1

#Para cada posicion del array lanzamos un dump

while [ $num -le $NUM_REPOS ]; do

#echo ${A_REPOS[$num]}

svnadmin dump ${A_REPOS[$num]}|gzip -9 > ${A_REPOS[$num]}".gz"

let num=num+1

done


Script con paralelización:

#Definimos el array que contendrá los repos

typeset -a A_REPOS

#Obtenemos el numero de repos (Directorios, sin el directorio de copias ni el "." o el "..")

let NUM_REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1|wc -l`

#Obtenemos una lista de los repos

REPOS=`ls -l|grep "drwx"|grep -v "DUMP_BACKS"|tr -s ' ' |cut -d ' ' -f 9|tr -s '.'|cut -d '.' -f 1`

let num=1

#Definimos el numero de procesadores de muestra maquina

let PMAX=(`ls -ld /sys/devices/system/cpu/cpu*|wc -l`)-1

#definimos un array con el numero de cores

typeset REPOS_CORE[$PMAX]


#Llenamos el array con los elementos de la lista de repos

while [ $num -le $NUM_REPOS ]; do

A_REPOS[$num]=`echo $REPOS|tr -s ' ' |cut -d ' ' -f $num`

let num=num+1

done


num=1

pos=1

while [ $num -le $NUM_REPOS ]; do

#Llenamos un array con tantos elementos como procesadores
REPOS_CORE[$pos]=${A_REPOS[$num]}

#Cuando esta lleno lanzamos los procesos y colocamos la posicion a 1 para volver a llenarlo
if [ $pos -eq $PMAX ] then

for i in REPO_CORE; do

svnadmin dump $i|gzip -9 > $i."gz" &

pos=0

wait

done

fi

let num=num+1

let pos=pos+1

done


Los colores indican las diferencias entre uno y otro.

Básicamente cuando tenemos el array con los nombres de los repos, vamos llenando otro hasta tener tantos elementos como cores, en ese momento lanzamos todos los dump y colocamos la posición, a 0 para que se coloque a 1, y repetir el proceso.

De este modo conseguimos lanzar varios dump al mismo tiempo, con lo que con el tiempo del mayor, realizaremos los demás. (Creo)

NOTA: Repito y no me cansaré de hacerlo ;), que el segundo script NO ESTÁ TESTEADO, básicamente es una idea que pienso que puede funcionar.

martes, 23 de junio de 2009

Bash Script con varios nucleos - Parelelizando

Hace unos dias lei un árticulo sobre este tema en LinuxMagazine el cual me pareció de lo más interesante.
La verdad es que hasta ese momento no se me había pasado por la cabeza la posibilidad de explotar la potencia de varios cores en un script bash.

Cuando paralelizar script?
Este es para mi el punto mas importante a tener en cuenta, ya que aunque podríamos vernos tentados a paralelizar a diestro y siniestro, no siempre nos aportará beneficios, es más en determinadas ocasiones supondrá una pérdida de rendimiento.
No es mi intención explicar el concepto de procesamiento paralelo, simplemente mencionar que a menos que el proceso que estemos ejecutando suponga una carga muy alta para un core, no es recomendable, ya que el coste de cambiar de core será mayor que la ganancia obtenida.
Una manera de saber si para nuestro proceso es "rentable" o no, sería ver la salida del comando sar.

En mi caso tengo ejecutandose un find en la maquina:

#find / -name "*".jpg"*"

En una segunda consola miro el consumo de cpu:

#sar -u -P ALL 1 0

Obteniendo salidas como esta:
00:36:34 CPU %user %nice %system %iowait %steal %idle
00:36:35 all 0,95 0,00 1,65 22,22 0,00 75,18
00:36:35 0 1,96 0,00 3,92 76,47 0,00 17,65
00:36:35 1 0,95 0,00 2,86 15,24 0,00 80,95
00:36:35 2 0,89 0,00 0,89 0,00 0,00 98,21
00:36:35 3 0,00 0,00 0,00 0,00 0,00 100,00


Como podemos observar, el procesador "0" esta trabajando mucho más que el resto y sería un candidato para el tema que nos ocupa de ser porque el consumo se debe a operaciones I/O, lo cual hace que no sea buena idea, ya que no es trabajo propiamente del procesador. Otro caso seria si la mayor parte del trabajo fuera en la columna "user" Dicho esto, una vez hayamos decidido si es o no oportuno, comenzamos a paralelizar nuestro script.


1.- Este ejemplo es el más agresivo ya que podría provocar un incremento de procesos en la máquina y un consumo de memoria capaz de dejarla frita.
Para cada orden de nuestro bucle se inicia un proceso distinto, y luego se espera q que todos los procesos hayan finalizado.

funcion(){
for i in XXX do
loquesea $i &
done
wait
}

2.- Este ejemplo intenta distribuir argumentos para la ejecución de procesos, según el número de procesadores de nuestra máquina.(Para que el número total de procesos no aumente demasiado)
Este procesamiento es adecuado siempre que el consumo de cpu sea similar entre procesos ya que si no, podría darse el caso de que todos los procesos con consumo alto recayeran sobre la misma cpu, con lo que no habríamos conseguida nada
Este problema lo tendremos siempre que no hagamos una selección de procesadores en función de su carga.

#Definimos nuestro numero de procesadores

let PMAX=(`ls -ld /sys/devices/system/cpu/cpu*|wc -l`)-1

funcion(){

procesadores=0

#Recorremos la entrada de parametros a procesar

for i in XXX do

#Cada parametro lo añadimos al vector final

items[$procesadores]="${items[procesadores]} \"$i\""

shift

#Modificamos la posicion actual entre 0 y PMAX-1

let procesadores=$((procesadores+1)%PMAX)

done

#Con todos los argumentos en nuestro vector, lanzamos PAMX procesos, con la ejecucion

#de estos parametros

for (procesadores=0 procesadoresdo"<"PMAX procesadores++)

ejecucionXXX

done

wait