viernes, 16 de diciembre de 2016

PED - Diseño y Administracion de SO - UNED (Top)

Como no hay segunda convocatoria pienso que no hay ningún problema por publicar la PED.
Aún no está evaluada por lo que puede que no sea un buen ejemplo :-).

Tiene como nota un 10.

El Objetivo de esta práctica es programar un script en bash llamado mitop.sh que muestre información sobre los procesos de forma similar a la mostrada por comando top.


Obtención de datos iniciales 

Como paso inicial se lee el contenido del directorio /proc filtrando el resultado para obtener solo los PID de todos los procesos independientemente de su estado (R, S, D, Z, T).

listadoProcesos=$(ls -d  [0-9]*)

A continuación realizamos la primera medición de tiempo inicio=`date +%s%N` y obtenemos la suma de ticks de reloj planificados (modo usuario + modo núcleo) de  los todos los procesos existentes usando un bucle for y el archivo proc/PID/stat. Esta información junto con el PID se almacena en el archivo ‘tiempo1’ 

Es necesario usar una sentencia condicional  if [ -d "$i" ]  para descartar procesos que han finalizado y que por lo tanto no existen en /proc.
Realizamos la pausa de 1 segundo y realizamos la segunda medición de tiempo fin=`date +%s%N`.  Con estas dos medidas obtendremos el tiempo real de entre las dos iteraciones.

Finalmente, volvemos a obtener la suma de ticks de reloj planificados (modo usuario  + modo núcleo) de  los todos los procesos existentes (archivo ‘tiempo2’), calculamos la diferencia y la guardamos (archivo ‘tiempoTotal’), ordenamos el resultado y nos quedamos con los 10 procesos con mayor tiempo de CPU (archivo ‘tiemporTotalOrdenado’).

paste $HOME/tiempo1 $HOME/tiempo2 | awk '{print $1, ($4 - $2)}' >> $HOME/tiempoTotal
sort -k2 -nr $HOME/tiempoTotal | head -10 >> $HOME/tiempoTotalOrdenado

Detalle de la cabecera

La información a  mostrar en la cabecera la obtenemos de la variable ‘listadoProcesos’, del archivo /proc/meninfo, del archivo temporal ‘CPU_PID’ y del comando ‘free’

numeroProcesos=$(echo "$listadoProcesos"| wc -w)
memoriaTotal=$(awk '/MemTotal/ {print $2}' < /proc/meminfo)
memoriaLibre=$(awk '/MemFree/ {print $2}' < /proc/meminfo)
memoriaUsada=$(free | awk 'NR==2{print $3}')
usoCPU=`awk '{sum+=$2};END{print sum}' $HOME/CPU_PID`

Detalle por Proceso

Esta parte es la más complicada ya que tenemos que realizar algunos cálculos para obtener los %CPU y %MEM. El resto de información mostrada se obtiene de nuevo del archivo proc/PID/stat (PR,VIRT, S, COMMAND, MEM por PID) y con el comando ‘ps’ (USER, TIME).

Se han utilizado una serie de bucles while cuya condición de salida es la finalización de las líneas de un archivo temporal que se le pasa como parámetro de entrada. Estos bucles generan, mediante la llamada a una función, mediante la lectura de proc/PID/stat o del comando ‘ps’ un archivo temporal de salida con la información requerida. 

Esta es la estructura genérica del bucle usado.

while read linea
do
read VARIABLE <<< $(echo -e "$linea"| awk '{print $COLUMNA;}')
//operaciones de lectura o calculos
printf "%s\t%s\n" $VARIABLE $VARIABLE CALCULADA >> $HOME/archivo salida
done < $HOME/archivo entrada;


A continuación explico en detalle el procedimiento seguido para obtener %CPU y %MEM.

%CPU, Porcentaje de uso del procesador en el intervalo de tiempo elegido.

Para realizar este cálculo, necesitamos saber cuál es el tiempo durante el cual cada proceso ha estado planificado en la CPU (utime+stime) durante el intervalo de tiempo elegido ‘tiempoTotal’. Esta información ya la tenemos ‘tiempoTotalOrdenado’ pero en ticks de reloj por lo que es necesario convertirla en milisegundos. 

Para poder realizar esta conversión lo primero que necesitamos saber cuánto equivale un tick de reloj en milisegundos. Esta información la hemos calculado previamente durante la preparación del entorno de ejecución y la tenemos  en la variable ‘miliSgPorTick’. Con estos dos datos, usando la función ‘ticksToMs’ convertimos los ticks de reloj a milisegundos para cada proceso. 

ticksToMs()
{
  let timeMs=($2*$miliSgPorTick)
  printf "%s\t %d\n" $1 $timeMs
}


Una vez que tenemos el tiempo de planificación de cada proceso en milisegundos, usamos otra función ‘CPUporPID’ para calcular el %CPU para cada proceso durante el intervalo de tiempo elegido

CPUporPID()
{
  porcentaje=$(echo "scale=4; $2/$tiempoTotal" | bc)  
  porcentajeT=$(echo "scale=4; $porcentaje*100" | bc) 
  porcentajeFormateado=`awk 'BEGIN{printf "%.4f", "'"$porcentajeT"'"}'`
  printf "%s\t%.4s\n" $1 $porcentajeFormateado
}

%MEM, Porcentaje de uso del procesador en el intervalo de tiempo elegido.

Para realizar este cálculo simplemente tenemos que sabe el tamaño en Kb de cada página de memoria, el número de páginas asignadas a cada proceso y el tamaño total de memoria principal. El tamaño de una página en Kb,  la hemos calculado previamente durante la preparación del entorno de ejecución y la tenemos  en la variable ‘pageSizeKB, el número de páginas en memoria asignadas al proceso ‘rss’ y el tamaño de la memoria también, en el archivo temporal ‘PVSCM_PID’ y la variable ‘memoriaTotal’ respectivamente. Ya solo nos queda llamar a la función MEMporPID pasando como parámetro el número de páginas para calcular el %MEM.

MEMporPID()
{
  porcentajeM1=$(echo "scale=4; $2*$pageSizeKB" | bc)  
  porcentajeM2=$(echo "scale=4; $porcentajeM1/$memoriaTotal" | bc)
  porcentajeMT=$(echo "scale=4; $porcentajeM2*100" | bc) 
  porcentajeMFormateado=`awk 'BEGIN{printf "%.4f", "'"$porcentajeMT"'"}'`
  printf "%s\t%.4s\n" $1 $porcentajeMFormateado
}

Como último paso en la sección DETALLE PROCESO  generamos un único archivo con todos los datos necesarios usando el comando paste.  El nombre de este archivo es ‘outputPID’.

Impresión de datos por pantalla

Se imprimen por pantalla los datos obtenidos usando los comandos echo y printf. El comando printf se ha elegido para el área de detalle del proceso ya que permite un mayor control del formato. Para la lectura del archivo ‘outputPID’ volvemos a usar un bucle while.





Y finalmente aquí está el código.

Culex.

No hay comentarios:

Publicar un comentario