\newpage
%===========================================================================
%       x.10 > Clusters HP
%===========================================================================
\pagestyle{empty}
\begin{latexonly}
\ifpdf
 \begin{figure}[htbp]
%      \includegraphics[bb = -250 220 0 0, scale=1]{./TuXes/tux-net.jpg}
 \end{figure}
 \vspace{5in}
\else
 \begin{figure}
%      \includegraphics[-275,650][0,0]{./TuXes/tux-net}
 \end{figure}
\fi
\hfill\line(1,0){400}
\end{latexonly}
\topmargin 1in
\section{CLUSTERS HP}
\begin{latexonly}
\line(1,0){400}
\newpage
\end{latexonly}
\topmargin 0in
\pagestyle{fancy}
%========================cita===============================================
\begin{latexonly}
\hspace{1in}\textcolor{blue_omosix}{{\em The problems that exist in the world today}}

\hspace{1in}\textcolor{blue_omosix}{{\em cannot be solved by the level of thinking that created them.}}

\hspace{4in}\textcolor{blue_omosix}{{\em Albert Einstein}}
\vspace{0.5in}
\end{latexonly}
%===========================================================================
\subsection{Conceptos importantes: migraci\'on y balanceo)}
Los clusters HP est\'an dedicados a dar el mayor rendimiento computacional
posible y existen multitud de formas de implementarlos.

Ha llevado a\~{n}os implementarlos, por tanto a lo largo de la historia
 ha habido todo tipo de ideas para intentar hacerlos lo m\'as eficientes posible.
 En este documento se estudian unas cuantas de estas implementaciones
 (PVM, MPI, Beowulf) y se ahondar\'a en una de ellas: openMosix.

\vspace{.2in}
La primera divisi\'on en las implementaciones puede ser la divisi\'on entre
 las
\begin{itemize}
\item soluciones que funcionan a nivel de aplicaci\'on y 
\item soluciones que funcionan a nivel de kernel.
\end{itemize}
 Las que funcionan a nivel de aplicaci\'on suelen tomar forma de librer\'\i a.
 Se tienen que realizar los programas para que aprovechen esta librer\'\i a
 por lo tanto cualquier programa ya existente para que pueda ser usado en
 un cluster y mejore su rendimiento tiene que ser reescrito al
 menos parcialmente.

 Esto tiene bastantes inconvenientes: muchas de las aplicaciones
 que necesitan grandes tiempos de c\'omputo se realizaron hace d\'ecadas en
 lenguaje Fortran. Este lenguaje aparte de estar relegado hoy en d\'\i a a aplicaciones
 matem\'aticas o f\'\i sicas, puede llegar a ser bastante dif\'\i cil de comprender;
 por lo tanto es bastante dif\'\i cil migrarlo al nuevo entorno distribuido.
 
Por otro lado una de las ventajas que tienen los clusters HP con respecto
 a los supercomputadores es que son bastante m\'as econ\'omicos. Pero si el
 dinero que se ahorra en el hardware hay que invertirlo en cambiar los
 programas esta soluci\'on no aporta beneficios que justifiquen tal
 migraci\'on de equipos. Adem\'as hay que tener en cuenta que la mayor
 parte de las instituciones o instalaciones dom\'esticas no tienen
 dinero para invertir en ese software, pero que s\'\i\ disponen de
 ordenadores en una red (universidades por ejemplo) .

La segunda opci\'on es que el software que se encarga del HP se encuentre
 en el kernel del sistema operativo. En este caso no se necesitan cambiar
 las aplicaciones de usuario, sino que \'estas usan las llamadas est\'andar
 del kernel por lo tanto el kernel internamente es el que se encarga de
 distribuir el trabajo de forma transparente a dicha aplicaci\'on.
 Esto tiene la ventaja de que no hace falta hacer un desembolso en cambiar
 las aplicaciones que lo necesitan y que cualquier aplicaci\'on puede ser
 distribuida. Por supuesto un factor que siempre habr\'a que tener en cuenta es la propia
programaci\'on de la aplicaci\'on.

 Por otro lado esta aproximaci\'on tambi\'en tiene varios inconvenientes: 
 el kernel se vuelve mucho m\'as complejo y es m\'as propenso a fallos.
 Tambi\'en hay que tener en cuenta que estas soluciones son espec\'\i ficas de
 un kernel, por lo que si las aplicaciones no est\'an pensadas para ese sistema
 operativo habr\'\i a que portarlas. Si los sistemas operativos tienen las mismas
 llamadas al sistema, siguiendo un est\'andar POSIX, no habr\'\i a grandes problemas.
 Otros sistemas operativos propietarios que no cumplen estos est\'andares
 no pueden disponer de estas ventajas.
 
Una forma de conseguir HP es migrando procesos, dividiendo las aplicaciones
 grandes en procesos y ejecutando cada proceso en un nodo distinto.
 Lo que se quiere conseguir es el m\'aximo uso de los recursos en todo momento,
 especialmente los procesadores.
 Para conseguirlo hay dos aproximaciones:
\begin{itemize}
  \item {\bf Asignar est\'aticamente cada proceso a un nodo en particular.}

En esta aproximaci\'on
 es important\'\i sima la pol\'\i tica de localizaci\'on.
 Se elige est\'aticamente el nodo donde el proceso vivir\'a toda su vida.
 Por tanto es muy importante elegir correctamente estos nodos.
 Muchas veces esta soluci\'on necesita un administrador que decida d\'onde debe
 ir cada proceso.
 El caso m\'as simple es tener todos los nodos con la misma potencia de c\'alculo
 y dividir el \'unico programa al que se quiera dedicar los recursos en un
 n\'umero de procesos igual al n\'umero de nodos de los que se disponen.
 As\'\i  se asignar\'\i a cada proceso a uno de los nodos.
 Hay que tener en cuenta que esta configuraci\'on es lejana a la normal y
 que ya que un fallo en el algoritmo de elecci\'on de nodo puede infrautilizar
 mucho de los recursos la configuraci\'on manual es normal en estos algoritmos.
 Esto no es tan malo como pueda parecer a primera vista porque es tambi\'en
 muy corriente en estos casos que una vez hecha la configuraci\'on inicial,
 los procesos est\'en ejecut\'andose durante a\~{n}os si es necesario.

  \item {\bf Asignar din\'amicamente procesos a los nodos.}

Los procesos una vez iniciados
 en un nodo pueden migrar a otro nodo din\'amicamente. En estos casos aunque
 es importante la pol\'\i tica de localizaci\'on para minimizar el gasto de recursos,
 tambi\'en es important\'\i sima la pol\'\i tica de migraci\'on.
 Por supuesto tambi\'en se pueden ubicar los procesos manualmente, con la ventaja
 de que se pueden ubicar en cualquier momento durante la vida del proceso.
 Si la pol\'\i tica de migraci\'on es correcta y los procesos tienen una vida
 larga y se ha dividido correctamente la aplicaci\'on, deber\'\i a haber al comienzo
 de la ejecuci\'on de los procesos un periodo de reordenaci\'on de los procesos,
 con varias migraciones, una vez el sistema llegara a una condici\'on estable,
 no deber\'\i an producirse apenas migraciones hasta que los procesos finalizaran.
 Igual que ocurre en el caso anterior, esta configuraci\'on es lejana a la
 habitual, pero al contrario del caso anterior, aqu\'\i  no es necesaria la
 configuraci\'on manual (si el algoritmo de migraci\'on es suficientemente bueno).
 Cuando se desbalancea el sistema \'este se encarga de que se vuelva a balancear,
 de tal forma de que se aprovechen los recursos al m\'aximo.
\end{itemize}
Sobre el balanceo ya se ha hablado en la secci\'on anterior, como se puede
 comprender el correcto balanceo es muy complejo, se puede balancear
 con respecto a una variable (por ejemplo el procesador), pero hacerlo con respecto a
 todo el sistema en conjunto es algo demasiado complejo y el tiempo de c\'omputo
 para hacer las elecciones correctas ser\'\i a muy grande.
 Por tanto estos algoritmos intentan tener un fundamento matem\'atico fuerte
 que intenta minimizar el tiempo de c\'omputo.
 Muchos de estos sistemas usan fundamentos estad\'\i sticos, como por
 ejemplo openMosix.

Como ya se ver\'a con m\'as detalle, openMosix intenta maximizar el uso de todos los recursos.
 Intentar solamente balancear respecto al procesador puede dar
 lugar a decisiones bastante malas, porque se pueden enviar muchos procesos
 que no hagan mucho uso del procesador a uno de los nodos, si estos procesos
 est\'an haciendo entrada/salida y son procesos grandes, es muy posible que
 el nodo empiece a hacer {\em trashing} pues se quedar\'a sin memoria, con lo que
 los procesos no podr\'an ejecutar su funci\'on.
  
En el cuadro se aprecian las posibles formas que existen para clusters. 
 Se muestra este cuadro para que se pueda comprender la cantidad de decisiones
 que se tienen que hacer cuando se implementa un cluster de este tipo y
 as\'\i  se comprender\'a mejor por qu\'e hay tantas implementaciones
 y tan dispares.
\begin{table}
\begin{center}
\begin{tabular}{ | l | l | } \hline
Tema & Problemas que genera \\ \hline \hline
Sin requisa de procesos & Mayor latencia para procesos de alta prioridad \\ \hline
Con requisa de procesos  & Sobrecarga, implementaci\'on compleja  \\ \hline
Balanceo est\'atico  & Mal balanceo de carga  \\ \hline
Balanceo din\'amico  & Sobrecarga, implementaci\'on compelja  \\ \hline
Nivel de aplicaci\'on  & Sobrecarga, falta de informaci\'on  \\ \hline
Nivel de kernel  & Dificultad de implementaci\'on  \\ \hline
Nodos dedicados  & Infrautilizci\'on de recursos  \\ \hline
Nodos comparten espacio  & Se encesita una pl\'\i tica eficiente de localizaci\'on  \\ \hline
Nodos comparten tiempo  & Sobrecarga cambio de contexto  \\ \hline
Scheduling independiente  & P\'erdida de rendimiento  \\ \hline
Scheduling de grupo  & Implementaci\'on compleja  \\ \hline
Con carga externa, quedarse  & P\'erdida de rendimiento en trabajos locales  \\ \hline
Ante carga externa, mgrar  & Sobrecarga de migraci\'on, l\'\i mites de
migraci\'on \\ \hline
\end{tabular}
\caption{Clusters HP. Aspectos de implementaci\'on}
\end{center}
\end{table}
Ya hemos explicado el balanceo est\'atico frente a balanceo din\'amico y el
 nivel de aplicaci\'on frente al nivel de sistema que ser\'an conceptos que
 necesitemos en las pr\'oximas secciones, ahora vamos a explicar las dem\'as
 caracter\'\i sticas.

{\em Requisa} se refiere a poder parar el proceso y coger sus recursos (b\'asicamente
 los registros del procesador y memoria).
 La requisa de los procesos puede existir o no.
 Con requisa no queremos decir hacer requisa de los procesos para migrarlos
 despu\'es, sino simplemente poder hacer requisa de un proceso en cualquier
 momento.
 Cuando un sistema es multitarea normalmente se implementa alg\'un sistema
 de requisa para poder parar procesos y hacer que otros procesos tomen el
 procesador para dar la sensaci\'on al usuario de que todos los procesos se
 est\'an ejecutando concurrentemente.

Si no se implementa requisa, un proceso de baja prioridad puede tomar el
 procesador y otro proceso de alta prioridad no podr\'a tomarlo hasta que
 el proceso de baja prioridad lo ceda a otros procesos.
 Este esquema puede ser injusto con las prioridades y un error en un programa,
 puede llegar a dejar sin funcionar la m\'aquina pues nunca devolver\'\i a el
 control, pero tampoco har\'\i a ning\'un trabajo \'util.
 Adem\'as para sistemas que necesitan tiempo real, simplemente es inaceptable
 que procesos de baja prioridad est\'en dejando a los procesos de tiempo real
 sin tiempo de procesador y quiz\'as con esta latencia extra se est\'e haciendo
 que el sistema no pueda cumplir sus operaciones en tiempo real, haciendo
 que el sistema sea in\'util.
 Hoy en d\'\i a la requisa se implementa al menos a un nivel elemental en casi
 todos los sistemas que necesiten hacer funcionar m\'as de un proceso (por
 no decir todos).
 Algunos sistemas lo que hacen es no esperar a que cumpla un temporizador
 y realizar la requisa sino a esperar que el proceso haga alguna llamada
 al sistema para aprovechar, tomar el procesador y cederlo a otro proceso.
 Esta aproximaci\'on sigue teniendo el problema de que si un proceso maligno
 o mal programado no hace llamadas a sistema porque haya quedado en un bucle,
 nunca se ejecutar\'a nada en ese ambiente.

Si se implementa la requisa hay que tener en cuenta que la implementaci\'on
 m\'as simple que se puede dar (que es la que usan buena parte de los sistemas)
 necesita un temporizador que marque cuando se acab\'o el tiempo del proceso
 y requisar ese proceso para asignar a otro proceso.
 Esto impone una sobre carga pues hay que tratar una interrupci\'on, actualizar
 unas variables para saber cuanto tiempo lleva un proceso trabajando.

Hay una implementaci\'on m\'as compleja que trata de que siempre que haya un
 proceso de una prioridad mayor al que se est\'a ejecutando se quite el procesador
 al proceso y se d\'e el procesador al proceso con mayor prioridad.
 Estos suelen ser sistemas en tiempo real que tambi\'en (ya que se ponen)
 pueden tener otras exigencias como unos tiempos m\'\i nimos de latencia para
 ciertos procesos.
 Para conseguir esto, el kernel no solamente tiene que requisar procesos
 de baja prioridad en favor de los procesos de tiempo real sino que tiene
 que ser capaz de requisar su propio c\'odigo.
 Esto suele significar que casi cualquier porci\'on del c\'odigo del kernel
 se puede ejecutar entre dos instrucciones de este mismo c\'odigo.
 Esto presenta much\'\i simos problemas a la hora de programar, hay que tener
 mucho m\'as cuidado con evitar condiciones de carrera dentro del propio kernel
 que antes por ser c\'odigo no requisable no se pod\'\i an dar.
 Por tanto implementar requisa, puede hacer que un sistema sea tiempo real
 pero complica tremendamente el n\'ucleo del sistema.

Las siguientes tres l\'\i neas en el cuadro tratan sobre los recursos del cluster,
 estos son los nodos.
 Existen tres modos en los que se puede dedicar los nodos del cluster, estos
 modos son:
\begin{itemize}
  \item {\bf Modo dedicado.}

En este modo que es el m\'as simple de todos, solamente un
 trabajo est\'a siendo ejecutado en el cluster en un tiempo dado, y como mucho
 un proceso de este trabajo que se est\'a ejecutando es asignado a un nodo
 en cualquier momento en el que se siga ejecutando el trabajo.
 Este trabajo no liberar\'a el cluster hasta que acabe completamente aunque
 solamente quede un proceso ejecut\'andose en un \'unico nodo.
 Todos los recursos se dedican a este trabajo, como se puede comprender
 f\'acilmente esta forma de uso de un cluster puede llevar a una
 p\'erdida importante de potencia sobre todo si no todos los nodos
 acaban el trabajo al mismo tiempo.
  \item {\bf Modo de divisi\'on en el espacio.}

En este modo, varios trabajos pueden estar
 ejecut\'andose en particiones disjuntas del cluster que no son m\'as que grupos
 de nodos.
 Otra vez como mucho un proceso puede estar asignado a un cluster en un
 momento dado.
 Las particiones est\'an dedicadas a un trabajo, la interconexi\'on y el sistema
 de entrada/salida puede estar compartidos por todos los trabajos, consiguiendo
 un mejor aprovechamiento de los recursos.
 Los grupos de nodos son est\'aticos y los programas necesitan un
 n\'umero espec\'\i fico de nodos para poder ejecutarse, esto lleva a
 dos conclusiones:
   \begin{enumerate}
    \item Puede existir trabajos para los que no haya una divisi\'on lo suficientemente
 grande por lo que non podr\'\i an ser ejecutados
    \item Puede tener un trabajo que solamente aproveche alguno de
 los nodos desperdiciando una divisi\'on de gran cantidad de
 nodos. Para evitar este segundo punto se tienen que usar t\'ecnicas
 para elegir inteligentemente los nodos donde se ejecuten los trabajos, intentando minimizar
 el n\'umero de nodos ociosos.
  \end{enumerate} 
Tambi\'en puede ocurrir que un trabajo muy largo tome los recursos del cluster
 evitando que otros trabajos m\'as r\'apidos acaben, esto consigue aumentar
 la latencia.
 
  \item {\bf Modo de divisi\'on en el tiempo.}

En cada nodo pueden estar ejecut\'andose varios
 procesos a la vez por lo que se solucionan los problemas anteriores.
 Este es el modo m\'as usado normalmente puesto que no tiene tantas restricciones
 como el otro y se puede intentar hacer un equilibrado de carga eligiendo
 correctamente los procesos.
\end{itemize}
Los dos siguientes puntos de la tabla tratan sobre {\em scheduling},
 esta planifiaci\'on solo se da cuando el modo que se ha elegido es el modo de divisi\'on en el
 tiempo.
 
Hay dos tipos de {\em scheduling} en cuanto a clusters se refiere:
\begin{itemize}
  \item {\bf {\em Scheduling }independiente.}

Es el caso m\'as sencillo y
 m\'as implementado, se usa un sistema operativo en cada nodo del
 cluster para hacer {\em scheduling}  de los distintos procesos en un
 nodo tradicional, esto tambi\'en es llamado {\em scheduling} local.
 Sin embargo, el rendimiento de los trabajos paralelos que est\'e llevando
 a cabo el cluster puede verse degradado en gran medida.

 Cuando uno de los procesos del trabajo paralelo quiera hacer cualquier
 tipo de interacci\'on con otro proceso por ejemplo sincronizarse con \'el,
 este proceso puede que no est\'e ejecut\'andose en esos momentos y puede que
 a\'un se tarde un tiempo (dependiente normalmente de su prioridad) hasta
 que se le ejecute por otro cuanto de tiempo.
 Esto quiere decir que el primer proceso tendr\'a que esperar y cuando el
 segundo proceso est\'e listo para interactuar quiz\'as el primer proceso est\'e
 en swap y tenga que esperar a ser elegido otra vez para funcionar.

  \item {\bf {\em Scheduling} de grupo.}

En este tipo se hace {\em
 scheduling} sobre todos los procesos del trabajo a la vez. Cuando uno
 de los procesos est\'a activo, todos los procesos est\'an
 activos. Estudios\footnote{Estudios realizados en Berkeley} han
 demostrado que este tipo de {\em scheduling} puede aumentar el
 rendimiento en uno o dos puntos de magnitud. Los nodos del cluster no
 est\'an perf\'ectamente sincronizados. De hecho, la mayor\'\i a de
 los clusters son sistemas as\'\i ncronos, que no usan el mismo reloj.

Cuando decimos, a todos los procesos se le hace {\em scheduling} a la
 vez, no quiere decir que sea ex\'actamene a la vez. Seg\'un ese mismo
 estudio, seg\'un aumenta la diferencia entre que se elige para
 ejecutarse el primer proceso y el \'ultimo, se pierda rendimiento (se
tarda m\'as en acabar el trabajo). Para conseguir buenos rendimientos
 se tiene que o bien, permitir a los procesos funcionar por mucho
 tiempo de forma continuada o bien que la diferencia entre que un
 proceso se ejecuta y el ultimo se ejecuta es muy peque\~{n}a.

 Pero como se puede comprender, hacer {\em scheduling} en un cluster
 grande, siendo el {\em scheduling} una operaci\'on cr\'\i tica y que
 tiene que estar optimizada al m\'aximo es una operaci\'on bastante
 compleja de lograr, adem\'as se necesita la informaci\'on de los
 nodos para poder tomar buenas decisiones, lo que acaba necesitando redes r\'apidas.
\end{itemize}
Las dos \'ultimas filas tratan de que deben hacer los procesos cuando
 se encuentran que en su nodo local hay otros procesos que provienen
 de otros nodos. Estos pueden venir por alguna pol\'\i tica de
 migraci\'on o porque se est\'e ejecutando el {\em scheduler} de grupo
 del que hemos hablado en el punto anterior. Los trabajos locales
 podr\'\i an tener prioridad sobre trabajos externos, por ejemplo los
 procesos de usuario interactivos donde no queremos que se degrade el
 rendimiento deben mantener mayor prioridad. Hay dos formas de tratar esta situaci\'on:
\begin{itemize}
  \item El trabajo externo migra: si el proceso migra, existe el coste de migraci\'on
 pero el proceso puede ir a un nodo donde se ejecute de forma m\'as eficiente.
  \item El trabajo externo se mantiene en el cluster: si el proceso se mantiene
 en el nodo donde se encuentra se evita la sobrecarga que conlleva la migraci\'on,
 para no afectar a los procesos de ese nodo se les da muy poca prioridad
 o por ejemplo se hace un grupo de procesos especial que son los extenso
 que disponen de menos CPU.
 El problema es que seguramente se ralenticen los procesos tanto locales
 como los externos, sobre todo si es un proceso que necesita frecuentar
 sincronizaciones, comunicaci\'on y acceso a Entrada/Salida.
\end{itemize}
Con una buenas decisiones en este apartado se puede solucionar los problemas
 expuestos.
%===========================================================================
\subsection{PVM y MPI}
%---------------------------------------------------------------------------
\subsubsection{Paso de mensajes}
Tanto PVM como MPI se basan en el concepto de paso de mensajes. Los mensajes
 son pasados entre los procesos para conseguir que se ejecuten de manera
 colaborativa y de forma sincronizada.
 Se ha elegido mensajes pues se puede implementar de forma m\'as o menos efectiva
 en un cluster, los mensajes se pueden enviar en forma de paquete IP y el
 ordenador destino desempaqueta el mensaje y decide a que proceso va dirigido.
 Una vez hecho esto, env\'\i a la informaci\'on al proceso en cuesti\'on.
  MPI en particular se necesita
 conocer de forma b\'asica los mecanismos de paso de mensajes.
 Hay tres mecanismos b\'asicos de paso de mensajes:
\begin{itemize}
  \item {\bf Paso de mensajes s\'\i ncrono.}

Cuando un proceso P ejecuta un env\'\i o s\'\i ncrono
 a un proceso Q, tiene que esperar hasta que el proceso Q ejecuta el correspondiente
 recibo de informaci\'on s\'\i ncrono.
 Ambos procesos no volver\'an del env\'\i o o el recibo hasta que el mensaje est\'a
 a la vez enviado y recibido.

 Cuando el enviar y recibir acaban, el mensaje original puede ser inmediatamente
 sobrescrito por el nuevo mensaje de vuelta y \'este puede ser inmediatamente
 le\'\i do por el proceso que envi\'o originariamente el mensaje.
 No se necesita un buffer extra en el mismo buffer donde se encuentra el
 mensaje de ida, se escribe el mensaje de vuelta.

  \item {\bf Enviar/Recibir bloqueante.}

Un env\'\i o bloqueante es ejecutado cuando un proceso
 lo alcanza sin esperar el recibo correspondiente.
 Esta llamada bloquea hasta que el mensaje es efectivamente enviado, lo
 que significa que el mensaje (el buffer donde se encuentra el mensaje)
 puede ser reescrito sin problemas.
 Cuando la operaci\'on de enviar ha acabado no es necesario que se haya ejecutado
 una operaci\'on de recibir.
 S\'olo sabemos que el mensaje fue enviado, puede haber sido recibido o puede
 estar en un buffer del nodo que lo env\'\i a, o en un buffer de alg\'un lugar
 de la red de comunicaciones o puede que est\'e en el buffer del nodo receptor.

Un recibo bloqueante es ejecutado cuando un proceso lo alcanza, sin esperar
 a su correspondiente env\'\i o.
 Sin embargo no puede acabar sin recibir un mensaje.
 Quiz\'as el sistema est\'e proveyendo un buffer temporal para los mensajes.

  \item {\bf Env\'\i o/recibo no bloqueante.}

Un env\'\i o no bloqueante es ejecutado cuando un
 proceso lo alcanza, sin esperar al recibo.
 Puede acabar inmediatamente tras notificar al sistema que debe enviar el
 mensaje.
 Los datos del mensaje no est\'an necesariamente fuera del buffer del mensaje,
 por lo que es posible incurrir en error si se sobreescriben los datos.

Un recibo no bloqueante es ejecutado cuando un proceso lo alcanza, sin esperar
 el env\'\i o.
 Puede volver inmediatamente tras notificar al sistema que hay un mensaje
 que se debe recibir.
 El mensaje puede que no haya llegado a\'un, puede estar todav\'\i a en transito
 o puede no haber sido enviado a\'un.
\end{itemize} 
%---------------------------------------------------------------------------
\subsubsection{PVM}
PVM es un conjunto de herramientas y librer\'\i as
 que emulan un entorno de prop\'osito general compuesto de nodos interconectados
 de distintas arquitecturas.
 El objetivo es conseguir que ese conjunto de nodos pueda ser usado de forma
 colaborativa para el procesamiento paralelo\footnote{Descripci\'on
 extra\'\i da directamente de la descripci\'on oficial del proyecto.}.

El modelo en el que se basa PVM es dividir las aplicaciones en distintas
 tareas (igual que ocurre con openMosix).
 Son los procesos los que se dividen por las m\'aquinas para aprovechar todos
 los recursos.
 Cada tarea es responsable de una parte de la carga que conlleva esa aplicacion.
 PVM soporta tanto paralelismo en datos, como funcional o una mezcla de
 ambos.

PVM permite que las tareas se comuniquen y sincronicen con las dem\'as tareas
 de la m\'aquina virtual, enviando y recibiendo mensajes, muchas tareas de
 una aplicaci\'on pueden cooperar para resolver un problema en paralelo.
 Cada tarea puede enviar un mensaje a cualquiera de las otras tareas, sin
 l\'\i mite de tama\~{n}o ni de n\'umero de mensajes.

El sistema PVM se compone de dos partes.
 La primera es un demonio, llamado {\bf\em pvmd} que residen en todas los
 nodos que forman parte de la m\'aquina virtual. Cuando un usuario
 quiere ejecutar una aplicaci\'on PVM, primero crea una m\'aquina virtual para arrancar PVM.
 Entonces se puede ejecutar la aplicaci\'on PVM en cualquiera de los nodos.
 Muchos usuarios pueden configurar varias m\'aquinas virtuales aunque se mezclen
 unas con las otras y se pueden ejecutar varias aplicaciones PVM simult\'aneamente.
 Cada demonio es responsable de todas las aplicaciones que se ejecutan en
 su nodo.
 
 As\'\i  el control est\'a totalmente distribuido excepto por un demonio maestro,
 que es el primero que se ejecuto a mano por el usuario, los dem\'as nodos
 fueron iniciados por el maestro y son esclavos.
 En todo momento siempre hay un {\em pvmd} maestro.
 Por tanto la m\'aquina virtual m\'\i nima es de un miembro, el maestro.

La segunda parte del sistema es la {\bf librer\'\i a de PVM}.
 Contiene un repertorio de primitivas que son necesarias para la cooperaci\'on
 entre los procesos o threads de una aplicaci\'on.
 Esta librer\'\i a contiene rutinas para inicializaci\'on y terminaci\'on de tareas,
 env\'\i o y recepci\'on de mensajes, coordinar y sincronizar tareas, broadcast,
 modificar la m\'aquina virtual.

Cuando un usuario define un conjunto de nodos, PVM abstrae toda la complejidad
 que tenga el sistema y toda esa complejidad se ve como un gran computador
 de memoria distribuida llamada m\'aquina virtual.
 Esta m\'aquina virtual es creada por el usuario cuando se comienza la operaci\'on.
 Es un conjunto de nodos elegidos por el usuario.
 En cualquier momento durante la operaci\'on puede elegir nuevos nodos para
 la m\'aquina virtual.
 Esto puede ser de gran ayuda para mejorar la tolerancia a fallos pues se
 tiene unos cuantos nodos de reserva (PVM no tiene migraci\'on) para si alguno
 de los nodos fallara.
 O si se ve que un conjunto de nodos de una determinada red est\'an fallando
 se pueden habilitar nodos de otra red para solucionarlo.
 Para conseguir abstraer toda la complejidad de las diferentes configuraciones,
 soporta la heterogeneidad de un sistema a tres niveles:
\begin{itemize}
  \item Aplicaciones: las subtareas pueden estar hechas para aprovechar las arquitectura
s sobre la que funcionan.
 Por tanto como se puede elegir en que conjunto de nodos se ejecutar\'an unas
 tareas espec\'\i ficas, podemos hacer nuestras aplicaciones con la arquitectura
 al m\'aximo por lo que se puede optimizar y hacer que funcionen aplicaciones
 hechas para arquitecturas espec\'\i ficas con PVM.
 
  \item M\'aquinas: nodos con distintos formatos de datos est\'an soportados, incluyendo
 arquitecturas secuenciales, vectoriales, SMP.
 Abstrae little endian y big endian.
 
  \item Redes: la m\'aquina virtual puede ser interconectada gracias a distintas tecnolog\'\i 
as de red.
 Para PVM, bajo \'el existe una red punto a punto, no fiable y no secuencial.
 Esto abstrae cualquier tecnolog\'\i a de red.
 Utiliza UDP y implementa toda la confiabilidad y todas las dem\'as operaciones
 como broadcast en la propia librer\'\i a PVM.
\end{itemize}
Tiene un conjunto de interfaces que est\'a basado en la observaci\'on de las
 necesidades de la mayor\'\i a de las aplicaciones, que est\'an escritas en C
 y Fortran.
 Los enlaces para C y C++ para la librer\'\i a PVM est\'an implementados como
 funciones, siguiendo las reglas usadas por la mayor\'\i a de los sistemas que
 usan C, incluyendo los sistemas operativos tipo UNIX.
 Los enlaces para Fortran est\'an implementados como subrutinas m\'as que funciones.
 
Todas las tareas est\'an identificadas con un \'unico identificador de tarea
 TID (Task IDentifier).
 Los mensajes son enviados y recibidos por TIDs.
 Son \'unicos en toda la m\'aquina virtual y est\'an determinados por el {\em pvmd}
 local y no se pueden elegir por el usuario.
 Varias funciones devuelven estos TIDs ({\em pvm\_mytid(),
 pvm\_parent()}, {\em etc.})para permitir que las aplicaciones de los
 usuarios conozcan datos de las otras tareas.
 Existen grupos nombrados por los usuarios, que son agrupaciones l\'ogicas
 de tareas.
 Cuando una tarea se une al grupo, a \'esta se le asigna un \'unico n\'umero dentro
 de ese grupo.
 Estos n\'umeros empiezan en 0 y hasta el n\'umero de tareas que disponga el
 grupo.
 Cualquier tarea puede unirse o dejar cualquier grupo en cualquier momento
 sin tener que informar a ninguna otra tarea del grupo.
 Los grupos se pueden superponer y las tareas pueden enviar mensajes multicast
 a grupos de los que no son miembro.

\vspace{.2in}
Cuando una tarea se quiere comunicar con otra ocurren una serie de cosas,
 los datos que la tarea ha enviado con una operaci\'on {\em send}, son
 transferidos a su demonio local quien decodifica el nodo de destino y
 transfiere los datos al demonio destino. Este demonio decodifica la
 tarea destino y le entrega los datos. Este protocolo necesita 3
 transferencias de datos de las cuales solamente una es sobre la red.
 Tambi\'en se puede elegir una pol\'\i tica de encaminado directo (dependiente
 de los recursos disponibles).
 En esta pol\'\i tica tras la primera comunicaci\'on entre dos tareas los datos
 sobre el camino a seguir por los datos son guardados en una cach\'e local.
 Las siguientes llamadas son hechas directamente gracias a esta informaci\'on.
 De esta manera las transferencias se reduce a una transferencia sobre la
 red.
 Para comunicar entre s\'e los demonios {\em pvmd} se usa UDP pues es
 mucho m\'as sencillo, s\'olo consume un descriptor de fichero, y con
 un simple socket UDP se puede comunicar a todos los dem\'as demonios.
Adem\'as es muy sencillo colocar temporizadores sobre UDP para
 detectar fallos de nodo, {\em pvmd} o red.
 La comunicaci\'on entre las tareas y los {\em pvmd} es mediante TCP
 puesto que se necesita tener la seguridad de que los datos llegar\'an.
 En el caso de que s\'olo se haga una trasferencia \'esta es TCP por lo que
 hay que establecer la conexi\'on primero por lo que realmente tampoco es
 tan beneficioso.
 En la siguiente figura se puede observar como los distintos m\'etodos de
 comunicaci\'on de PVM.
\begin{latexonly}
\ifpdf
        \begin{figure}[htbp]
        \includegraphics[bb = -250 300 0 0, scale=.5]{./pics/hp_pvm.png}
        \vspace{2.5in}
        \caption{Clusters HP. Comunicaciones en PVM}
        \end{figure}
\else
\end{latexonly}
        \begin{figure}
        \centering
        \includegraphics{pics/hp_pvm}
        \caption{Clusters HP. Comunicaciones en PVM}
        \end{figure}
\begin{latexonly}
\fi
\end{latexonly}

\vspace{.2in}
Cada nodo tiene una estructura llamada {\tt host table}.
 Esta tabla tiene una entrada ({\tt host descriptor}) por cada nodo de la m\'aquina
 virtual.
 El descriptor del nodo mantiene la informaci\'on de la configuraci\'on del
 host, las colas de paquetes y los buffer de mensajes.
 Inicialmente la tabla s\'olo tiene la entrada del nodo maestro.
 Cuando un nuevo esclavo es incluido a la m\'aquina virtual, la tabla del
 nodo maestro es actualizado para a\~{n}adir al nuevo esclavo.
 Entonces esta nueva informaci\'on es enviada por broadcast a todos los nodos
 que pertenezcan a la m\'aquina virtual.
 De esta manera se actualizan todas las tablas y se mantienen consistentes.

Las aplicaciones pueden ver el hardware como una colecci\'on de elementos
 de proceso virtuales sin atributos o pueden intentar explotar las capacidades
 de m\'aquinas espec\'\i ficas, intentando posicionar ciertas tareas en los nodos
 m\'as apropiados para ejecutarlas.
 
Hemos querido dar un r\'apido repaso a PVM para poder decir qu\'e es lo que
 no nos gusta de su aproximaci\'on y porque pensamos que openMosix es superior.
 Sabemos que la explicaci\'on que hemos dado est\'a lejos de mostrar todo el
 universo de PVM pero pensamos que puede dar una idea de c\'omo funciona.
 
PVM no tiene requisa de procesos din\'amico, esto quiere decir que una vez
 que un proceso empieza en una determinada m\'aquina seguir\'a en ella hasta
 que se muera.
 Esto tiene graves inconvenientes como explicamos en las caracter\'\i sticas
 de asignar est\'aticamente un proceso a un nodo en concreto.
 Hay que tener en cuenta que las cargas suelen variar y que, a no ser que
 todos los procesos que se est\'en ejecutando sean muy homog\'eneos entre s\'\i ,
 se est\'a descompensando el cluster.
 Por lo tanto tenemos unos nodos m\'as cargados que otros y seguramente unos
 nodos terminen su ejecuci\'on antes que otros, con lo que se podr\'\i an tener
 nodos muy cargados mientras otros nodos est\'an libres.
 Esto lleva a una p\'erdida de rendimiento general.

Otro problema de PVM es que est\'a implementado a nivel de usuario, esto no
 es malo de por s\'\i\  pero teniendo en cuenta el tipo de operaciones que lleva,
 s\'\i  lo es puesto que son operaciones de bastante bajo nivel como puedan
 ser paso de mensajes entre aplicaciones y la capa sobre UDP.
 Esto a\~{n}ade complejidad y latencia a las comunicaciones que se tienen que
 producir sobre las comunicaciones del kernel.
 Por lo que es una capa de software extra que carga bastante.

Se necesita un conocimiento amplio del sistema, tanto los programadores
 como los administradores tienen que conocer el sistema para sacar el m\'aximo
 rendimiento de \'el.
 No existe un programa que se ejecute de forma ideal en cualquier arquitectura
 ni configuraci\'on de cluster.
 Por lo tanto para paralelizar correcta y eficazmente se necesita que los
 programadores y administradores conozcan a fondo el sistema.

El paralelismo es expl\'\i cito, esto quiere decir que se programa de forma
 especial para poder usar las caracter\'\i sticas especiales de PVM.
 Los programas deben ser reescritos.
 Si a esto se unimos que, como se necesita que los desarrolladores est\'en
 bien formados por lo explicado en el punto anterior y que conozcan adem\'as
 PVM, se puede decir que migrar una aplicaci\'on a un sistema PVM no es nada
 econ\'omico.
 %---------------------------------------------------------------------------
\subsubsection{MPI}
MPI es una especificaci\'on est\'andar para una librer\'\i a de funciones de paso
 de mensajes.
 MPI fue desarrollado por el {\em MPI Forum}, un consorcio de vendedores de
 ordenadores paralelos, escritores de librer\'\i as y especialistas en
 aplicaciones.

Consigue portabilidad proveyendo una librer\'\i a de paso de mensajes est\'andar
 independiente de la plataforma y de dominio p\'ublico.
 La especificaci\'on de esta librer\'\i a est\'a en una forma independiente del
 lenguaje y proporciona funciones para ser usadas con C y Fortran.
 Abstrae los sistemas operativos y el hardware.
 Hay implementaciones MPI en casi todas las m\'aquinas y sistemas operativos.
 Esto significa que un programa paralelo escrito en C o Fortran usando MPI
 para el paso de mensajes, puede funcionar sin cambios en una gran variedad
 de hardware y sistemas operativos.
 Por estas razones MPI ha ganado gran aceptaci\'on dentro el mundillo de la
 computaci\'on paralela.

MPI tiene que ser implementado sobre un entorno que se preocupe de el manejo
 de los procesos y la E/S por ejemplo, puesto que MPI s\'olo se ocupa de la
 capa de comunicaci\'on por paso de mensajes.
 Necesita un ambiente de programaci\'on paralelo nativo.

Todos los procesos son creados cuando se carga el programa paralelo y est\'an
 vivos hasta que el programa termina.
 Hay un grupo de procesos por defecto que consiste en todos esos procesos,
 identificado por MPI\_COMM\_WORLD.
 
Los procesos MPI son procesos como se han considerado tradicionalmente,
 del tipo pesados, cada proceso tiene su propio espacio de direcciones,
 por lo que otros procesos no pueden acceder directamente al las variables
 del espacio de direcciones de otro proceso.
 La intercomunicaci\'on de procesos se hace v\'\i a paso de mensajes.

Las desventajas de MPI son las mismas que se han citado en PVM, realmente
 son desventajas del modelo de paso de mensajes y de la implementaci\'on en
 espacio de usuario.
 Adem\'as aunque es un est\'andar y deber\'\i a tener un API est\'andar, cada una
 de las implementaciones var\'\i a, no en las llamadas sino en el n\'umero de
 llamadas implementadas (MPI tiene unas 200 llamadas).
 Esto hace que en la pr\'actica los dise\~{n}adores del sistema y los programadores
 tengan que conocer el sistema particular de MPI para sacar el m\'aximo rendimiento.
 Adem\'as como s\'olo especifica el m\'etodo de paso de mensajes, el resto del
 entorno puede ser totalmente distinto en cada implementaci\'on con lo que
 otra vez se impide esa portabilidad que te\'oricamente tiene.
 
Existen implementaciones fuera del est\'andar que son tolerantes a fallos,
 no son versiones demasiado populares porque causan mucha sobrecarga.
%===========================================================================
\subsection{Beowulf}
El proyecto Beowulf fue iniciado por Donald Becker (tambi\'en famoso por crear
 numerosos drivers para tarjetas de red en Linux) en 1994 para la NASA.
 Este proyecto se basa en usar PVM y MPI, a\~{n}adiendo alg\'un programa m\'as que
 se usan para monitorizar, realizar benchmarks y facilitar el manejo del
 cluster.

Entre las posibilidades que integra este proyecto se encuentra la posibilidad
 de que algunos equipos no necesiten discos duros, por eso se consideran
 que no son un cluster de estaciones de trabajo, sino que dicen que pueden
 introducir nodos heterog\'eneos.
 Esta posibilidad la da otro programa y Beowulf lo a\~{n}ade a su distribuci\'on.

Beowulf puede verse como un empaquetado de
 PVM/MPI junto con m\'as software para facilitar el d\'\i a a d\'\i a del cluster
 pero no aporta realmente nada nuevo con respecto a tecnolog\'\i a.
%===========================================================================
\subsection{openMosix}
OpenMosix es un software para conseguir clustering en GNU/Linux, migrando los procesos
 de forma din\'amica con requisa.
 Consiste en unos algoritmos de compartici\'on de recursos adaptativos a nivel
 de kernel, que est\'an enfocados a conseguir alto rendimiento, escalabilidad
 con baja sobrecarga y un cluster f\'acil de utilizar.
 La idea es que los procesos colaboren de forma que parezca que est\'an en
 un mismo nodo.

Los algoritmos de openMosix son din\'amicos lo que contrasta y es una fuerte ventaja
 frente a los algoritmos est\'aticos de PVM/MPI, responden a las variaciones
 en el uso de los recursos entre los nodos migrando procesos de un nodo
 a otro, con requisa y de forma transparente para el proceso, para balancear
 la carga y para evitar falta de memoria en un nodo.

Los fuentes de openMosix han sido desarrollados 7 veces para distintas versiones de Unix y BSD,
 nosotros en este proyecto siempre hablaremos de la s\'eptima implementaci\'on
 que es la que se est\'a llevando a cabo para Linux.

OpenMosix, al contrario que PVM/MPI, no necesita una adaptaci\'on de la aplicaci\'on
 ni siquiera que el usuario sepa nada sobre el cluster.
 Como se ha visto, para tomar ventaja con PVM/MPI hay que programar con
 sus librer\'\i as, por tanto hay que rehacer todo el
 c\'odigo que haya (para aprovechar el cluster).

 En la secci\'on de PVM ya se han explicado las desventajas que ten\'\i a esta aproximaci\'on.
 Por otro lado openMosix puede balancear una \'unica aplicaci\'on si esta est\'a dividida
 en procesos lo que ocurre en gran n\'umero de aplicaciones hoy en d\'\i a.
 Y tambi\'en puede balancear las aplicaciones entre s\'\i , lo que balancea openMosix
 son procesos, es la m\'\i nima unidad de balanceo.
 Cuando un nodo est\'a muy cargado por sus procesos y otro no, se migran procesos
 del primer nodo al segundo.
 Con lo que openMosix se puede usar con todo el software actual si bien la divisi\'on
 en procesos ayuda al balanceo gran cantidad del software de gran carga
 ya dispone de esta divisi\'on.

El usuario en PVM/MPI tiene que crear la m\'aquina virtual decidiendo qu\'e
 nodos del cluster usar para correr sus aplicaciones cada vez que las arranca
 y se debe conocer bastante bien la topolog\'\i a y caracter\'\i sticas del cluster
 en general.
 Sin embargo en openMosix una vez que el administrador del sistema que es quien
 realmente conoce el sistema, lo ha instalado, cada usuario puede ejecutar
 sus aplicaciones y seguramente no descubra que se est\'a balanceando la carga,
 simplemente ver\'a que sus aplicaciones acabaron en un tiempo record.

PVM/MPI usa una adaptaci\'on inicial fija de los procesos a unos ciertos nodos,
 a veces considerando la carga pero ignorando la disponibilidad de otros
 recursos como puedan ser la memoria libre y la sobrecarga en dispositivos
 E/S.

En la pr\'actica el problema de alojar recursos es mucho m\'as complejo de lo
 que parece a primera vista y de como lo consideran estos proyectos, puesto
 que hay muchas clases de recursos (CPU, memoria, E/S, intercomunicaci\'on
 de procesos, etc.) donde cada tipo es usado de una forma distinta e impredecible.
 Si hay usuarios en el sistema, existe a\'un m\'as complejidad y dificultad
 de prever que va a ocurrir, por lo que ya que alojar los procesos de forma
 est\'atica es tan complejo que seguramente lleve a que se desperdicien recursos,
 lo mejor es una asignaci\'on din\'amica de estos recursos.

Adem\'as estos paquetes funcionan a nivel de usuario, como si fueran aplicaciones
 corrientes, lo que les hacen incapaces de responder a las fluctuaciones
 de la carga o de otros recursos o de adaptar la carga entre los distintos
 nodos que participan en el cluster.
 En cambio openMosix funciona a nivel de kernel por tanto puede conseguir toda
 la informaci\'on que necesite para decidir c\'omo est\'a de cargado un sistema
 y qu\'e pasos se deben seguir para aumentar el rendimiento, adem\'as puede
 realizar m\'as funciones que cualquier aplicaci\'on a nivel de usuario, por
 ejemplo puede migrar procesos, lo que necesita una modificaci\'on de las
 estructuras del kernel.
%=========================================================================
\subsection{TOP 500}
Este {\em ranking} indica cu\'ales son los 500 computadores m\'as potentes del mundo.
Se incluyen MPPs, constelaciones, clusters y m\'aquinas vectoriales.
 Vamos a destacar algunos de los resultados del Top de
 supercomputadores en diferentes \'epocas.


A fecha de junio de 2001 la lista demostraba claramente como estaban
avanzando los supercomputadores, algunos datos curiosos fueron:
\begin{itemize}
  \item El n\'umero 1 del top era {\tt ASCI White} de IBM que llega a 7,2 TeraFlops/s.
  \item 12 de los sistemas ten\'\i an m\'as de 1 TFlop/s, el m\'as
  peque\~{n}o del{\em top ten} alcanzaba 1.18TFlop/s.
  \item El rendimiento total era de 108.8 TFlop/s, comparado con 88.8
  TFlop/s del a\~{n}o anterior.
  \item El n\'umero 500 pas\'o de tener 55.1 TFlop/s a 67.8 TFlop/s.
\end{itemize}
Esta lista hace una divisi\'on de clusters entre clusters tradicionales y
 constelaciones. De los cluster que cuyos nodos no son SMP pod\'\i a verse que
 los dos primeros estaban en los puestos 30 y 31 y eran IBM.

