Serie ficheros virtuales

  

 

 

 

C Ficheros virtuales

 

 

 

 

A.I.3 Caché

 

 A.I.3.1 Concepto

 A.I.3.2 Caché lineal

 A.I.3.3 Consideraciones

 A.I.3.4 Caché con ficheros virtuales

 

                                                                       _______

 

A.I.3.1 Concepto

 

La idea de mantener la persistencia de los datos con objeto de reutilizar los cálculos y resultados previos de un proceso surge de forma natural, tanto más cuanto mayor sea el esfuerzo para obtenerlos.

 

Particularmente, los procesos que involucran gran cantidad de acceso a base de datos ó de cálculos complejos e iterativos, son candidatos ideales para utilizar técnicas de caché en memoria.

 

El concepto de caché consiste entonces en reservar los datos en memoria y recuperarlos directamente en caso de repetición de la solicitud, sin llegar a efectuar su recálculo. En contra lo que podría pensarse, las situaciones de repetición no son en absoluto acontecimientos raros en la práctica cotidiana, consideremos por ejemplo los procesos nocturnos masivos que en los grandes sistemas van recorriendo entornos y realizando subprocesos, dentro de los cuales hay tareas que acaban repitiéndose.

 

Las técnicas de caché no sólo pueden reaprovechar los resultados sino también obtener un considerable ahorro de tiempo de proceso, que incluso puede volver factibles procedimientos que se descartarían en otro caso y más teniendo en cuenta que utilizar la técnica con ficheros virtuales es muy fácil y no precisa cambiar lógica de proceso de forma significativa; si acaso, puede simplificarla.

 

Aunque el ahorro de tiempo se maximiza al emplear la memoria como espacio de trabajo, la técnica de utilizar un fichero de trabajo temporal en situaciones complejas repetitivas es en sí misma extremadamente efectiva frente a la alternativa de series, que se pierden al terminar el proceso local y no permiten un aprovechamiento posterior para reutilización en otros procesos, o para tratamientos postproceso o estadístico de los datos utilizados.

 

Además, al preparar a los procesos para establecer mecanismos de caché nos obligamos a compartimentar claramente entre datos de petición y resultados consecuentes asociados, facilitando la estructuración y el mantenimiento.

                                                                                                                                                                                         

                                                                       _______

 

A.I.3.2 Caché lineal

 

¿Cuál es el caché más sencillo? La ruptura de totales. Esto es, la comparación de un valor leído contra su valor en memoria para reconocer cambios de secuencia para hacer tareas de “ruptura de totales”.

 

Su generalización natural es guardar en una serie el conjunto de distintos valores tratados junto con sus resultados. Esta serie se va explorando en cada ciclo para reaprovechar los datos previamente calculados. Este es el caché lineal.

 

Es interesante observar que, de hecho, el ahorro de proceso se percibe de forma significativa en cuanto se empiezan a aplicar técnicas de caché que pueden ser tan sencillas como las descritas.

Presentamos ahora un ejemplo de archivo y recuperación de valores previos mediante un bucle lineal sobre un conjunto limitado de ítems:

 

- Codificación origen

 

Supongamos que la invocación que se presenta de una cierta utilidad SRRCS_PNM fuera muy costosa.

 

void eIII_0(long lNpruebas)

{

  long l = 0;       // Contador de for (contador de ciclos de prueba)

  long ll = -1;     // Contador de for auxiliar de items distintos (Resto de l|lKMAX)

  double dl = 0;    // Double ll/lKMAX, valor de entrada a la función SRRCS_PNM

  double dp = 0.0;  // Resultado del cálculo

  long lKMAX = 100; // Nº distinto de items de prueba

 

 

  // Bucle de pruebas

 

  for (l=0; l<lNpruebas; ++l)

  {

 

   // Contador auxiliar de ítems distintos (Parámetro de entrada de SRRCS_PNM)

   //

   // Precisamente la situación de tener ítems repetidos en un ciclo de cálculo costoso es lo que lleva a plantearse

   // la utilización de mecanismos de caché

 

 

   ++ll;

   if (ll==lKMAX) ll = 0;

 

 

   // Parámetro de solicitud

 

   dl = (double) ll / double (lKMAX);

 

 

   // Cálculo directo

 

   dp = SRRCS_PNM(dl);

 

  }

 

  return;

}

         

 

El funcionamiento es claro, se ejecuta un bucle de invocaciones directas de la función, al estilo por ejemplo siguiente:

 

 

  Número de prueba

 Valor de referencia

     Resultado (Cálculo directo)

  Ciclo 1.1

        0,1

           0,5398

        1.2

        0,2  

           0,5793

        ...

        ...                      

           ...

        1.9

        0,9

           0,8159

 

 

 

  Ciclo 2.1

        0,1

           0,5398

        2.2

        0,2  

           0,5793

        ...

        ...                      

           ...

        2.9

        0,9

           0,8159

 

 

 

 

 

 

  Ciclo 3.1

        0,1

           0,5398

        3.2

        0,2  

           0,5793

        ...

        ...                      

           ...

        3.9

        0,9

           0,8159

 

 

 

  . . .

 

 

 

 

 

 Veamos ahora como ahorrar tiempo de proceso una técnica de caché lineal simple:

 

 

                                                             _______

 

 

- Codificación de caché lineal simple

 

void eIII_1(long lNpruebas)

{

  long l = 0;       // Contador de for (contador de ciclos de prueba)

  long ll = -1;     // Contador de for auxiliar de ítems distintos (Resto de l|lKMAX)

  long li = 0;      // Contador de for (para el lookup de búsqueda)

  double dl = 0;    // ll/lKMAX, valor de entrada a la función SRRCS_PNM

  double dp = 0.0;  // Resultado del cálculo

  long lKMAX = 100; // Máximo tamaño de caché. También nº distinto de ítems de prueba

  long iNsec = -1;  // Iterador de caché (contador de salvas a caché)

  double SD[100];   // Archivador de los datos abscisa

  double SP[100];   // Archivador de los datos ordenada

 

 

  // La técnica consiste en definir una serie donde reservar los datos, un mecanismo de grabación y un mecanismo de búsqueda.

  //  Éstas ideas son la base de la extrapolación que lleva a la aplicación de ficheros virtuales.

 

  // En éste ejemplo, el caché se utilizará para sustituir la invocación a una función por la recuperación del valor tabulado

  // en memoria en forma de caché lineal

 

 

  // Bucle de pruebas

 

  for (l=0;l<lNpruebas;++l)

  {

 

   // Contador auxiliar de items distintos

 

   ++ll;

   if (ll==lKMAX) ll = 0;

 

 

   // Parámetro de solicitud

 

   dl = (double) ll / double (lKMAX);

   dp = 0.0;

 

 

   // Recuperación desde el caché lineal simple

 

   if (iNsec >= 0)

   {

    for (li=0; li<=iNsec; ++li)

    {

 

     if (dl == SD[li])

     {

      dp = SP[li];

      break;

     }

 

   }

  }

  if (dp > 0.0) continue;

 

 

  // Cálculo directo

 

  dp = SRRCS_PNM(dl);

 

 

 

  // Grabación en el caché

 

  ++iNsec;

 

  if (iNsec < lKMAX)

  {

   SD[iNsec] = dl;

   SP[iNsec] = dp;

  }

  

 }

 

 return;

}

 

 

Ahora se ejecuta un primer bucle de invocaciones directas de la función, seguidas de recuperaciones lineales:

 

 

  Número de prueba

 Valor de referencia

                 Resultado

  Ciclo 1.1

        0,1

           0,5398 (Cálculo directo)

        1.2

        0,2  

           0,5793 (Cálculo directo)

        ...

        ...                      

           ...

        1.9

        0,9

           0,8159 (Cálculo directo)

 

 

 

  Ciclo 2.1

        0,1

           0,5398 Recuperación lineal. Profundidad 1

        2.2

        0,2  

           0,5793 Recuperación lineal. Profundidad 2

        ...

        ...                      

           ...

        2.9

        0,9

           0,8159 Recuperación lineal. Profundidad 9

 

 

                  Media profundidad de búsqueda: 5

 

 

 

  Ciclo 3.1

        0,1

           0,5398 Recuperación lineal. Profundidad 1

        3.2

        0,2  

           0,5793 Recuperación lineal. Profundidad 2

        ...

        ...                      

           ...

        3.9

        0,9

           0,8159 Recuperación lineal. Profundidad 9

 

 

                  Media profundidad de búsqueda: 5

  . . .

 

 

 

 

                                                                       _______

 

 

A.I.3.3 Consideraciones

 

En el ejemplo se utiliza como soporte físico para archivo del caché una serie de claves y otra de datos y para la comparación el operador =.

 

En situaciones más complejas, habría que usar como soporte físico estructuras seriadas y para la comparación efectiva la función memcmp.

 

Aun siendo una situación sencilla, la rutina resultante amplia la codificación original oscureciendo el propósito de cálculo.

 

El archivo queda limitado a un tamaño prefijado estático. Además, si este se establece muy grande, el rendimiento del sistema se va degradando de forma directa según el tamaño efectivo de exploración va creciendo.

 

 

                                                                       _______

 

 

A.I.3.4 Caché con ficheros virtuales

 

La alternativa a la codificación del epígrafe anterior utilizando ficheros virtuales resulta mucho más concisa y pone de manifiesto que su uso no precisa alterar la lógica de proceso, pues esencialmente basta incluir las sentencias new, write y chain como sigue:

 

 

void eIII_2(long lNpruebas)

{

  long lNID = 0;    // Identificador del fichero virtual

  long lResul = 0;  // Resultado de invocaciones a SRRCW

  long l = 0;       // Contador de for (contador de ciclos de prueba)

  long ll = -1;     // Contador de for auxiliar de items distintos (Resto de l|lKMAX)

  double dl = 0;    // ll/lKMAX, valor de entrada a la función SRRCS_PNM

  double dp = 0.0;  // Resultado del cálculo

  long lKMAX = 100; // Máximo nº de ítems distintos

 

 

 // Ejemplo re-escrito bajo técnica de fichero virtual

 

 

 // En éste ejemplo, el caché se utilizará para sustituir la invocación a una función por la recuperación del valor tabulado

 // en memoria por medio de un fichero virtual

 

 

  // Crea el fichero virtual. Es un fichero sencillo compuesto de una parte de clave double y una parte de datos también double

 

  lNID = SRRCW_NEW("EIII_2", sizeof(double), sizeof(double));

 

 

 

  // Bucle de pruebas

 

  for (l=0; l<lNpruebas; ++l)

  {

   // Contador auxiliar de ítems distintos

 

   ++ll;

   if (ll==lKMAX) ll = 0;

 

 

   // Parámetro de solicitud

 

   dl = (double) ll / double (lKMAX);

   dp = 0.0;

 

 

 

   // Recuperación desde el caché

 

   lResul = SRRCW_CHAIN("EIII_2", &dl, &dp);

   if (dp > 0.0) continue;

 

 

 

   // Cálculo directo

 

   dp = SRRCS_PNM(dl);

 

 

 

   // Grabación en el caché

 

   lResul = SRRCW_WRITE("EIII_2", &dl, &dp);

  }

 

 

  // Elimina el fichero virtual (*)

 

   lResul = SRRCW_ERASE("EIII_2");

 

  return;

}

 

(*) A nivel de PC, la sentencia SRRCW_ERASE puede eludirse en los subprocedimientos si se incluye un SRRCW_CLOSE al final del programa principal, que elimina 

    todos los ficheros virtuales utilizados.

      En iSeries incluso puede obviarse, pues toda la memoria virtual se reclama automáticamente al terminar el trabajo.

 

 

 

Tal como se anticipaba, los bucles de recuperación/grabación a caché quedan sustituidos cada uno por una sola sentencia de denominación elocuente: SRRCW_CHAIN y SRRCW_WRITE (Herederas de la nomenclatura utilizada en lenguajes de programación como el ILE RPG)

 

 

Internamente, ahora se ejecuta un primer bucle de invocaciones directas de la función, seguidas de recuperaciones dicotómicas:

 

 

  Número de prueba

 Valor de referencia

                 Resultado

  Ciclo 1.1

        0,1

           0,5398 (Cálculo directo)

        1.2

        0,2  

           0,5793 (Cálculo directo)

        ...

        ...                      

           ...

        1.9

        0,9

           0,8159 (Cálculo directo)

 

 

 

  Ciclo 2.1

        0,1

           0,5398 Recuperación dicotómica. Profundidad 3

        2.2

        0,2  

           0,5793 Recuperación dicotómica. Profundidad 3

        ...

        ...                      

           ...

        2.9

        0,9

           0,8159 Recuperación dicotómica. Profundidad 3

 

 

                  Media profundidad de búsqueda: 3

 

 

 

  Ciclo 3.1

        0,1

           0,5398 Recuperación dicotómica. Profundidad 3

        3.2

        0,2  

           0,5793 Recuperación dicotómica. Profundidad 3

        ...

        ...                      

           ...

        3.9

        0,9

           0,8159 Recuperación dicotómica. Profundidad 3

 

 

                  Media profundidad de búsqueda: 3

  . . .

 

 

 

 

                                                                       _______

 

 

Volviendo al tema general del libro, hay que señalar que, en esencia, el desarrollo de una aplicación de base de datos virtual surge de la ampliación natural de una aplicación núcleo que resuelva el problema del caché; dicho de otro modo, de añadir a las sentencias del modesto núcleo constituido por WRITE y CHAIN todo el resto de utilidades, como se comienza a exponer en el capítulo siguiente.

                                                                       _______