Tampoco pienses que a mi se me ocurre escribir esa sintaxis y funcionar a la primera...
Lo que yo hago es imaginar la estructura de datos que necesito, cómo agrupar la información, dividirla en pura lista de elementos que convertiré en un array, o si voy a almacenar estructuras con nombre, que convertiré en un hash.
Y casi siempre, lo que se escribe en el programa, no funciona a la primera, ni a la segunda, ni a la décima. Hay que jugar con Data::Dumper para verificar una y otra vez que Perl está construyendo nuestro castillo de naipes de forma sólida. Y que está extrayendo las cartas una a una y todo sigue en pie
Te explico un poco lo que hacen las líneas:
my @fechas = sort keys %{ $log{$maquina}->{ ${ $medidas{$medida}->{datos} }[0] } };
El hash %medidas es una constante. Mejor dicho, guarda una serie de constantes, de las magnitudes y textos que deben acompañar a los xml generados. Definida a partir de la línea 8.
El bucle de la línea 89 recorre las claves de ese hash, es decir, 'cpu', 'mem' e 'io'.
Con la expresión $medidas{$medida}->{datos} estamos accediendo a la entrada 'datos' de cada una de esas medidas. Y es una referencia a un array. Como tal, podemos acceder a su primer elemento: ${ $medidas{$medida}->{datos} }[0] (otra forma de escribirlo, más clara: $medidas{$medida}->{datos}->[0]).
Si $medida fuera 'cpu', entonces de esta última expresión obtendríamos el valor 'cpu_ready_summation'. Ahora tenemos esto: $log{$maquina}->{'cpu_ready_summation'}, que, según la línea 72, es una referencia a un hash que guarda en sus claves los 'Timestamp' de esa medida. Esas claves son extraídas por keys(), y luego ordenadas alfabéticamente por sort() (podemos hacerlo porque las fechas fueron normalizadas en la línea 68).
El resultado final es que en @fechas quedan los 'timestamp' de la primera magnitud ('cpu_ready_summation') de la $medida que en ese momento estemos analizando. ¿Por qué de la primera y solo de la primera? Pues porque vamos a dar por supuesto que el archivo CSV está bien, y por cada medida realizada, todas las magnitudes tienes los mismos 'timestamp' (esto es algo que no nos has dicho, pero que suponemos que es así).
Más tarde, las @fechas se usarán para recuperar los valores capturados (línea 120).
for my $item ( @{ $medidas{$medida}->{datos} } )
Esto es la línea 96 del segundo código y la línea 114 del primer código: recorren los valores del array que se encuentra referenciado por la entrada 'datos' en cada hash según la $medida que sea en ese momento. En tu código de ejemplo, pusiste dos bucles distintos para recorrer los valores de 'cpu.usage.average' y 'cpu.ready.summation'. Aquí hay un bucle que recorre todos los valores, por lo que da igual si son dos, tres o más magnitudes que hay que leer.
open my $SALIDA, '>', "${maquina}_$medida.xml";
Bueno, esto no tiene nada que ver con referencias de array o hash. Es solo una cuestión de nomenclatura.
La intención es crear un archivo .xml con el nombre de la máquina, un guion bajo, y seguido por el nombre de la medida en cuestión.
Resulta que si pongo "$maquina_$medida.xml", Perl intentará interpolar la variable '$maquina_' (se cree que el guion bajo forma parte del nombre de la variable), y claro, esa variable no existe.
El guion bajo es un carácter legal para los nombres de variables, así que hay que decirle a Perl que en realidad, ese guion bajo es un guion bajo literal. La forma de hacerlo es reescribiendo la variable $maquina como ${maquina}.