Sei sulla pagina 1di 235

MEJORA DEL RENDIMIENTO DE LAS APLICACIONES JAVA USANDO COOPERACION ENTRE EL SISTEMA OPERATIVO Y LA MAQUINA VIRTUAL DE JAVA

MEJORA DEL RENDIMIENTO DE LAS APLICACIONES JAVA USANDO COOPERACION ENTRE EL SISTEMA OPERATIVO Y LA MAQUINA VIRTUAL DE JAVA

Yolanda Becerra
Departament dArquitectura de Computadors Universitat Polit`cnica de Catalunya e Barcelona

Directores de tesis:
Toni Cortes Jordi Garcia Nacho Navarro

TESIS DEPOSITADA EN CUMPLIMIENTO DE LOS REQUERIMIENTOS PARA OBTENER EL GRADO DE Doctora en Informtica a JULIO, 2006

RESUMEN

El uso de los entornos virtualizados de ejecucin se ha extendido a todos los mbitos y, o a en particular, se est utilizando para el desarrollo y la ejecucin de aplicaciones con un a o alto consumo de recursos. Por lo tanto, se hace necesario evaluar si estas plataformas ofrecen un rendimiento adecuado para este tipo de programas y si es posibl aprovechar las caracter sticas de estas plataformas para favorecer su ejecucin. o El objetivo principal de este trabajo ha sido ha sido demostrar que es posible explotar las caracter sticas de los entornos virtualizados de ejecucin para ofrecer a los programas o una gestin de recursos que se adapte mejor a sus caracter o sticas. En este trabajo demostramos que el modelo de ejecucin de este tipo de entornos, basado o en la ejecucin sobre mquinas virtuales, ofrece una nueva oportunidad para implementar o a una gestin espec o ca de recursos, que permite mejorar el rendimiento de los programas sin renunciar a las numerosas ventajas de este tipo de plataformas como, por ejemplo, una portabilidad total del cdigo de los programas. o Para demostrar los benecios de esta estrategia hemos seleccionado como caso de estudio la gestin del recurso memoria para los programas de clculo cient o a co en el entorno de ejecucin de Java. Despus de un anlisis detallado de la inuencia que tiene la gestin de o e a o memoria sobre este tipo de programas, hemos visto que a adir en el entorno de ejecucin n o una pol tica de prefetch de pginas que se adapte al comportamiento de los programas es a una posible v para mejorar su rendimiento. a Por este motivo, hemos analizado detalladamente los requerimientos que debe cumplir esta pol tica y cmo repartir las tareas entre los diferentes componentes del entorno de o ejecucin de Java para cumplir estos requerimientos. o

vi

Como consecuencia, hemos dise ado una pol n tica de prefetch basada en la cooperacin o entre la mquina virtual y el sistema operativo. En nuestra propuesta, por un lado, las a decisiones de prefetch se llevan a cabo utilizando todo el conocimiento que la mquina a virtual tiene sobre el comportamiento dinmico de los programas y el conocimiento que a el sistema operativo tiene sobre las condiciones de ejecucin. Por otro lado, el encargao do de llevar a cabo las decisiones de gestin es el sistema operativo, lo que garantiza la o abilidad de la mquina. Adems, esta estrategia es totalmente transparente al prograa a mador y al usuario, respetando el paradigma de portabilidad de los entornos de ejecucin o virtualizados. Hemos implementado y evaluado esta estrategia para demostrar los benecios que ofrece al tipo de programas seleccionado y, aunque estos benecios dependen de las caracter sticas del programa, la mejora del rendimiento ha alcanzado hasta un 40 % si se compara con el rendimiento obtenido sobre el entorno original de ejecucin. o

AGRADECIMIENTOS

En primer lugar, quiero agradecer a mis directores de tesis, Toni Cortes, Jordi Garcia y Nacho Navarro, el esfuerzo que cada uno de ellos ha invertido en este trabajo y su nivel de implicacin. o Tambin quiero agradecer al Departament dArquitectura de Computadors y, en particular, e a la l nea de investigacin de Computacin de Altas Prestaciones y a su director Mateo o o Valero, el haberme proporcionado el entorno adecuado y los recursos necesarios para poder desarrollar este trabajo. Toni Cortes y Jordi Garcia son los principales responsables de que este trabajo haya llegado a su n, no slo por su labor de direccin, sino tambin por su apoyo y la conanza que o o e han depositado en m Gracias por no haber permitido que me rindiera hace casi seis a os. . n Gracias por vuestros consejos, por vuestra paciencia y por sacar tiempo para este trabajo (muchas veces de donde no lo ten ais). Gracias por esas reuniones de trabajo (at picas) que, entre risas y bromas, han servido para encontrar el camino de salida de algn que u otro laberinto (y para hacerme ms fuerte). Es verdad que en las dicultades se descubren a a los verdaderos amigos: vosotros lo sois. Son muchos los motivos por los que quiero dar las gracias a David Carrera. El me ha ayudado con sus comentarios, siempre acertados, sobre este trabajo y con la instalacin y o la administracin de las mquinas que hemos utilizado. Y, an ms importante, ha sido o a u a un apoyo fundamental en los momentos de desnimo. Gracias por tu paciencia y por esas a rutas (y ese universo cticio de fauna diversa) que siempre consiguen distraerme de las preocupaciones: slo tu categor personal supera tu capacidad profesional. o a Afortunadamente, la lista de compa eros y amigos del departamento que me han ayudado n en todo este tiempo es demasiado larga para ponerla de forma exhaustiva: muchas gracias vii

viii

a todos. De forma especial tengo que agradecer el apoyo tcnico y personal de dos de ellos. e Ernest Artiaga, mi compa ero ms antiguo desde la poca del colegio, pasando por la n a e licenciatura, hasta llegar a los estudios de doctorado. En demasiadas ocasiones tu talento me ha sacado de un apuro: siempre silencioso... pero cmo se nota si no ests! Tambin o a e Xavier Martorell, desde mis primeros d en el departamento, me ha ofrecido su amistad as y su valioso soporte tcnico. Gracias por tus comentarios siempre precisos: todo un lujo. e Tambin quiero dar las gracias a mis amigos, por su inmensa paciencia y por su cari o. e n En especial gracias a Susana, Mar Jos y Pedro: mi familia elegida a dedo. Gracias por a e haber sido un hombro en el que llorar en los malos momentos y por haber re conmigo do en los buenos. Y por ultimo quiero dar las gracias a mi extensa familia porque recibir cari o incondicional n por tierra, mar y aire hace que todo sea mucho ms llevadero. En especial gracias a mi a hermano Jos Antonio y a mi cu ada Yolanda, por la conanza que me da sentir que e n os tengo ah Y sobre todo, gracias a mis padres, Jos y Nieves: el ejemplo que siempre . e ha guiado mis pasos. Gracias por no escatimar muestras de cari o, por vuestra entrega n y dedicacin, y por la paciencia que habis tenido estos a os. Este trabajo os lo dedico o e n porque, sin lugar a dudas, sin vosotros no habr sido posible. a

Financiacin o
Este trabajo ha sido subvencionado parcialmente por el Ministerio de Educacin Espa ol o n y por la Unin Europea (fondos FEDER) bajo los contratos TIC2001-0995-C02-01 y o TIN2004-07739-C02-01

A mis padres Jos y Nieves e

INDICE

RESUMEN . AGRADECIMIENTOS . LISTA DE FIGURAS . LISTA DE TABLAS . 1. INTRODUCCION 1.1. Motivacin o 1.2. Caso de estudio 1.2.1.El lenguaje de programacin Java y su plataforma de ejecucin o o 1.2.2.Gestin de memoria en el entorno de ejecucin de Java o o 1.2.3.Entorno de trabajo 1.3. Objetivos y planteamiento de este trabajo 2. GESTION DE MEMORIA PARA LOS PROGRAMAS JAVA 2.1. Divisin de tareas entre el SO y la JVM o 2.2. Gestin de la memoria virtual en Linux o 2.2.1.Algoritmo de reemplazo 2.2.2.Prefetch de pginas a 2.3. Gestin del espacio lgico de direcciones en Java o o 2.3.1.Gestin del heap en la JVM classic o 2.3.2.Gestin del heap en la JVM HotSpot o 2.4. Conclusiones

v vii xv xx 1 2 5 6 7 8 9 13 13 15 17 18 19 21 23 26

xi

xii

3.

EVALUACION DEL USO DE LA MEMORIA VIRTUAL DE LOS PROGRAMAS JAVA 3.1. Entorno de Trabajo 3.1.1.Programas de prueba 3.2. Evaluacin del rendimiento de la gestin de memoria o o 3.2.1.Clasicacin de los fallos de pgina o a 3.2.2.Metodolog para la recoleccin de datos a o 3.2.3.Importancia del tiempo de gestin de fallos de pgina o a 3.2.4.Distribucin de los fallos de pgina en el espacio de direcciones o a 3.2.5.Origen de los fallos de pgina a 3.2.6.Validacin de los resultados en la JVM HotSpot o 3.3. Rendimiento ptimo de la gestin de memoria en Java o o 3.3.1.Modelo de gestin de memoria ptima o o 3.3.2.Implementacin del modelo de gestin de memoria ptima o o o 3.3.3.Evaluacin del rendimiento de la gestin ptima de memoria o o o 3.4. Evaluacin del tipo de objetos o 3.5. Oportunidades de mejora

29 30 30 32 32 33 39 43 44 48 51 52 53 60 60 65

4.

MEJORA DEL RENDIMIENTO DE LOS PROGRAMAS JAVA MEDIANTE EL PREFETCH DE MEMORIA 4.1. Tareas y requerimientos para un prefetch efectivo 4.2. Seleccin de pginas de prefetch o a 4.2.1.Limitaciones del SO para la seleccin de pginas o a 4.2.2.Limitaciones del compilador para la seleccin de pginas o a 4.2.3.Superacin de las limitaciones mediante la JVM o 4.3. Carga as ncrona y anticipada 4.4. Visin general de la propuesta de prefetch o

67 68 70 72 73 74 77 79

5.

PREFETCH GUIADO POR LA JVM Y TRANSPARENTE AL SO 5.1. Seleccin de pginas de prefetch o a 5.1.1.Efectividad de la prediccin a nivel de instruccin o o

85 86 87

Indice

xiii

5.1.2.Caracterizacin del patrn de accesos o o 5.1.3.Consideraciones para la optimizacin de la seleccin de pginas o o a 5.2. Carga as ncrona y anticipada 5.3. Visin general: prefetch a nivel de usuario o 5.4. Implementacin del prefetch a nivel de usuario o 5.4.1.Implementacin de la seleccin de pginas o o a 5.4.2.Solicitud de carga as ncrona: prefetcher 5.5. Evaluacin del prefetch a nivel de usuario o 5.5.1.Metodolog para los experimentos a 5.5.2.Programas de prueba 5.5.3.Rendimiento del prefetch a nivel de usuario 5.5.4.Conclusiones de la evaluacin o 5.6. Prefetch transparente al SO: slo un paso en el camino o 6. PREFETCH COOPERATIVO ENTRE LA JVM Y EL SO 6.1. Seleccin de pginas de prefetch o a 6.2. Carga as ncrona y anticipada 6.3. Interfaz entre el SO y la JVM para permitir la cooperacin o 6.3.1.Exportacin del estado de la memoria o 6.3.2.Solicitud de carga as ncrona 6.4. Visin general: prefetch cooperativo o 6.5. Implementacin del prefetch cooperativo o 6.5.1.Implementacin para exportar el estado de la memoria o 6.5.2.Implementacin de la llamada a sistema para la carga as o ncrona 6.5.3.Modicaciones de la JVM para usar el prefetch cooperativo 6.6. Evaluacin del prefetch cooperativo o 6.6.1.Metodolog para los experimentos a 6.6.2.Evaluacin de las decisiones de dise o o n 6.6.3.Evaluacin de los benecios del prefetch cooperativo o 6.6.4.Conclusiones de la evaluacin o

93 95 99 101 103 104 115 121 121 122 124 130 132 135 137 138 139 140 141 143 144 145 152 157 163 164 165 173 187

xiv

6.7. Cooperacin entre JVM y el SO: la base para una estrategia de prefetch o estable y ecaz 7. TRABAJO RELACIONADO 7.1. Evaluacin del uso de la memoria o 7.2. Gestin de memoria en Java o 7.3. Gestin espec o ca de recursos 8. CONCLUSIONES Y TRABAJO FUTURO 8.1. Resumen del trabajo 8.2. Contribuciones de este trabajo 8.3. Trabajo futuro REFERENCIAS . 189 193 193 195 196 201 201 205 207 209

LISTA DE FIGURAS

Cap tulo 1 1.1. Modelo de ejecucin de Java o Cap tulo 2 2.1. Gestin de memoria en el entorno de ejecucin de Java o o 2.2. Reemplazo de memoria en Linux 2.3. Organizacin del heap en la JVM classic o 2.4. Algoritmo de la liberacin de memoria: marcado y barrido con o compactacin o 2.5. Organizacin del heap en la JVM HotSpot o 2.6. Liberacin de memoria de la generacin joven en la JVM HotSpot o o Cap tulo 3 3.1. Esquema de funcionamiento del recuento de fallos de pgina a 3.2. Ejemplo de uso del interfaz de manipulacin de los contadores o 3.3. Tiempo dedicado a resolver fallos de pgina a 3.4. Porcentaje de tiempo dedicado a resolver fallos de pgina a 3.5. Clasicacin de los fallos de pgina seg n su origen o a u 3.6. HotSpot vs. classic 3.7. Simulacin de la gestin ptima de memoria o o o 3.8. Algoritmo para generar las trazas 3.9. Esquema de la generacin de trazas o 3.10. Simulador para la gestin de memoria ptima o o 35 38 40 41 46 50 53 56 57 59 23 24 25 15 18 21 7

xv

xvi

3.11. Ejecucin real vs. gestin ptima o o o 3.12. Clasicacin de objetos por tama o o n Cap tulo 4 4.1. Visin general del mecanismo de prefetch o Cap tulo 5 5.1. Prediccin a nivel de instruccin o o 5.2. Efectividad de la prediccin a nivel de bytecode o 5.3. Informacin sobre accesos y ecacia de la prediccin o o 5.4. Patrn de accesos en la multiplicacin de matrices o o 5.5. Grafo del recorrido por las en la multiplicacin de matrices o 5.6. Grafo del recorrido por columnas en la multiplicacin de matrices o 5.7. Prediccin basada en working sets o 5.8. Visin general del prefetch transparente al SO o 5.9. Visin general de la implementacin de la seleccin de pginas o o o a 5.10. Organizacin de la informacin de prediccin o o o 5.11. Funcin de hash para localizar la informacin de prediccin o o o 5.12. Grafo de estados del algoritmo de prediccin o 5.13. Actualizacin de la funcin de prediccin asociada o o o 5.14. Utilizacin de la heur o stica que aproxima del estado de la memoria 5.15. Mecanismo de carga as ncrona transparente al SO 5.16. Multiplicacion de matrices pequenas 5.17. Comportamiento de la Multiplicacion de matrices grandes 5.18. Resultados de la Multiplicacion de matrices grandes 5.19. Comportamiento de la Multiplicacion de matrices extra-grandes 5.20. Resultados de la Multiplicacion de matrices extra-grandes Cap tulo 6

61 63

80

87 89 91 94 95 96 98 102 105 107 108 111 112 113 116 126 127 128 130 131

Lista de Figuras

xvii

6.1. Cooperacin entre JVM y SO para la estrategia de prefetch o 6.2. Interfaz de la llamada a sistema de carga as ncrona 6.3. Visin general del prefetch cooperativo entre JVM y SO o 6.4. Estructura de datos que caracteriza al bitmap dentro del SO 6.5. Conguracin del bitmap en la JVM o 6.6. Resultado de la inicializacin del bitmap o 6.7. Acceso al estado de la pgina p a 6.8. Actualizacin del bitmap en la liberacin de memoria o o 6.9. Actualizacin del bitmap en la carga de memoria o 6.10. Fallo de pgina vs. carga as a ncrona 6.11. Campos a adidos a la estructura que representa una pgina en Linux n a 6.12. Prediccin de accesos no estabilizada o 6.13. Prediccin de accesos estabilizada o 6.14. Condiciones no favorables para el prefetch: operaciones canceladas 6.15. Condiciones favorables para el prefetch: prefetch en curso 6.16. Posibles comportamientos de las peticiones de carga anticipada 6.17. Alternativas para la actualizacin de la tabla de pginas o a 6.18. Resultados de la multiplicacion de matrices 6.19. Resultados de RHS 6.20. Resultados de Crypt 6.21. Resultados de Sparse 6.22. Resultados de FFT 6.23. Resultados de HeapSort 6.24. Inuencia de la automatizacin de la distancia para rhs o 6.25. Inuencia de la automatizacin de la distancia para crypt o 6.26. Inuencia de la automatizacin de la distancia para sparse o Cap tulo 7

136 141 143 146 149 149 150 151 152 154 156 160 161 162 163 169 172 176 178 179 180 182 183 185 186 186

Cap tulo 8

LISTA DE TABLAS

Cap tulo 1

Cap tulo 2

Cap tulo 3 3.1. Tama os de entrada de los benchmarks n 3.2. Fallos de pgina en los accesos a objetos ( %) a 3.3. Bytecodes de creacin de objetos o 3.4. Bytecodes de acceso a objetos 3.5. Uso de los arrays de grandes dimensiones Cap tulo 4 31 43 55 55 65

Cap tulo 5 5.1. Bytecodes de acceso a arrays 5.2. Tama os de las matrices de entrada para la multiplicacin (AxB) n o Cap tulo 6 6.1. Caracter sticas de las matrices de entrada para la multiplicacin (AxB) o 6.2. Inuencia en el rendimiento del bitmap del estado de las pginas a 6.3. Resumen de las caracter sticas de los experimentos Cap tulo 7 xix 166 166 174 104 124

xx

Cap tulo 8

1
INTRODUCCION

Los entornos virtualizados de ejecucin han demostrado ser una opcin muy atractiva pao o ra el desarrollo y la ejecucin de programas. El inters por estos entornos de ejecucin ha o e o crecido al mismo tiempo que se descubr el potencial de Internet para la ejecucin distria o buida de aplicaciones y la posibilidad de explotar de forma global los recursos conectados a la red. Para poder aprovechar este potencial es necesario independizar los programas de las plataformas reales de ejecucin, ya que el entorno formado por las mquinas conectadas o a a Internet es muy heterogneo. Esta es precisamente una de las principales caracter e sticas de este tipo de entornos de ejecucin: aislan a los programas de la plataforma real o dotndolos de una portabilidad total, que permite que se ejecuten sobre cualquier sistema a operativo y en cualquier arquitectura. Sin embargo, la portabilidad no es la unica ventaja derivada del uso de estos entornos. Por ejemplo, las facilidades ofrecidas por los lenguajes dise ados para el desarrollo de n aplicaciones en este tipo de entornos (como Java o C#) son tambin un reclamo para los e programadores. Por todo ello, el uso de los entornos virtualizados se ha extendido a todos los mbitos a de la computacin, para el desarrollo de programas con caracter o sticas muy diversas. Esto signica que estas plataformas de ejecucin se estn utilizando para programas con o a caracter sticas muy diferentes a las que se consideraba durante su creacin y, en concreto, o se estn utilizando para desarrollar aplicaciones con un alto consumo de recursos. Por a consiguiente, es necesario estudiar si realmente son adecuadas y si existe alguna otra

Cap tulo 1

caracter stica de estos entornos que se pueda explotar para mejorar el rendimiento de este tipo de programas. Una de las caracter sticas ms relevantes de estos entornos de ejecucin viene dada por a o su modelo de ejecucin. Este modelo se basa en la utilizacin de una capa de software o o o mquina virtual que, en tiempo de ejecucin, convierte el cdigo binario del programa a o o en el cdigo correspondiente a la plataforma real que est soportando la ejecucin. Esto o a o signica que la mquina virtual tiene acceso a toda la informacin sobre el comportaa o miento dinmico de los programas y, por lo tanto, es capaz de tomar las decisiones de a gestin ms adecuadas para este comportamiento. En este trabajo proponemos a adir a o a n los entornos virtualizados de ejecucin una gestin de recursos basada en la cooperacin o o o entre la mquina virtual y el sistema operativo, que aproveche la informacin que posee a o la mquina virtual para adaptar las decisiones de gestin a las caracter a o sticas de cada programa.

1.1

MOTIVACION

La gran diversidad de plataformas de ejecucin ha hecho que la portabilidad de los proo gramas haya sido siempre una caracter stica muy apreciada por los desarrolladores de aplicaciones. Sin embargo, el auge de Internet y su utilizacin para la ejecucin de aplicao o ciones de forma distribuida, han incrementado a n ms el inters de esta caracter u a e stica, debido a la heterogeneidad de las mquinas conectadas a esta red. a Por este motivo han aparecido lenguajes, como Java [AGH00] o C# [AW02], en los que se ha denido el modelo de ejecucin recuperando el concepto de mquina virtual, con o a el objetivo de independizar el cdigo ejecutable de las aplicaciones de la plataforma real o donde se ejecuta. Este modelo de ejecucin consiste en generar, durante la fase de como pilacin, un cdigo intermedio independiente de la mquina f o o a sica. La ejecucin de este o cdigo independiente se hace sobre una mquina virtual (la Java Virtual Machine [LY99], o a en el caso de los programa Java, o la Common Language Infrastructure [Ecm05], en el caso de los programas C#), que se encarga de convertir las instrucciones en las correspondientes a la plataforma real. De esta manera, se puede ejecutar el mismo cdigo sobre o

Introduccin o

cualquier sistema operativo (SO) y en cualquier mquina f a sica, sin necesidad de repetir su compilacin, consiguiendo una portabilidad total. o Estos lenguajes en principio se utilizaban para implementar peque os cdigos que pern o mit exportar servicios a travs de Internet. Sin embargo, su uso se ha extendido y an e diversicado a todos los mbitos de la programacin, hasta ser utilizados para el desarroa o llo de aplicaciones completas. Existen varios motivos que han provocado esta diversicacin. En primer lugar, las facio lidades que ofrecen a los programadores estos lenguajes y sus plataformas de ejecucin. o Estas facilidades van ms all de la portabilidad e incluyen, por ejemplo, programacin a a o orientada a objetos, gestin automtica de memoria, una comprobacin estricta del cdigo o a o o que lo hace robusto y seguro, etc. Adems, el modelo de ejecucin y la utilizacin de la a o o mquina virtual como parte del entorno de desarrollo permite incluir otras caracter a sticas atractivas para los programadores. Por ejemplo, estos entornos garantizan la abilidad del cdigo ejecutado, dan la posibilidad de integrar diferentes lenguajes de programacin y o o dan facilidades para permitir la interoperabilidad entre diferentes componentes software [Ric00]. En segundo lugar, la expansin de Internet ha ofrecido una nueva opcin para la ejecucin o o o de aplicaciones con un alto consumo de recursos. Esta opcin consiste en considerar de o forma global los recursos conectados a Internet para ejecutar de forma distribuida estas aplicaciones. De esta manera es posible explotar mejor estos recursos y, por ejemplo, obtener tiempo de clculo de procesadores que de otra manera se encontrar ociosos a an [CM92, AES97, KaMR02]. Las tcnicas de grid computing van ms all y, entre otros obe a a jetivos, pretenden virtualizar el entorno formado por un conjunto de mquinas conectadas a a Internet [FGT02, BFH03, KFH+ 06]. Por lo tanto, actualmente las plataformas de ejecucin basadas en mquinas virtuales se o a estn utilizando para ejecutar programas con un comportamiento diferente al contemplado a durante su dise o y, en particular, se estn utilizando para la ejecucin de programas con n a o un alto consumo de recursos. Esto signica que es necesario estudiar si estas plataformas son realmente adecuadas para soportar la ejecucin de los nuevos tipos de programas y o

Cap tulo 1

si es posible explotar alguna de sus caracter sticas para mejorar el rendimiento obtenido por estos programas. Esto es especialmente importante si tenemos en cuenta que, el mtodo de ejecucin bae o sado en mquinas virtuales, tiene un coste asociado que disminuye el rendimiento de los a programas con respecto a la ejecucin basada en una compilacin tradicional. Esta diso o minucin no tiene un impacto signicativo cuando se trata de peque os cdigos, como los o n o que inicialmente se utilizaban como parte de las aplicaciones de Internet. Sin embargo, su importancia puede aumentar cuando los cdigos ejecutados tienen mayor envergaduo ra y, aunque el resto de las ventajas de la plataforma compensan esta disminucin del o rendimiento, es conveniente minimizar en lo posible sus efectos. Esta es precisamente la motivacin inicial de este trabajo: es posible aprovechar las o caracter sticas de los entornos de ejecucin basados en mquinas virtuales para soportar de o a forma ecaz la ejecucin de los programas con un alto consumo de recursos, sin renunciar o a las ventajas de este modelo de ejecucin? o Una de las caracter sticas que distingue a este entorno de ejecucin de los entornos trao dicionales basados en compilacin es que, en tiempo de ejecucin, las mquinas virtuales o o a tienen acceso tanto al cdigo como a los datos de los programas. Es decir, tienen ms o a informacin sobre el comportamiento de los programas que los compiladores, que estn o a limitados a la informacin esttica, y que los sistemas operativos, que slo pueden aproxio a o mar este comportamiento usando la informacin que le proporciona el hardware (mediante o algunas excepciones o interrupciones) o los propios programas (mediante las llamadas a sistema). Mediante esta informacin, las mquinas virtuales pueden completar una caracterizacin o a o dinmica y exhaustiva de los programas, que las capacita para determinar qu decisiones a e de gestin de recursos se adaptan a las necesidades de cada programa. Es decir, este tipo o de entorno de ejecucin favorece la utilizacin de pol o o ticas de gestin espec o cas para el comportamiento de cada programa. Hay que decir que los sistemas operativos, tradicionalmente, han implementado pol ticas de propsito general para la gestin de los recursos o o de la mquina, ya que no disponen de suciente informacin sobre el comportamiento de a o

Introduccin o

los programas para ofrecer una gestin espec o ca. Estas pol ticas en trminos generales e ofrecen un rendimiento aceptable en el caso medio. Sin embargo, es posible optimizar la gestin de recursos si para tomar las decisiones de gestin se tiene en cuenta el uso que o o cada programa hace de cada recurso. Se han hecho muchas propuestas para proporcionar a los programas una gestin de reo cursos espec ca. Sin embargo, hasta ahora, ninguna de ellas ha podido satisfacer por completo los requerimientos de este objetivo (ver cap tulo 7). Esto ha sido as porque, o bien no ten acceso a una informacin completa sobre los programas (estrategias baan o sadas en el anlisis esttico de los compiladores y estrategias que implementan pol a a ticas espec cas dentro del SO), o bien no respetaban la abilidad del sistema o el coste de asegurarla limitaba demasiado el rendimiento de los programas (estrategias basadas en permitir que el programador aporte su propio cdigo de gestin). o o En este trabajo proponemos dotar al entorno de ejecucin de una gestin espec o o ca de recursos basada en la cooperacin entre la mquina virtual y el SO, que supera las limio a taciones de los trabajos previos relacionados. En la estrategia que proponemos, por un lado la mquina virtual aporta todo el conocimiento que tiene sobre el comportamiento a de los programas para guiar las decisiones de gestin de los recursos. Por otro lado, el SO o comprueba que las condiciones de ejecucin son las adecuadas para llevar a cabo dichas o decisiones y, de ser as las aplica garantizando la abilidad del sistema. ,

1.2

CASO DE ESTUDIO

Para probar los benecios de la cooperacin entre el sistema operativo y la mquina virtual o a en la gestin de recursos, hemos seleccionado como caso de estudio la gestin de memoria o o en el entorno de ejecucin de los programas Java. Hay que destacar, sin embargo, que la o idea es igualmente aplicable a otros entornos virtualizados de ejecucin y a la gestin de o o otros recursos del sistema.

Cap tulo 1

1.2.1

El lenguaje de programacin Java y su plataforma de o ejecucin o

El lenguaje de programacin Java [AGH00] es un lenguaje orientado a objetos, que fue o dise ado pensando en la ejecucin de programas en un entorno distribuido heterogneo, n o e formado por sistemas empotrados con necesidades de tiempo real [GM96]. En este entorno, se necesitaba un lenguaje robusto, que garantizara la seguridad y que permitiera que los programas fueran totalmente independientes de la arquitectura, para poderlos ejecutar distribuidamente en cualquier nodo de la red heterognea. e Sin embargo, las caracter sticas de Java lo han convertido en un lenguaje de programacin o muy atractivo y su uso se ha extendido a todo tipo de aplicaciones y en entornos de ejecucin muy diferentes al que origin su nacimiento. Por ejemplo, podemos encontrar o o proyectos que trabajan en el uso de Java para aplicaciones de comercio [CHL+ 00], miner a de datos [MMGL99] o aplicaciones cient cas [MMG+ 00]. La plataforma de ejecucin de Java [Kra96] est formada por dos componentes principales: o a la Java Virtual Machine (JVM), que es la mquina virtual en la que se basa el modelo a de ejecucin, y la Java Application Programming Interface (Java API), que constituye el o interfaz, independiente del SO, que ofrece a los programadores los servicios necesarios. El modelo de ejecucin de Java se basa en la JVM [LY99], que es la encargada de aislar los o programas ejecutables de la mquina real donde se ejecutan, y garantiza que un binario de a un programa Java se podr ejecutar en cualquier sistema que disponga de la plataforma a de ejecucin de Java (ver gura 1.1). o As pues, el compilador de Java (en la gura 1.1, javac), genera para cada chero fuente (.java) el chero correspondiente (.class) con el resultado de traducir el cdigo escrito o en Java a un lenguaje intermedio (bytecode), que es un cdigo binario independiente del o sistema real. En tiempo de ejecucin, la plataforma de Java carga en memoria el bytecode que constituo ye el binario del programa y, a medida que el programa invoque funciones de la Java API,

Introduccin o

java API

bytecode .java javac .class

JVM1

SO1

JVM2

SO2

java API tiempo de compilacin tiempo de ejecucin

Figura 1.1 Modelo de ejecucin de Java o

se cargan dinmicamente los cheros que las codican. La JVM se encarga de ejecutar ese a bytecode, convirtindolo en las instrucciones correspondientes al SO y a la mquina real e a que se est utilizando. En este punto hay que mencionar que la JVM ofrece dos posibilia dades para realizar esta conversin: basarla en la interpretacin del bytecode o utilizar un o o compilador al vuelo (compilador just-in-time (JIT)) que, en tiempo de ejecucin, genera o el cdigo mquina correspondiente al bytecode. o a

1.2.2

Gestin de memoria en el entorno de ejecucin de Java o o

La gestin del recurso memoria en el entorno de ejecucin de Java est dividida entre o o a los dos niveles de ejecucin. En el nivel de usuario, la JVM toma todas las decisiones o sobre la organizacin del espacio lgico de los programas Java, mientras que, en el nivel o o de sistema, el SO contin a implementando el resto de tareas relacionadas con la gestin u o de memoria como, por ejemplo, la proteccin entre los diferentes programas en ejecucin o o o la implementacin del mecanismo de memoria virtual. o

Cap tulo 1

Hay que destacar que la gestin del espacio de direcciones que ofrece la plataforma de o ejecucin de Java, constituye una de sus caracter o sticas ms valoradas por los programaa dores ya que es simple, able, robusta, automtica y, en muchos aspectos transparente al a programador (en el cap tulo 2 ofrecemos una descripcin detallada de esta gestin). Por o o ejemplo, el programador no necesita controlar expl citamente las posiciones que ocupan sus datos en memoria ni existe el tipo de dato puntero a memoria, con lo cual desaparece una de las mayores causas de error de programacin y una de las ms complicadas de o a detectar y solucionar. Tambin se evita que el programador tenga que gestionar la libee racin de la memoria ocupada por los datos que ya no necesita, ya que esta liberacin se o o hace automticamente mediante la tcnica de recoleccin de basura (garbage collection). a e o Sin embargo, dado que Java se est utilizando para desarrollar aplicaciones con caraca ter sticas muy distintas a las que en un principio se consideraban, es necesario evaluar la inuencia que esta gestin tiene sobre el rendimiento de estos nuevos tipos de programas. o Por ejemplo, durante el desarrollo inicial de esta plataforma se consideraba un tipo de programas que utiliza un conjunto de datos de trabajo (working set) peque o. Es decir, n son programas que pueden completar su ejecucin sin utilizar el mecanismo de memoria o virtual y, por lo tanto, con una participacin reducida del SO en lo referente a la gestin de o o la memoria. Por este motivo, los esfuerzos durante el diseo de la plataforma se dedicaron n a ofrecer al programador una buena gestin del espacio lgico de direcciones, sin considerar o o la posible interaccin con las decisiones sobre gestin de memoria tomadas por el sistema o o operativo.

1.2.3

Entorno de trabajo

Para realizar este trabajo, en primer lugar es necesario determinar la plataforma a utilizar para el desarrollo de nuestras propuestas. El principal condicionante para esta seleccin o es que necesitamos tener acceso al cdigo fuente de los componentes de la plataforma, o para poder modicarlos libremente e incorporar nuestras propuestas. Por este motivo, hemos seleccionado un SO y una mquina virtual cuyo cdigo es de libre distribucin. a o o En concreto trabajamos sobre el SO Linux y sobre la versin del entorno de desarrollo o de programas Java (J2SDK Standard Edition) que Sun distribuye para Linux. Durante el

Introduccin o

desarrollo de este trabajo hemos utilizado diferentes versiones tanto del SO como de la JVM. En cada cap tulo describimos la versin utilizada para el trabajo que ese cap o tulo presenta. En cuanto al mbito de los programas de prueba, nos hemos centrado en los programas de a clculo cient a co. As en las diferentes fases de este trabajo, hemos utilizado programas de , prueba suministrados por el grupo de trabajo JavaGrande [JGF01] y cdigos que forman o parte del conjunto de programas Java NAS [FSJY03]. Adems hemos implementado un a benchmark sinttico, para utilizar cuando el anlisis de nuestras propuestas hac necesario e a a un cdigo sencillo que nos permitiera un mayor control sobre su ejecucin. o o

1.3

OBJETIVOS Y PLANTEAMIENTO DE ESTE TRABAJO

En este trabajo proponemos introducir en los entornos virtualizados de ejecucin la poo sibilidad de ofrecer a los programas una gestin de recursos espec o ca, aprovechando el conocimiento que tienen las mquinas virtuales sobre el comportamiento de los prograa mas, haciendo que las decisiones de gestin sean compartidas entre el sistema operativo o y las mquinas virtuales. a La tesis que vamos a demostrar en este trabajo es la siguiente: Es posible aprovechar las caracter sticas de las plataformas de ejecucin basadas en mquinas virtuales para permitir o a que soporten de forma ecaz la ejecucin de programas o con alto consumo de recursos, sin renunciar a las ventajas que ofrece su modelo de ejecucin. o

10

Cap tulo 1

Para ello, nuestro objetivo principal es demostrar que: El modelo de ejecucin basado en mquinas virtuales preo a senta la oportunidad de ofrecer a los programas una gestin o de recursos espec ca, que se adapta a su comportamiento dinmico sin comprometer la abilidad del sistema. a El caso de estudio que hemos seleccionado es la gestin de memoria en el entorno de o ejecucin de los programas Java. Por lo tanto, para incorporar en el entorno de ejecucin o o de Java una gestin de memoria adaptada al comportamiento de los programas, el primer o paso es analizar el uso que estos programas hacen de la memoria y cmo se ven afectados o por las decisiones que se toman sobre la gestin de este recurso. Las conclusiones de este o anlisis deben indicar si es posible mejorar el rendimiento de los programas, modicando a las pol ticas de gestin de memoria existentes o incluyendo alguna nueva pol o tica ms a adecuada. En cualquier caso, hay que garantizar que las decisiones que se tomen tendrn a en cuenta el comportamiento particular de cada programa y, adems, se respetar la a a abilidad del sistema. As pues, los objetivos aplicados de este trabajo son:

Analizar detalladamente la gestin de memoria que ofrece el entorno de o ejecucin de Java y las posibles interacciones entre las tareas que se desao rrollan en cada nivel de ejecucin (ver cap o tulo 2). Evaluar el uso de la memoria que hacen los programas Java y la inuencia que tiene la gestin de memoria sobre su rendimiento (ver cap o tulo 3). Proponer los cambios y las pol ticas de gestin de memoria adecuadas para o mejorar el rendimiento de los programas (ver cap tulo 3). Introducir estos cambios en el entorno de ejecucin de Java (ver cap o tulos 4, 5 y 6): Diseando la estrategia que deben seguir las pol n ticas de gestin que o se van a introducir en el entorno de ejecucin, para que sus decisiones o se puedan adaptar al comportamiento de cada programa.

Introduccin o

11

Implementando estas pol ticas mediante un cdigo eciente, que favoo rezca la ecacia de las pol ticas de gestin. o Y evaluando la implementacin para demostrar que el entorno de ejeo cucin modicado con nuestras propuestas realmente mejora el rendio miento de las aplicaciones.

2
GESTION DE MEMORIA PARA LOS PROGRAMAS JAVA

En este cap tulo presentamos la gestin de memoria que ofrece el entorno de ejecucin o o de Java. Esta gestin aparece distribuida entre los dos niveles de ejecucin (nivel de o o usuario y nivel de sistema), ya que la JVM se encarga de implementar la organizacin y el o mantenimiento del espacio de direcciones de los programas, mientras que el SO conserva el control del resto de tareas de gestin de memoria. o En la seccin 2.1 describimos las tareas involucradas en la gestin de memoria y cmo o o o se reparten entre los dos componentes principales del entorno de ejecucin (SO y JVM). o A continuacin la seccin 2.2 describe la implementacin que hace el SO de las tareas o o o de gestin de memoria que lleva a cabo y la seccin 2.3 describe la implementacin de o o o las tareas que ejecuta la JVM. Cierra el cap tulo las conclusiones que hemos extra del do estudio que sobre la gestin de memoria del entorno. o

2.1

DIVISION DE TAREAS ENTRE EL SO Y LA JVM

Las tareas de gestin de memoria de un proceso se pueden separar en dos grandes grupos. o Por un lado, es necesario gestionar el espacio lgico de direcciones del proceso. Es decir, o hay que permitir la reserva y la liberacin de memoria en tiempo de ejecucin, y manteo o ner qu regiones del espacio de direcciones son vlidas y qu permisos de acceso tienen e a e asociados.

13

14

Cap tulo 2

Por otro lado, hay que implementar la traduccin de direcciones, manteniendo la relacin o o entre las direcciones lgicas y las posiciones f o sicas que realmente ocupan. Como parte de esta tarea se implementa la proteccin entre los accesos a memoria f o sica de los diferentes procesos que estn en ejecucin y se implementa el mecanismo de memoria virtual. Este a o mecanismo permite que parte de los espacios de direcciones de los procesos en ejecucin o se mantengan fuera de memoria f sica, en el almacenamiento secundario (rea de swap), a ya que se garantiza su carga en memoria f sica siempre que el proceso necesite acceder a esas zonas. En el caso del entorno de ejecucin de Java, la JVM releva al SO de las tareas de gestin o o del espacio lgico de direcciones de los programas. Para ello, al principio de la ejecucin le o o pide al SO que valide el tama o mximo de memoria que se va a dedicar para almacenar los n a objetos del programa. A partir de ese momento, la JVM gestiona esa memoria, decidiendo las posiciones que ocupan en cada momento los objetos dentro de este espacio y liberando la memoria ocupada por objetos que dejan de estar en uso. Sin embargo, el SO sigue implementando la gestin de la traduccin de direcciones y del mecanismo de memoria o o virtual, lo cual garantiza la abilidad e integridad del sistema. Esto signica que la gestin de memoria de un proceso aparece separada entre los dos o niveles de ejecucin: la gestin del espacio lgico de direcciones se lleva a cabo en el nivel o o o de usuario y la asociacin con el espacio f o sico contin a ejecutndose en el nivel de sistema u a (ver gura 2.1). Hay que destacar que ambos niveles de gestin se ejecutan independientemente, aunque o las decisiones y la ejecucin de uno de ellos pueden afectar al rendimiento de las decisiones o del otro nivel. En el dise o de la JVM no se tuvo en cuenta el efecto de esta interaccin ya n o que se pensaba en un entorno de ejecucin en el que apenas se utilizaba el mecanismo de o memoria virtual. Recordemos que el objetivo inicial era ejecutar programas de tiempo real para dispositivos empotrados, y este tipo de programas no deben usar la memoria virtual, porque eso ralentizar su ejecucin y podr ser que no cumplieran con las restricciones a o a de tiempo. Por ese motivo, es necesario estudiar el efecto de esta interaccin para aquellos o programas Java que s necesitan utilizar el mecanismo de memoria virtual.

Gestin de memoria para los programas Java o

15

SO JVM

reemplazo fallo de pgina

disco p p

memoria fsica espacio lgico

Figura 2.1 Gestin de memoria en el entorno de ejecucin de Java o o

A continuacin vamos a describir brevemente los aspectos ms relevantes de ambos niveles o a de gestin en nuestro entorno de trabajo, as como las posibles interacciones que pueden o aparecer entre ellos.

2.2

GESTION DE LA MEMORIA VIRTUAL EN LINUX

La gestin de memoria virtual en Linux se basa en paginacin bajo demanda. Es decir, si o o un proceso accede a una pgina de su espacio lgico de direcciones que no tiene asociada a o una pgina f a sica, el hardware genera una excepcin (fallo de pgina) que Linux resuelve o a para que el proceso pueda completar el acceso a memoria. Para poder resolver el fallo de pgina, Linux debe reservar una pgina f a a sica y asociarla a la pgina lgica, actualizando la tabla de pginas del proceso. Adems, si la pgina lgica a o a a a o contiene informacin, entonces es necesario recuperar esa informacin y escribirla en la o o pgina f a sica reservada. Hay que decir que el mtodo utilizado para recuperar los datos de e la pgina depende del tipo de regin al que pertenezca y de si se trata del primer acceso o a o

16

Cap tulo 2

no. Por lo tanto, en funcin de las tareas involucradas en la resolucin del fallo de pgina, o o a podemos distinguir tres situaciones distintas:

Fallo debido al primer acceso a una pgina de memoria annima: las regiones de a o memoria annima son las que no estn respaldadas por ningn dispositivo lgico y o a u o su contenido ser el almacenado por el programa durante la ejecucin. Es decir, en a o el momento de la creacin se consideran vac Por lo tanto, para resolver este tipo o as. de fallo de pgina, Linux slo reserva una pgina f a o a sica libre y la asocia a la pgina a lgica. o Fallo debido al primer acceso a una pgina de memoria mapeada: en Linux es poa sible mapear el contenido de un dispositivo lgico sobre una regin del espacio de o o direcciones y acceder a ese dispositivo a travs de la regin que lo mapea. Para este e o tipo de regiones, el fallo de pgina debido a un primer acceso debe localizar los datos a correspondientes en el dispositivo lgico asociado para cargarlos en la pgina f o a sica que se reserve. Fallo debido al acceso a una pgina ya en uso: cuando no se trata del primer acceso a a una pgina, signica que esa pgina lgica ha tenido que ser expulsada al rea de a a o a swap. Por lo tanto, es necesario localizar los datos en el rea de swap y cargarlos en a memoria f sica.

Hay que destacar que el tiempo dedicado a resolver un fallo de pgina es muy diferente a si es necesario realizar una carga de informacin en memoria f o sica (como los dos ultimos casos) o si es posible resolverlos sin ning n acceso a un dispositivo lgico (como en el caso u o del primer fallo de pgina sobre memoria annima). Por este motivo, Linux denomina a o fallos de pgina hard o major a aquellos que involucran una operacin de carga, y fallos a o de pgina soft o minor a los que se resuelven sin esa carga asociada. a En este punto, es interesante mencionar que, adems del primer acceso a una pgina de a a memoria annima, hay otras excepciones de fallo de pgina generadas por el hardware o a que Linux clasica como fallos soft. Son accesos que tampoco requieren la carga de la informacin, bien sea porque ya est presente en memoria f o a sica y slo es necesario aco tualizar la tabla de pginas, o porque ya se encuentra en proceso de ser cargada debido a a

Gestin de memoria para los programas Java o

17

una solicitud previa. Por ejemplo, Linux implementa la optimizacin copy on write para o gestionar el uso de la copia de memoria que se da, por ejemplo, durante la creacin de o nuevos procesos. Esta tcnica se basa en permitir la comparticin de la memoria copiada e o mientras ning n proceso intente escribir en la regin, momento en el que la copia se hace u o realmente efectiva. Para detectar esta situacin, Linux marca en la tabla de pginas que o a las pginas involucradas son de slo lectura. De esta manera, un acceso de escritura sobre a o una de esas pginas provoca una excepcin de fallo de pgina que, si la pgina ya est cara o a a a gada, se puede resolver efectuando la copia en una nueva pgina f a sica y actualizando la tabla de pginas con la nueva asociacin y con el permiso de escritura ya activado. Es a o decir, es un fallo de pgina que no necesita ninguna carga para ser resuelto y que, por a tanto, forma parte de los fallos de pgina soft. a

2.2.1

Algoritmo de reemplazo

Un aspecto importante relacionado con la memoria virtual es el algoritmo de reemplazo. Este algoritmo es el encargado de decidir qu pginas del espacio lgico de direcciones de e a o un proceso son expulsadas al rea de swap. El objetivo es mantener en memoria f a sica las pginas activas, es decir, las pginas que los procesos estn utilizando. De esta manera, se a a a intenta minimizar el n mero de fallos de pgina por accesos a pginas que se encuentran u a a en el rea de swap, ya que el acceso a disco necesario para solventar estas excepciones a ralentiza la ejecucin de los programas. o El algoritmo utilizado por Linux es una aproximacin del LRU (Least Receantly Used). El o algoritmo LRU se basa en el hecho de que el pasado reciente de un proceso aproxima su futuro inmediato. As selecciona como pginas v , a ctimas aquellas que hace ms tiempo que a no se referencian, suponiendo que sern las que el proceso tarde ms en necesitar. Para a a poder implementar este algoritmo ser necesario actualizar la informacin sobre el uso de a o la memoria para cada referencia a una pgina, lo que a adir un alto coste al tiempo de a n a ejecucin. Por ese motivo, los sistemas reales implementan algoritmos que aproximan el o comportamiento del LRU. En el caso de Linux, divide la memoria en dos listas diferentes: las pginas activas y las pginas inactivas. Cada vez que es necesario liberar pginas, a a a primero recorre la lista de pginas inactivas, reactivando aquellas pginas que han sido a a referenciadas (se mueven a la lista de pginas activas) y liberando las pginas que no lo a a

18

Cap tulo 2

han sido (ver gura 2.2). Hay que decir que, si antes de completar la liberacin de una o pgina, el proceso intenta referenciarla de nuevo, el fallo de pgina provocado es un fallo a a de pgina soft que Linux resuelve asociando de nuevo la pgina lgica con la pgina f a a o a sica que conserva los datos. Una vez nalizado el tratamiento de la lista de pginas inactivas, a el algoritmo de reemplazo recorre la lista de pginas activas actualizando el contador de a actividad de cada pgina, que sirve para decidir cundo se mueve la pgina a la lista de a a a pginas inactivas: si la pgina ha sido referenciada desde la ultima ejecucin del algoritmo, a a o se incrementa su contador de actividad y en caso contrario se decrementa.

lista de pginas activas

sin actividad

accedida

lista de pginas inactivas

vctimas

rea de swap

lista de pginas libres

Figura 2.2 Reemplazo de memoria en Linux

2.2.2

Prefetch de pginas a

Tambin con el objetivo de minimizar el n mero de fallos de pgina, Linux implementa e u a una pol tica muy simple de carga anticipada (prefetch). Esta pol tica est limitada por la a poca informacin que tiene el sistema sobre los accesos a memoria de los procesos, que o no le permite implementar una prediccin de accesos futuros elaborada. Por este motivo, o el prefetch de Linux simplemente, para cada fallo de pgina, solicita del disco la carga de a un n mero determinado de pginas consecutivas a partir de la que ha provocado el fallo. u a El n mero de pginas cargadas con antelacin es un parmetro del sistema, global para u a o a

Gestin de memoria para los programas Java o

19

todos los procesos y congurable por el administrador de la mquina. Linux no actualiza a la tabla de pginas del proceso con las pginas cargadas con antelacin hasta que ocurre la a a o primera referencia. Es decir, esta carga anticipada tambin involucra fallos de pgina soft. e a Hay que destacar que esta pol tica slo puede favorecer a las aplicaciones que acceden de o forma secuencial al espacio de direcciones. Es ms, el prefetch de pginas errneas puede a a o perjudicar el rendimiento de la mquina ya que se estn cargando pginas no necesarias a a a que pueden provocar la expulsin de pginas que s son utiles para los procesos. Por o a este motivo, las versiones actuales de Linux slo utilizan este mecanismo si el sistema de o memoria no est sobrecargado. a

2.3

GESTION DEL ESPACIO LOGICO DE DIRECCIONES EN JAVA

La JVM es la encargada de gestionar el espacio lgico de direcciones de los programas o Java. En esta gestin hay que destacar tres aspectos importantes: la estructuracin del o o heap del programa, la reserva de nuevos objetos y la liberacin de objetos no necesarios. o El heap es la zona del espacio de direcciones donde la JVM almacena los objetos de los programas. Al inicio de la ejecucin la JVM pide al SO que valide suciente memoria o lgica para soportar el tama o mximo de heap que el programa puede utilizar, aunque o n a inicialmente no sea necesario todo ese espacio. De esta manera, la JVM pasa a administrar ese espacio lgico, decidiendo en cada momento qu cantidad de memoria es adecuada o e para que el programa se ejecute. Tanto el tama o mximo del heap como el tama o inicial n a n que se ofrece al programa son parmetros de la ejecucin que puede decidir el usuario al a o lanzar el programa, aunque ambos tienen valores por defecto. La reserva de memoria en Java se hace bajo peticin de los programas. Cuando el programa o crea un nuevo objeto, la JVM primero comprueba si hay suciente espacio en el heap, y, en ese caso, busca na zona apropiada para el nuevo objeto. Esto signica que la JVM sabe exactamente las direcciones de memoria asociadas a cada objeto y, por lo tanto, las direcciones involucradas en cada acceso. Como consecuencia de la reserva de un nuevo objeto, es posible que la JVM decida hacer crecer el espacio utilizado por el heap, siempre

20

Cap tulo 2

respetando los l mites establecidos por el tama o inicial y el tama o mximo al inicio de n n a la ejecucin. o En cuanto a la liberacin de memoria, est basada en el mecanismo de garbage collection o a y, por lo tanto, es automtica y transparente al usuario [JL96a]. Cuando la JVM detecta a que la ocupacin del heap hace necesario liberar memoria, inicia el proceso de garbage o collection, buscando aquellos objetos que ya no estn en uso y liberando la memoria que a ocupaban. Adems, Java tambin ofrece a los programadores un method para provocar la a e ejecucin expl o cita de la liberacin de memoria. o Todas estas tareas de gestin pueden inuir en el rendimiento de la memoria virtual de o la mquina de dos posibles maneras. Primero, por las decisiones que se toman durante la a gestin. Por ejemplo, agrupar en las mismas pginas aquellos objetos que se utilizan al o a mismo tiempo puede reducir el n mero de fallos de pgina de los programas. Y, segundo, u a por la propia ejecucin de los algoritmos de gestin. Tanto el algoritmo de reserva como o o el algoritmo de liberacin pueden implicar recorridos del heap, y estos recorridos, por o un lado, pueden provocar nuevos fallos de pgina y, por otro lado, pueden alterar la a informacin que utiliza el algoritmo de reemplazo de memoria virtual para seleccionar las o pginas v a ctimas. Por este motivo, es necesario estudiar la inuencia de esta interaccin en el rendimiento o de los programas Java que requieren el uso de la memoria virtual. Si esta interaccin es o responsable de una penalizacin signicativa sobre el rendimiento, entonces mejorar la o interaccin entre ambos niveles puede ser un camino para aumentar el rendimiento de o estos programas, sin renunciar a las ventajas de la plataforma de ejecucin. o A continuacin describimos en detalle la implementacin de las tareas de gestin en dos o o o mquinas virtuales diferentes. Las dos mquinas que vamos a describir vienen suminisa a tradas por el entorno de desarrollo de programas Java de Sun que hemos utilizado (Java 2 SDK Standard Edition para Linux). Este entorno de ejecucin permite que el usuario o pueda seleccionar la JVM que quiere utilizar para la ejecucin de sus programas. Estas o mquinas virtuales son la JVM classic, versin 1.2.2 (seccin 2.3.1), y la JVM HotSpot, a o o versin 1.3.1 (seccin 2.3.2). o o

Gestin de memoria para los programas Java o

21

2.3.1

Gestin del heap en la JVM classic o

El heap que implementa la JVM classic est totalmente contiguo en memoria lgica y a o est dividido en dos zonas separadas. En la primera se sitan las cabeceras de los objetos a u (handles) y en la segunda los objetos propiamente dichos (ver gura 2.3). Cada cabecera contiene las caracter sticas del objeto al que representa y la direccin donde se encuentra. o Esta separacin de cabeceras y datos facilita los posibles cambios de posicin de los objetos o o supervivientes, que pueden ser necesarios para eliminar la fragmentacin externa del heap, o despus de una liberacin de memoria. Sin embargo, acceder a un objeto en esta JVM e o requiere como m nimo dos accesos a memoria: uno para obtener su direccin y otro para o acceder realmente a los datos.

HEAP
cabeceras objetos

cmin lmite inferior heap

cmax/omin ltima reserva

omax lmite superior heap

Figura 2.3 Organizacin del heap en la JVM classic o

La reserva de memoria se hace de forma secuencial y c clica. Cuando el programa instancia un nuevo objeto, la JVM busca en el heap suciente memoria contigua para situarlo, empezando en el punto donde naliz la ultima reserva de memoria. La b squeda acaba o u cuando se encuentra una regin de tama o suciente o cuando se alcanza el punto inicial de o n la b squeda. Este mtodo c u e clico tiene como objetivo reaprovechar los huecos aparecidos por las liberaciones previas de objetos en desuso. Hay que destacar que este algoritmo, en el peor de los casos recorre toda la zona de datos y, por lo tanto, es una potencial fuente de fallos de pgina. a

22

Cap tulo 2

La liberacin de memoria se hace mediante el algoritmo de garbage collection mark and o sweep with compact [JL96b]. Este algoritmo se divide en tres fases principales:

Fase de marcado (mark): durante esta fase se recorre la zona de handles para detectar y marcar aquellos objetos que estn referenciados (objetos vivos) y que, por lo tanto, a no se pueden liberar. Fase de barrido (sweep): una vez marcados los objetos vivos, el algoritmo accede a la zona de objetos para liberar la memoria que ocupan los objetos que no se estn a marcados (objetos muertos). Ntese que en esta fase se est accediendo a zonas de o a memoria que en realidad ya no estn en uso y, por lo tanto, se est alterando la a a informacin sobre el comportamiento del programa que recibe el SO. o Fase de compactacin (compact): una vez liberada la memoria ocupada por los objeo tos muertos, el algoritmo comprueba si el grado de fragmentacin externa del heap o aconseja compactar la memoria libre, para evitar que el rendimiento del algoritmo de reserva degenere. El algoritmo de compactacin puede involucrar varios recorridos de o la zona de objetos, ya que intenta mover cada objeto vivo al primer hueco libre de la zona de objetos, con suciente espacio para soportarlo. Por lo tanto, esta fase tambin puede alterar la informacin sobre el uso de la memoria que hace el programa. e o Adems, al recorrer el heap varias veces, es una potencial fuente de fallos de pgina, a a que se a adir a los fallos de pgina propios del cdigo del programa. n an a o

Una vez nalizada la liberacin de objetos muertos, la JVM comprueba si es conveniente o aumentar el tama o utilizable del heap, siempre respetando los l n mites del tama o mxin a mo. Esta ultima operacin es muy simple, ya que unicamente requiere modicar el valor o de los l mites del heap. En la gura 2.4 representamos el algoritmo ejecutado para liberar memoria cuando no es posible satisfacer la reserva de memoria para un nuevo objeto.

Gestin de memoria para los programas Java o

23

reserva ok = reserva(&ultima reserva, tamao); n if (!reserva ok) { marcar objetos refereciados(); compactar = barrer objetos no marcados(); ultima reserva = omin; if (compactar) { compactar heap(); ultima reserva = ultimo objeto(); } if (necesita expandir) expandir heap(); n reserva ok = reserva(&ultima reserva, tamao); }

Figura 2.4 Algoritmo de la liberacin de memoria: marcado y barrido con compactacin o o

2.3.2

Gestin del heap en la JVM HotSpot o

Cuando se implement la JVM HotSpot, la plataforma Java ya se estaba utilizando pao ra una amplia gama de aplicaciones diferentes. Por este motivo se intent favorecer a o aquellas aplicaciones con mayor consumo de recursos. Este esfuerzo se ve reejado en la implementacin del modelo de memoria y del garbage collector [Sun01]. o En esta versin de la JVM los objetos ya no aparecen separados de sus cabeceras, lo que o elimina el problema de la doble indireccin necesaria para acceder a los datos. Adems se o a ha conseguido reducir la cabecera de la mayor de los objetos a slo dos bytes, en lugar a o de los tres bytes necesarios en la versin classic, lo que disminuye la cantidad de memoria o necesaria para albergar la misma cantidad de objetos. En la versin 1.3.1 de HotSpot, que es la que hemos utilizado en este trabajo, tanto la o organizacin del heap como el mtodo de reserva de nuevos objetos depende en gran o e medida del algoritmo de garbage collection utilizado. En esta versin, el usuario puede o escoger entre dos garbage collectors generacionales diferentes.

24

Cap tulo 2

Los garbage collectors generacionales [SMM99, WLM92] estn pensados para favorecer a la localidad de referencia y se basan en la suposicin de que la mayor de objetos Java o a tienen una vida corta. Por este motivo, la zona de objetos se divide en dos partes: la zona de objetos de reciente creacin (generacin joven) y la zona de objetos donde se o o van almacenando los objetos que llevan ms tiempo en ejecucin (generacin vieja) (ver a o o gura 2.5). As estos garbage collectors acceden frecuentemente a la zona de los objetos , jvenes para eliminar los que ya no estn en uso (minor collections). Cada vez que un o a objeto sobrevive a una recoleccin se incrementa su edad. Cuando la edad de un objeto o llegue a un determinado l mite se considera que es un objeto viejo y se mueve a la zona de objetos viejos. Slo cuando una minor collection no consigue liberar suciente memoria, o se recurre a una limpieza ms profunda de la zona de objetos, que considera tambin la a e zona de objetos viejos (major collection). Por lo tanto, si se cumple la premisa en la que se basan estos garbage collectors y la mayor de objetos mueren jvenes, entonces se reduce la cantidad de memoria que el a o garbage collector tiene que acceder para liberar los objetos muertos. Es decir, se limitan las posibles interacciones con el mecanismo de memoria virtual.

HEAP
generacin vieja generacin joven

objetos viejos

eden

from

to

viejos max lmite inferior heap ltima reserva

jvenes max lmite superior heap

Figura 2.5 Organizacin del heap en la JVM HotSpot o

Gestin de memoria para los programas Java o

25

Los dos garbage collectors que ofrece la versin 1.3.1 de HotSpot coinciden en el algoritmo o utilizado para las minor collections, que es mark and copy. Para ello, la zona de objetos jvenes a su vez est divida en 3 zonas diferentes (ver gura 2.5). La zona que se usa para o a crear objetos nuevos (eden), una zona que se utiliza para almacenar los supervivientes y en la que se reservan objetos que no han cabido en el eden (from) y una zona que se utiliza durante la copia (to). Durante la minor collection se van copiando en la zona to todos los objetos de eden y from que a n estn vivos. Una vez nalizada la liberacin, la u a o zona from y la zona to intercambian los papeles, mientras que la zona eden queda vac y a preparada para alojar a los nuevos objetos que se creen a continuacin (ver gura 2.6). o

supervivientes viejos

supervivientes jvenes

objetos viejos

eden

from to

viejos max lmite inferior heap ltima reserva

jvenes max lmite superior heap

Figura 2.6 Liberacin de memoria de la generacin joven en la JVM HotSpot o o

Las diferencias entre los dos garbage collectors ofrecidos radican en el mtodo usado para e las major collections. Aunque los dos mtodos usan el algoritmo mark and sweep with e compact, explicado en la seccin 2.3.1 (ver gura 2.4), ambos se diferencian en la zona o sobre la que se ejecuta el algoritmo. En el garbage collector que se utiliza por defecto, cada major collection se hace sobre toda la zona de objetos viejos. La alternativa a esta opcin, es solicitar una limpieza incremental, en cuyo caso cada major collection se hace o slo sobre una porcin de la zona de objetos viejos. Esta alternativa est orientada a o o a disminuir el tiempo de pausa de los programas, necesario mientras dura la limpieza de objetos. Para utilizar la opcin del garbage collector incremental, es necesario dividir el o

26

Cap tulo 2

heap en diferentes zonas (trenes), de manera que cada ejecucin de una major collection o analiza una tren diferente. En cuanto a la reserva de nuevos objetos siempre se hace en la zona de la generacin o joven, de forma consecutiva. La copia de los objetos supervivientes tambin se hace a e continuacin del ultimo objeto. Hay que decir que, durante la copia de los objetos jvenes o o supervivientes, se intenta situar prximos en el heap los objetos que estn relacionados, o a es decir, los objetos que se referencian entre s con el objetivo de agrupar los objetos que , tienen una alta probabilidad de ser accedidos con proximidad en le tiempo. En cuanto a los objetos que deben ser movidos a la zona de los objetos viejos, tambin se copian a e continuacin del ultimo objeto de la zona. En el caso del garbage collector incremental, se o tiene que decidir adems si el objeto que pasa a la generacin vieja se incluye en el ultimo a o tren existente, o si es necesario crear un tren nuevo (esta decisin afecta a la cantidad de o objetos que se analizan en cada major collection).

2.4

CONCLUSIONES

En este cap tulo hemos presentado brevemente cmo se gestiona el uso de la memoria en o el entorno de ejecucin de Java. En este entorno, el SO sigue siendo el responsable de o gestionar la asociacin entre las direcciones del espacio lgico del programa y la posicin o o o f sica que ocupan. Sin embargo, la JVM es la encargada, desde el nivel de usuario, de gestionar el espacio lgico de direcciones de los programas de forma transparente al SO. o Esta separacin de la gestin de memoria entre los dos niveles de ejecucin tiene como o o o ventaja que la JVM puede adaptar las decisiones sobre el espacio de direcciones al comportamiento del programa, intentando, por ejemplo, favorecer la localidad de referencia del programa. Adems, al no requerir la participacin del sistema en cada nueva reserva, a o puede mejorar el rendimiento de los programas que necesiten crear un gran n mero de u objetos durante su ejecucin. Sin embargo, es necesario estudiar la interaccin que tienen o o entre s las decisiones tomadas de forma independiente en los dos niveles de ejecucin, ya o que, durante el dise o del lenguaje Java, no se tuvo en cuenta el efecto de esta interaccin. n o Hay que decir que, las versiones ms actuales de JVM, como la JVM HotSpot, tienen una a implementacin ms cuidadosa de la gestin del espacio lgico, que pretende favorecer el o a o o

Gestin de memoria para los programas Java o

27

rendimiento de la memoria virtual. A pesar de ello, en el trabajo relacionado no existe ning n estudio detallado sobre el efecto que tiene esta separacin de la gestin de memoria u o o entre los dos niveles sobre el rendimiento de los programas que hacen un uso intensivo del mecanismo de memoria virtual. En el cap tulo 3 presentamos un anlisis minucioso a de varios programas que necesitan del uso de la memoria virtual para poder completar su ejecucin, y vemos cmo se puede mejorar el rendimiento de este mecanismo desde la o o gestin de memoria implementada como parte de la JVM. o

3
EVALUACION DEL USO DE LA MEMORIA VIRTUAL DE LOS PROGRAMAS JAVA

En este cap tulo presentamos la evaluacin que hemos hecho del uso de la memoria de o algunos programas Java que tienen un consumo importante de recursos. El objetivo de esta evaluacin es comprobar si estos programas se ven afectados por el rendimiento de o la memoria virtual y obtener las causas de esta inuencia. Adems, queremos determinar a si es posible mejorar el rendimiento de los programas Java mediante alguna pol tica de gestin de memoria que aproveche las caracter o sticas propias del entorno de ejecucin de o Java. Para ello hemos contado y clasicado los fallos de pgina provocados por los prograa mas, as como el tiempo involucrado en estos fallos de pgina. De esta manera podemos a cuanticar la penalizacin que el uso de la memoria virtual a ade al rendimiento de los o n programas. Nuestra clasicacin nos permite distinguir entre los fallos de pgina provoo a cados por el propio cdigo del programa y los fallos de pgina debidos a la ejecucin del o a o cdigo de gestin. Adems, para completar la caracterizacin y as acotar nuestro estuo o a o dio, hemos separado los fallos de pgina en funcin de la zona del espacio de direcciones a o accedida (ver seccin 3.2). o Por otro lado, tambin hemos obtenido una cota mxima del rendimiento de estos prograe a mas, simulando su ejecucin sobre un sistema de gestin de memoria perfecto. Esta cota, o o aunque sea inalcanzable, nos permite estimar si existe margen de mejora en el sistema de memoria (seccin 3.3). o

29

30

Cap tulo 3

Por ultimo, hemos hecho un anlisis del tipo de objetos que utilizan los programas (seccin a o 3.4). El objetivo de este anlisis es completar la informacin sobre el uso de la memoria a o que hacen los programas, para as facilitar las propuestas de mejora de la gestin de o memoria.

3.1

ENTORNO DE TRABAJO

En esta seccin vamos a describir el entorno de trabajo que hemos utilizado para la o evaluacin del uso de la memoria. o Como ya se ha explicado en el cap tulo 1 el SO sobre el que hemos desarrollado este trabajo es Linux. La versin del kernel que hemos utilizado para esta evaluacin es la 2.2.12. o o En cuanto a la mquina virtual de Java, hemos utilizado tanto la JVM classic como la a JVM HotSpot, ambas suministradas por Sun como parte del entorno de desarrollo J2SDK Standard Edition. Inicialmente, hemos evaluado la inuencia de la memoria virtual en el rendimiento de los programas utilizando la JVM classic (versin 1.2.2). Una vez hecha o esta evaluacin hemos comparado los resultados con la ejecucin sobre la JVM HotSpot o o (versin 1.3.1), lo que nos ha permitido validar las conclusiones que hab o amos obtenido sobre la JVM classic. Para ambas mquinas virtuales, hemos utilizado la versin basada a o unicamente en la interpretacin de los programas, sin utilizar compilacin al vuelo, para o o facilitar la introduccin en las JVM de nuestras herramientas de medida. o Todos los experimentos de este evaluacin los hemos ejecutado sobre un PC con un proo cesador Pentium III a 500 Mhz con 128Mb de memoria f sica.

3.1.1

Programas de prueba

El grupo JavaGrande [JGF01] trabaja sobre el uso de Java para computacin de altas o prestaciones. Este grupo suministra un conjunto de programas de prueba, para que se utilicen en la comparacin del rendimiento de entornos Java cuando ejecutan programas o con gran consumo de recursos (aplicaciones grandes) [BSW+ 00].

Evaluacin del uso de la memoria virtual de los programas Java o

31

En este conjunto de programas hay algunos n cleos de uso frecuente en computacin de u o altas prestaciones y algunas aplicaciones completas. Para cada programa se suministran tres versiones, con datos de entrada de diferentes tama os, identicadas, de menor a mayor n tama o, como SizeA, SizeB y SizeC. n De todo este conjunto de programas, hemos seleccionado los que tienen un consumo de memoria suciente para que sea necesario el uso de la memoria virtual. La tabla 3.1 resume para cada uno de los benchmarks que hemos utilizado el tama o de entrada n correspondiente a cada versin (hemos marcado en negrita los datos correspondientes a la o versin que utilizamos en los experimentos). A continuacin describimos brevemente estos o o benchmarks junto con la versin que utilizamos en los experimentos (para una descripcin o o completa se puede consultar [JGF01]).
Programas Crypt HeapSort MonteCarlo FFT Sparse Unidades de la entrada Bytes Enteros Muestras Nmeros complejos u Doubles SizeA 3.000.000 1.000.000 10.000 2.097.152 50.000x50.000 SizeB 20.000.000 5.000.000 60.000 8.388.608 100.000x100.000 SizeC 50.000.000 25.000.000 n.a. 16.777.216 500.000x500.000

Tabla 3.1 Tama os de entrada de los benchmarks n

Crypt: Este es un kernel que implementa la encriptacin y desencriptacin de un o o array, usando el algoritmo International Data Encryption (IDEA). Para este kernel hemos seleccionado el tama o mayor (SizeC), que trabaja sobre un array de 50.000.000 n bytes. HeapSort: Este kernel ordena un array de enteros mediante el algoritmo de ordenacin heap. El tama o que hemos utilizado es el mayor (SizeC), que tiene como o n entrada un array de 25.000.000 enteros. MonteCarlo: Este programa consiste en una aplicacin completa que implementa o una simulacin nanciera basada en tcnicas Monte Carlo, para derivar precios en o e base de unos datos histricos. Para esta aplicacin slo se suministran dos versiones o o o y hemos elegido la ms peque a (SizeA), que genera 10.000 elementos de la serie a n temporal, porque consume suciente memoria para presionar al sistema de memoria.

32

Cap tulo 3

FFT: Este kernel implementa una transformada de Fourier sobre un conjunto de n meros complejos. Hemos usado la versin ms peque a de este programa, ya que u o a n sta consume suciente memoria (SizeA). Esta versin trabaja sobre 2.097.152 n mee o u ros complejos. Sparse: Este kernel multiplica 200 veces una matriz dispersa por un vector denso. La matriz est almacenada comprimiendo las las. Para este kernel hemos seleccionado a la versin de mayor tama o (SizeC), en la que la matriz tiene 500.000 x 500.000 o n doubles.

3.2

EVALUACION DEL RENDIMIENTO DE LA GESTION DE MEMORIA

Hemos hecho tres grupos de experimentos para evaluar el rendimiento de la gestin de o memoria actual. El primer grupo nos ha permitido obtener el tiempo que el sistema dedica a gestionar fallos de pgina para los programas de prueba. De esta manera, cuanticamos a la relevancia que tiene la memoria virtual sobre el rendimiento de los programas. Los otros dos grupos de experimentos nos han servido para determinar el tipo de accesos ms a afectado por el uso de la memoria virtual, clasicndolos en funcin de la zona del espacio a o de direcciones accedida y del tipo de cdigo en ejecucin. El resultado de esta clasicacin o o o ha servido para acotar nuestros objetivos para la mejora de la gestin de memoria. o

3.2.1

Clasicacin de los fallos de pgina o a

Para poder realizar esta evaluacin hemos denido la siguiente clasicacin para los fallos o o de pgina. a En primer lugar, hemos separado los fallos de pgina que implican un acceso a disco a (hard) de aquellos fallos de pgina que se pueden resolver sin ning n acceso a disco (soft). a u Ejemplos de tipos de acceso que provocan un fallo de pgina soft son el primer acceso a a una pgina sin datos, un acceso que se reere a una pgina que ya est siendo cargada (por a a a ejemplo, como consecuencia de una operacin de prefetch), o un acceso a una pgina que o a

Evaluacin del uso de la memoria virtual de los programas Java o

33

est en proceso de ser expulsada al rea de swap pero que todav no se ha hecho efectiva a a a la escritura en disco y, por lo tanto, es posible reactivarla. Hacemos esta distincin porque o el tiempo necesario para resolver estos dos tipos de fallos de pgina es muy diferente, ya a que el tiempo de acceso a disco domina claramente sobre el resto de tiempo necesario para la resolucin de un fallo de pgina. o a Para obtener la zona del espacio de direcciones ms afectada por los fallos de pgina hemos a a distinguido entre tres zonas diferentes: zona de objetos, zona de cabeceras y accesos fuera del heap. En este ultimo grupo se engloban fallos provocados por accesos al cdigo del o programa, a las pilas de los ujos de ejecucin, etc. o Por ultimo hemos separado los fallos de pgina provocados durante la ejecucin de cdi a o o go de gestin de los provocados durante la ejecucin del cdigo del programa. Adems, o o o a nuestra clasicacin considera tres tipos de tareas de gestin y distingue entre los fallos o o de pgina provocados por la reserva de nuevos objetos, los provocados durante las fases a de marcado y barrido de la liberacin de objetos muertos y los que se dan durante la fase o de compactacin del heap. o

3.2.2

Metodolog para la recoleccin de datos a o

Para poder efectuar la clasicacin de los fallos de pgina hemos necesitado modicar o a tanto el kernel de Linux como la JVM. En el kernel de Linux hemos a adido los contadores que nos permiten separar los diferentes n fallos de pgina y el tiempo empleado en su resolucin, as como el cdigo necesario a o o para manipular esos contadores. Cada vez que un programa de prueba provoca un fallo de pgina, el kernel de Linux actualiza los contadores correspondientes a su tipo. Para a calcular el tiempo invertido en resolver cada fallo de pgina hemos utilizado el contador a de ciclos que posee el procesador sobre el que hemos medido los programas de prueba. Sin embargo el kernel de Linux carece de suciente informacin para distinguir entre o todos los tipos de fallos de pgina que hemos denido y slo es capaz de separar fallos a o de pgina soft y hard. Dado un fallo de pgina, Linux slo conoce el proceso que lo ha a a o

34

Cap tulo 3

provocado, pero no sabe el tipo de cdigo que estaba ejecutando. De la misma manera, o Linux tampoco sabe el uso concreto que se le est dando a una direccin involucrada en a o un fallo de pgina, slo puede saber el espacio de direcciones al que pertenece y el tipo a o de acceso permitido sobre esa direccin. o Por este motivo, adems de los contadores, hemos a adido al kernel de Linux unas variaa n bles de conguracin, que contienen la informacin necesaria para que Linux complete la o o clasicacin de los fallos de pgina. Y hemos modicado la JVM para que se encargue de o a mantener estas variables con los valores adecuados. Las variables de conguracin contienen los siguientes datos: o

Identicador del proceso que se quiere monitorizar L mites de las zonas del espacio de direcciones. Para mantener estos l mites hemos implementado seis variables diferentes, que nos permiten dividir el espacio de direcciones en las tres zonas distintas que queremos considerar. Dos de las variables delimitan la zona de objetos, otras dos variables limitan la zona que contiene las cabeceras de los objetos, y las otras dos separan el heap del programa del resto del espacio de direcciones. Tipo de cdigo que est en ejecucin, es decir, si se trata del cdigo del programa o si o a o o se trata de cdigo de alguna de las tareas de gestin (reserva de nuevos objetos, fase o o del garbage collector de marcado y barrido o fase de compactacin del heap). o

Cada vez que hay un fallo de pgina, el kernel de Linux consulta estas variables para a determinar, primero, si lo ha provocado el proceso que se est monitorizando y, segundo, a el tipo de fallo de pgina y, por lo tanto, los contadores asociados. a Como ya hemos explicado en el cap tulo 2, la JVM decide la organizacin del espacio lgico o o de direcciones de los programas Java y, por lo tanto, conoce exactamente las direcciones que forman parte en cada momento de cada zona. Adems la JVM tambin controla a e el tipo de cdigo que se ejecuta en cada momento. Es decir, tiene toda la informacin o o necesaria para congurar la clasicacin de fallos de pgina. o a

Evaluacin del uso de la memoria virtual de los programas Java o

35

Para que la JVM pueda modicar las variables de conguracin, es necesario denir o un interfaz entre la JVM y el kernel que lo permita. Hemos implementado este interfaz mediante el mecanismo que Linux ofrece para interactuar con los gestores de dispositivos (ver gura 3.1). Este mecanismo permite que se incorporen fcilmente nuevos dispositivos a as como el cdigo espec o co que los manipula, sin necesidad de modicar el kernel del SO. El cdigo espec o co forma parte de gestores externos, y su interfaz con los programas de usuario debe ser el genrico que dene Linux para el acceso a cualquier dispositivo. As e , hemos creado en nuestro sistema de cheros un nuevo dispositivo lgico que representa o a los contadores y hemos implementado el cdigo del gestor encargado de manipular o este nuevo dispositivo. En la gura 3.1 mostramos un esquema del funcionamiento del mecanismo.

bytecode() consulta

SO

gestor contadores

cont. config.

JVM

configuracin

fallo de pgina

Figura 3.1 Esquema de funcionamiento del recuento de fallos de pgina a

El gestor de los contadores implementa unicamente tres funciones del interfaz y que des cribimos brevemente a continuacin. o

open: recibe como parmetro el dispositivo lgico asociado a los contadores. Esta a o funcin inicializa los contadores y registra al proceso que la utiliza como proceso para o el que se debe evaluar la memoria virtual: countFd=open(" /dev/contadores ", O RDONLY)

36

Cap tulo 3

ioctl: esta llamada a sistema est pensada para la conguracin de los dispositivos y a o permite que se utilice para diferentes tareas. El segundo parmetro sirve para indicar a el tipo de tarea solicitada, y en el tercero se pueden pasar los datos necesarios para la tarea. En nuestro caso la utilizamos para las tareas descritas a continuacin. o Activacin y desactivacin del recuento: estas opciones permiten suspender moo o mentneamente el recuento de fallos de pgina y reanudarlo cuando interese, a a para poder analizar, en caso necesario, zonas concretas de la ejecucin de los o programas. Para esta funcionalidad, el segundo parmetro de la llamada ioctl a contiene la operacin que interesa realizar (activar o desactivar), mientras que el o tercer parmetro no se utiliza: a ioctl(countFd, UPDATE ACT STATE, 0) Modicacin de la variable que indica el tipo de cdigo en ejecucin: para llevar o o o a cabo esta tarea, en el segundo parmetro de la llamada ioctl indicamos que a ha cambiado el tipo de cdigo en ejecucin, y en el tercer parmetro se informa o o a sobre el cdigo que inicia la ejecucin: o o ioctl(countFd, UPDATE CODE, code type) Modicacin de las variables que contienen los l o mites del espacio de direcciones: mediante estas opciones es posible mantener actualizadas las variables del kernel que denen los l mites de las zonas el heap. El segundo parmetro de la llamada a ioctl indica el l mite que se quiere modicar y el tercer parmetro el nuevo valor a para la variable: ioctl(countFd, LIMIT ID, limit addr) Consulta de los valores de los contadores: la implementacin que hemos hecho para o la operacin de consulta requiere que, mediante el segundo y el tercer parmetro, o a se indique el tipo de fallo de pgina para el que se quiere consultar los datos a (zona del espacio de direcciones y cdigo involucrado), y el tipo de informacin o o que se quiere obtener (n mero de fallos de pgina o tiempo de resolucin), y la u a o llamada devuelve como valor de retorno el contador solicitado. Para el caso de los contadores del n mero de fallos de pgina, cada llamada a ioctl devuelve el u a valor de uno de ellos. Para los contadores de tiempo de resolucin, para cada tipo o de fallo de pgina es necesario utilizar dos llamadas a ioctl, ya que el tipo de a datos que devuelve esta llamada (int) es menor que el tipo de datos del contador

Evaluacin del uso de la memoria virtual de los programas Java o

37

de tiempo (long long) y, por lo tanto, es necesario obtener por separado la parte baja y la parte alta de su valor. ioctl(countFd, COUNTER ID|ZONA ID, CODE ID) close: se libera el uso de los contadores: close(countFd)

En la gura 3.2 mostramos un ejemplo del uso del interfaz para manipular los contadores. Cuando la JVM inicia la ejecucin utiliza la llamada open sobre el dispositivo lgico de los o o contadores para registrarse como proceso que va a ser monitorizado. Adems debe utilizar a la llamada ioctl para completar la conguracin del recuento, es decir, para registrar o los l mites de las zonas del heap y para indicar el tipo de cdigo que est en ejecucin. o a o A partir de ese momento, utiliza la llamada ioctl cada vez que es necesario modicar alguna variable de conguracin. Por ejemplo, si se modica alguno de los l o mites del heap, o cada vez que pasa a ejecutar cdigo de gestin. Por ultimo, antes de nalizar la o o ejecucin, utiliza la llamada ioctl para consultar el valor de los contadores y la llamada o close para liberar el uso de los contadores.

Ejecucin de los experimentos para la evaluacin o o


Las medidas que presentamos para evaluar el rendimiento de la gestin de memoria son o el resultado de la ejecucin real de los programas de prueba sobre el entorno de ejecucin. o o Por lo tanto, hay que tener en cuenta que existen factores externos que pueden inuir en los resultados, como por ejemplo, la ejecucin de los procesos de gestin del SO. Para o o suavizar los efectos de estos factores externos, presentamos la media de los resultados de varias ejecuciones. Adems, para que todos los programas se ejecuten en las mismas a condiciones, hemos reiniciado la mquina antes de cada bater de experimentos. a a Hemos ejecutado los programas sobre diferentes tama os de memoria f n sica, para poder evaluar su comportamiento bajo diferentes condiciones de ejecucin. Esto se puede cono seguir a travs de un parmetro de arranque del kernel de Linux, con el que se puede e a indicar la cantidad de memoria f sica disponible en el sistema. De esta manera, aunque la mquina dispon de 128Mb reales de memoria RAM, los experimentos se han hecho a a

38

Cap tulo 3

... countFd = open(/dev/contadores , O RDONLY); /* conguracin de los l o mites de la zona de Objetos */ ioctl(countFd, TOP OBJECTS, maxHeapAddr); ioctl(countFd, BOTTOM OBJECTS, minHeapAddr); ... /* registrar el resto de l mites del espacio de direcciones */ ... /* el programa inicia la ejecucin */ o ioctl(countFd, UPDATE CODE, program); /* activa el recuento */ ioctl(countFd, UPDATE ACT STATE, 0); ... /* si cambian los valores de conguracin actualizar las variables */ o ... /* al nal de la ejecucin desactivar recuento y consultar los valores de los contadores */ o ioctl(countFd, UPDATE ACT STATE, 0); hard pf heap program = ioctl(countFd, HARD PF | HEAP, program); hard pf heap management = ioctl(countFd, HARD PF | HEAP, jvm); ... hi time = ioctl(countFd, HI HARD PF TIME | HEAP, program); lo time = ioctl(countFd, LO HARD PF TIME | HEAP, program); hard pf time heap program = (hi time 32)lo time; ... close(countFd); ...

Figura 3.2 Ejemplo de uso del interfaz de manipulacin de los contadores o

adems sobre 64Mb, 32Mb y 16Mb, lo que nos ha permitido analizar la inuencia de la a disminucin de memoria sobre el comportamiento de los programas. o Otro parmetro de ejecucin que puede inuir en los resultados es el tama o del heap. a o n Como ya se ha dicho, el usuario tiene la opcin de decidir el tama o inicial y el tama o o n n mximo del heap, y la JVM adapta el tama o actual al ms adecuado para cada momento a n a de la ejecucin, respetando siempre los l o mites jados. El tama o mximo debe ser el n a suciente para soportar todos los objetos que estn en uso simultneamente. Pero, adems a a a de esa restriccin, el tama o del heap tambin puede inuir en el rendimiento de la gestin o n e o del espacio de direcciones. Un tama o de heap peque o puede aumentar la frecuencia n n necesaria de limpieza de memoria. Adems puede ralentizar el proceso de reserva de a

Evaluacin del uso de la memoria virtual de los programas Java o

39

memoria, porque se puede complicar la localizacin de espacios libres adecuados para o satisfacer las reservas. Para estos experimentos, hemos seleccionado como tama o mximo n a de heap para cada programa el suciente para que se ejecute, sin entrar en otro tipo de consideraciones. En cuanto al tama o m n nimo dejamos que la JVM utilice el tama o n m nimo que decide por defecto. De esta manera, emulamos el comportamiento de un usuario estndar, que no tiene por qu conocer los detalles de implementacin de la JVM a e o que utiliza para ejecutar sus programas.

3.2.3

Importancia del tiempo de gestin de fallos de pgina o a

El primer paso que hemos dado en la evaluacin es determinar la relevancia que tiene la o memoria virtual sobre el rendimiento de los programas de prueba. Para ello hemos medido el tiempo que el SO debe dedicar a resolver los fallos de pgina de los programas. a En las guras 3.3 y 3.4 presentamos los resultados de este experimento. Las abscisas de las dos grcas representan los diferentes tama os de memoria f a n sica que hemos considerado, mientras que el eje de las coordenadas representa el tiempo de ejecucin, separando el o tiempo de fallo de pgina del resto de tiempo de la aplicacin. La gura 3.3 representa a o el tiempo en valor absoluto (expresado en horas de ejecucin), mientras que en la gura o 3.4 el tiempo aparece expresado en porcentaje con respecto al tiempo total de ejecucin. o Slo mostramos el tiempo dedicado a resolver fallos de pgina hard , porque hemos visto o a que el efecto de los fallos de pgina soft se puede ignorar. a En las grcas se puede ver que para Crypt el tiempo de clculo domina claramente a a el tiempo de ejecucin, y hace que el tiempo dedicado a resolver fallos de pgina sea o a totalmente insignicante. Adems, en la gura 3.3 se puede ver que el tiempo de fallo de a pgina se mantiene estable ante los cambios en el tama o de memoria y, por lo tanto, el a n tiempo de ejecucin es prcticamente el mismo para todos los tama os de memoria que o a n hemos evaluado. Para el resto de programas de prueba se puede observar en la gura 3.3 que, cuando la memoria f sica deja de ser suciente para albergar todo el espacio de direcciones de los programas, el tiempo dedicado a resolver fallos de pgina es considerable. Adems, en a a

40

Cap tulo 3

Crypt SizeC
Tiempo ejecucin (horas)
0,40 0,30 0,20 0,10 0,00 16Mb 32Mb 64Mb 128Mb

HeapSort SizeC
>10 das

Tiempo ejecucin (horas)

250,00 200,00 150,00 100,00 50,00


0,84

0,00 16Mb 32Mb 64Mb 128Mb

Tamao de memoria fsica

Tamao de memoria fsica

MonteCarlo SizeA
Tiempo ejecucin (horas)
2,50 2,00 1,50 1,00 0,50 0,00 16Mb 32Mb 64Mb 128Mb Tiempo de fallo de pgina Tiempo de clculo

Tamao de memoria fsica

FFT SizeA
39h 7h

Sparse SizeC
350h

Tiempo ejecucin (horas)

Tiempo ejecucin (horas)

4,00 3,00 2,00 1,00 0,00 16Mb 32Mb 64Mb 128Mb

10,00 8,00 6,00 4,00 2,00 0,00 16Mb 32Mb 64Mb 128Mb

Tamao de memoria fsica

Tamao de memoria fsica

Figura 3.3 Tiempo dedicado a resolver fallos de pgina a

la gura 3.4 se ve que, en esta situacin, el tiempo de fallo de pgina representa en la o a mayor de los casos ms de un 90 % del tiempo total de ejecucin. a a o El tiempo de ejecucin de HeapSort y de MonteCarlo aumenta para cada disminucin o o en el tama o de memoria f n sica, debido al aumento del tiempo necesario para resolver los fallos de pgina. Es ms, excepto para la ejecucin sobre 128Mb, el tiempo de fallo de a a o pgina de las dos aplicaciones domina por completo el tiempo de ejecucin. En el caso a o

Evaluacin del uso de la memoria virtual de los programas Java o

41

Crypt SizeC
Tiempo ejecucin (%)
Tiempo ejecucin (%)
100% 80% 60% 40% 20% 0% 16Mb 32Mb 64Mb 128Mb 100% 80% 60% 40% 20% 0%

HeapSort SizeC

16Mb

32Mb

64Mb

128Mb

Tamao de memoria fsica

Tamao de memoria fsica

MonteCarlo SizeA
Tiempo ejecucin (%)
100% 80% 60% 40% 20% 0% 16Mb 32Mb 64Mb 128Mb Tiempo de fallo de pgina Tiempo de clculo

Tamao de memoria fsica

FFT SizeA
100% 100%

Sparse SizeC

Tiempo ejecucin (%)

80% 60% 40% 20% 0% 16Mb 32Mb 64Mb 128Mb

Tiempo ejecucin (%)

80% 60% 40% 20% 0% 16Mb 32Mb 64Mb 128Mb

Tamao de memoria fsica

Tamao de memoria fsica

Figura 3.4 Porcentaje de tiempo dedicado a resolver fallos de pgina a

de HeapSort este incremento del tiempo es ms evidente. Si se ejecuta sobre 128Mb, a el working set del programa cabe en memoria y por lo tanto no provoca ning n fallo de u pgina, y el tiempo de ejecucin es 50 minutos. Sin embargo, si se ejecuta sobre 64Mb, el a o tiempo de ejecucin pasa a ser de ms de 2 d con casi un 98 % del tiempo dedicado a o a as, resolver fallos de pgina. Y si se ejecuta slo con 16Mb entonces el tiempo de ejecucin a o o supera los 10 d con un tiempo de clculo insignicante comparado con el tiempo de as a fallo de pgina. En el caso de MonteCarlo, aunque el tiempo absoluto no sufre un a incremento tan considerable, tambin se observa que el porcentaje de tiempo dedicado a e

42

Cap tulo 3

resolver fallos de pgina se multiplica, y pasa de ser nulo, en el caso de la ejecucin sobre a o 128Mb, a representar un 78,6 % sobre el tiempo total del programa, si la ejecucin se hace o sobre 64Mb, y un 94,6 % si se hace sobre 16Mb. Sparse y FFT necesitan menos cantidad de memoria para albergar todos sus datos, y se ejecutan sobre 128Mb y sobre 64Mb sin provocar fallos de pgina. Sin embargo, a si la cantidad de memoria deja de ser suciente para almacenar su working set, para ambas aplicaciones el tiempo de fallo de pgina se incrementa considerablemente y, como a consecuencia tambin lo hace el tiempo total de ejecucin. e o En el caso de Sparse, si comparamos la ejecucin sobre 32 Mb con la ejecucin sobre o o 128Mb, podemos observar en la gura 3.3 que el tiempo total de ejecucin se ha multiplio cado por un factor de 2,3, y en la gura 3.4 vemos que el porcentaje de tiempo dedicado a resolver fallos de pgina deja de ser nulo y pasa a ser de un 40 %. Si la comparacin la a o hacemos de la ejecucin sobre 16Mb con la ejecucin sobre 128Mb, el factor multiplicativo o o del tiempo de ejecucin pasa a ser 990, ya que el programa pasa de ejecutarse en unicao mente 21 minutos sobre 128Mb a necesitar aproximadamente 350 horas para completar su ejecucin sobre 16Mb. Adems, en la gura 3.4 se ve que para la ejecucin sobre 16Mb o a o el porcentaje de tiempo de fallo de pgina de Sparse convierte en insignicante el resto a de tiempo de su ejecucin. o Para FFT la diferencia en el tiempo de ejecucin sobre 128Mb y sobre 32Mb viene o afectada por un factor multiplicativo de 70, ya que pasa de una ejecucin de 6 minutos o sobre 128Mb a una ejecucin de aproximadamente 7 horas sobre 32Mb (ver gura 3.3), y o el porcentaje de tiempo dedicado a resolver fallos de pgina pasa de ser nulo a representar a un 90 % del tiempo total (ver gura 3.4). En cuanto a la comparacin entre la ejecucin o o sobre 128Mb y la ejecucin sobre 16Mb, el tiempo de ejecucin se multiplica por un factor o o de 347 y pasa a ser aproximadamente 39 horas sobre 16Mb, con un porcentaje dedicado a resolver fallos de pgina del 95 % sobre el tiempo total de ejecucin. a o Adems, tanto para Sparse como para FFT se observa un incremento en el tiempo que a no se dedica a resolver fallos de pgina. Este incremento se debe al aumento de clculo a a necesario para gestionar el uso de la memoria virtual.

Evaluacin del uso de la memoria virtual de los programas Java o

43

Los resultados de este experimento nos muestran que, cuando la memoria f sica no es suciente para soportar el espacio de direcciones de los programas, la memoria virtual se convierte en un aspecto cr tico para el rendimiento. Por lo tanto, analizando las causas de esta penalizacin, se podr ver si es posible optimizar la ejecucin de los programas en o a o este tipo de escenarios.

3.2.4

Distribucin de los fallos de pgina en el espacio de o a direcciones

El objetivo de este experimento es determinar qu regiones del espacio de direcciones de e las aplicaciones tienen ms accesos que involucran fallos de pgina. Como ya se ha dicho, a a hemos considerado tres posibles zonas: objetos, cabeceras de objetos, y resto del espacio de direcciones. La tabla 3.2 resume los resultados signicativos de este experimento para cada tama o n de memoria f sica que estamos considerando, y contiene el porcentaje que representan los fallos de pgina provocados por los accesos a objetos sobre el total de los provocados por a los programas. Recordemos que en la subseccin 3.2.3 hemos visto que la ejecucin de o o los programas FFT y Sparse sobre 64Mb y 128Mb y la de HeapSort sobre 128Mb se completan sin provocar fallos de pgina y, por lo tanto, para este experimento no aplica a ejecutar estas dos aplicaciones sobre estos dos tama os de memoria f n sica (en la tabla 3.2, las casillas correspondientes a estos resultados aparecen marcadas como
Programas / Tam. mem. Crypt SizeC HeapSort SizeC MonteCarlo SizeA FFT SizeA Sparse SizeC 16Mb 96.99 % 100 % 90.29 % 99.96 % 100 % 32Mb 97.50 % 100 % 95.81 % 99.93 % 99.90 % 64Mb 98.05 % 99.99 % 96.96 % n/a n/a 128Mb 97.73 % n/a 95.60 % n/a n/a n/a).

Tabla 3.2 Fallos de pgina en los accesos a objetos ( %) a

El resultado de este experimento nos muestra que la mayor de los fallos de pgina a a provocados por los programas evaluados se deben a accesos a la zona de objetos. Se puede ver en la tabla 3.2 que el porcentaje menor es de un 90 % mientras que para el resto de ejecuciones supera siempre el 95 %.

44

Cap tulo 3

Esto signica que ni los accesos a las cabeceras de los objetos ni los accesos a cdigo o o pilas son relevantes para el rendimiento de la memoria virtual. Por lo tanto, de cara a buscar fuentes de mejora para este rendimiento podemos centrarnos slo en la zona de o objetos y en los accesos involucrados.

3.2.5

Origen de los fallos de pgina a

El objetivo de este experimento es distinguir entre los fallos de pgina provocados por a el cdigo de las aplicaciones de los provocados por la ejecucin del cdigo de gestin de o o o o la JVM. De esta manera, se puede determinar la penalizacin que la interaccin entre el o o cdigo de gestin de la JVM y la memoria virtual est a adiendo al rendimiento de los o o a n programas. Como ya se ha dicho en la subseccin 3.2.1, en esta clasicacin hemos considerado tres o o tipos de tareas: reserva de memoria, liberacin de memoria (marcado y barrido) y como pactacin del heap. o Sin embargo, esta clasicacin no es suciente para determinar por completo el impacto o que la ejecucin de la JVM tiene sobre los programas. Por ejemplo, no nos permite separar o los fallos de pginas que, provocados por el cdigo del programa, son debidos a la ejecucin a o o del cdigo de gestin, que puede haber causado la expulsin anticipada de las pginas que o o o a el programa necesitaba a continuacin. o Para evaluar la importancia de este efecto, ejecutamos cada programa de prueba de dos maneras diferentes. La primera, es la que ya se ha utilizado en los experimentos anteriores y emula el tipo de ejecucin que un usuario estndar utilizar La segunda manera intenta o a a. reducir al mximo la ejecucin del cdigo de gestin de la JVM. Esta limitacin se consia o o o o gue lanzando los programas con un tama o inicial de heap igual que el tama o mximo, n n a es decir, el suciente para albergar los objetos vivos del programa. De esta manera, no ser necesario que se ejecute en ning n momento la liberacin de memoria ni la compaca u o tacin del heap. Adems, la reserva de memoria pasa a ser una tarea muy simple, ya que o a consiste en asignar siempre la posicin contigua a la asignada en la ultima operacin de o o reserva. Por ultimo, para tratar las posibles llamadas expl citas que los programas hagan

Evaluacin del uso de la memoria virtual de los programas Java o

45

al garbage collector, hemos substituido el garbage collector de la mquina por un cdigo a o vac que retorna inmediatamente al ser invocado (garbage collector nulo). o, Si el cdigo del programa provoca menos fallos de pgina al reducir de esta manera el o a cdigo de gestin de la JVM, podremos concluir que la ejecucin del cdigo de gestin de o o o o o la JVM est perjudicando el uso de la memoria virtual que hace el cdigo del programa. a o A la hora de comparar los resultados de los dos tipos de ejecucin hay que tener en o cuenta que la ejecucin con gestin de memoria m o o nima puede provocar que el espacio de direcciones de los programas sea mayor, ya que en ning n momento se liberan objetos u que ya no son necesarios. Como consecuencia, puede ser que la cantidad de memoria f sica necesaria para la ejecucin sea mayor y que el n mero de fallos de pgina del o u a programa aumente. Si se da esta situacin, la unica conclusin que podemos extraer de o o esta comparacin, es que los benecios obtenidos por la ejecucin del cdigo de gestin o o o o de la JVM son mayores que la posible inuencia negativa que su ejecucin pueda tener o sobre el uso de la memoria virtual del programa. En la gura 3.5 se muestran los resultados que hemos obtenido, tanto para la ejecucin o normal (las columnas de la grca marcadas como gc) como para la ejecucin con gestin a o o de memoria m nima (las marcadas como gcnulo). Slo aparecen los fallos de pgina debidos o a a los accesos a objetos ya que, como hemos mostrado en la seccin 3.2.4, sta es la regin o e o ms afectada por los fallos de pgina. a a Lo primero que hay que destacar es que, para todos los programas excepto para MonteCarlo, el cdigo de los programas es la fuente de la mayor de los fallos de pgina o a a provocados. Adems, el resultado de ejecutarlos con la gestin de memoria habitual o con a o la gestin de memoria m o nima es prcticamente el mismo. a Para entender este comportamiento hemos contado el n mero de veces que estos prou gramas necesitan que se libere memoria durante la ejecucin con la gestin de memoria o o habitual, y hemos visto que este n mero es muy bajo (var entre tres, para FFT y Heapu a Sort, y siete, para Sparse). Este es el motivo por el que el rendimiento de los programas apenas se ve afectado si no se ejecuta esta tarea. Por este motivo, tambin, una mejora e

46

Cap tulo 3

Crypt SizeC
Fallos de pgina hard
1,00E+05 7,50E+04 5,00E+04 2,50E+04 0,00E+00
1 16 6M M b g b gc c n 3 2 ul o 32 M M b g b gc c n 6 4 ul o 64 M M b g b gc c 1 2 nu 12 8M lo 8M b g b gc c nu lo

HeapSort SizeC
Fallos de pgina hard
4,00E+07 3,00E+07 2,00E+07 1,00E+07 0,00E+00
1 16 6M M b g b gc c nu 3 lo 32 2M M b gc b gc nu 6 lo 64 4M M b gc b gc nu 1 12 28M lo 8M b g b gc c nu lo
ms de 4,00E+07

Parmetros de ejecucin

Parmetros de ejecucin

MonteCarlo SizeA
Fallos de pgina hard
1,20E+06 Reserva 9,00E+05 6,00E+05 3,00E+05 0,00E+00
1 16 6M M b g b gc c n 3 2 ul o 32 M M b g b gc c n 6 4 ul o 64 M M b g b gc c 1 2 nu 12 8M lo 8M b g b gc c nu lo

Compactacin Marcado y barrido Aplicacin

Parmetros de ejecucin

FFT SizeA
Fallos de pgina hard Fallos de pgina hard
1,00E+07 7,50E+06 5,00E+06 2,50E+06 0,00E+00
1 16 6M M b g b gc c n 3 2 ul o 32 M M b g b gc c n 6 4 ul o 64 M M b g b gc c 1 2 nu 12 8M lo 8M b g b gc c nu lo
1,89E+07 1,9E+07

Sparse SizeC
1,60E+08 1,20E+08 8,00E+07 4,00E+07 0,00E+00
1 16 6M M b g b gc c nu 3 lo 32 2M M b gc b gc nu 6 lo 64 4M M b gc b gc nu 1 12 28M lo 8M b g b gc c nu lo

Parmetros de ejecucin

Parmetros de ejecucin

Figura 3.5 Clasicacin de los fallos de pgina seg n su origen o a u

del rendimiento del mecanismo de liberacin de memoria no inuir en el rendimiento de o a estos programas. Respecto a la tarea de reserva de memoria, estos resultados no nos permiten asegurar que no est inuyendo en el rendimiento de los programas. Como ya hemos dicho, si no se a liberan objetos, el proceso de reserva es muy simple y no a ade sobrecarga a la ejecucin. n o Sin embargo, durante este proceso se decide la distribucin de los objetos en el heap, y o esa decisin puede inuir sobre la efectividad de la memoria virtual. Desde el punto de o

Evaluacin del uso de la memoria virtual de los programas Java o

47

vista del rendimiento de la memoria virtual, la decisin adecuada sobre la situacin de o o los objetos ser la que agrupara en las mismas pginas los objetos que estn en uso al a a a mismo tiempo, para conseguir que las decisiones que el SO toma a nivel de pgina se a correspondan tambin con el uso a nivel de objeto. Para poder estudiar la inuencia de e esta decisin, hemos analizado el tipo de objetos que estos programas reservan y cmo se o o utilizan (ver seccin 3.4). o

Comportamiento particular de MonteCarlo


El programa MonteCarlo se comporta diferente al resto de programas que hemos ejecutado. Este programa s que necesita una participacin importante de la liberacin de o o memoria y, por lo tanto, los resultados son muy diferentes si se ejecuta el programa con la gestin de memoria habitual o con la gestin de memoria m o o nima. En primer lugar, si analizamos la ejecucin con gestin de memoria m o o nima, vemos que se consigue que todos los fallos de pgina sean debidos a la ejecucin del cdigo del programa. a o o Adems, este n mero de fallos de pgina se mantiene estable aunque se reduzca la cantidad a u a de memoria f sica disponible. Esto se debe al patrn de accesos del programa: su working o set, los datos que utiliza el programa al mismo tiempo, ocupa poco espacio de memoria, y los fallos de pgina se producen slo durante los cambios de working set. a o Por otro lado, en la ejecucin con la gestin de memoria habitual el n mero de fallos de o o u pgina se incrementa considerablemente con cada reduccin en el tama o de la memoria a o n f sica. Sin embargo, todo el incremento se debe a fallos de pgina provocados por el cdigo a o de gestin, mientras que los fallos de pgina debidos al cdigo del programa se mantienen o a o estables. Esto signica que la ejecucin del cdigo de gestin no afecta a los fallos de o o o pgina provocados por el cdigo del programa. A continuacin se analiza los efectos de a o o cada una de las tareas de gestin sobre el rendimiento nal del programa. o

Reserva de memoria: esta es la tarea que provoca ms fallos de pgina cuando la a a memoria f sica disponible es reducida. Esto se debe a que implementa una b squeda u c clica por toda la zona de objetos, empezando a partir del punto donde se hizo la ultima reserva. Este recorrido de la zona de objetos naliza cuando encuentra suciente

48

Cap tulo 3

espacio contiguo para albergar al nuevo objeto o cuando se alcanza el punto inicial de la b squeda, en cuyo caso se inicia la liberacin de memoria. Por lo tanto, en el u o peor de los casos, si no se encuentra el espacio adecuado, puede implicar un recorrido completo de toda la zona de objetos, con los fallos de pgina que eso implica. a Marcado y barrido: la ejecucin de este algoritmo de liberacin de memoria est geo o a nerando alrededor del 30 % de los fallos de pgina del cdigo de gestin. Durante la a o o fase de marcado, recorre la zona de cabeceras de los objetos para marcar los objetos que no estn en uso. La fase de barrido es la que accede a la zona de objetos, y slo a o accede a aquellos objetos marcados, para liberar la memoria que ocupan. Adems, se a ejecuta en menos ocasiones que la tarea de reserva, ya que slo se lanza cuando la o reserva no ha sido capaz de satisfacer la creacin de un objeto nuevo y como respuesta o a una unica llamada expl cita que hace el programa al nal de su ejecucin. o Compactacin del heap: por ultimo, los fallos de pgina provocados por la compactao a cin del heap representan menos del 10 % del total de los fallos de pgina del cdigo o a o de gestin. Esta fase debe recorrer varias veces todo el heap, para mover los objetos o y eliminar la fragmentacin externa del heap. Sin embargo, MonteCarlo slo reo o quiere una ejecucin de esta compactacin. Por este motivo, aunque es un algoritmo o o susceptible de provocar una gran cantidad de fallos de pgina, para este programa su a impacto es menos importante que el resto de tareas de gestin. o

Finalmente, comparando los resultados entre ambos tipos de ejecucin, podemos observar o que el n mero de fallos de pgina provocados por el cdigo del programa es ligeramente u a o superior si utilizamos la gestin de memoria m o nima. Esto es debido a que la liberacin o de memoria consigue reducir el tama o del rea de objetos y, de esta manera, la cantidad n a de memoria f sica necesaria para soportarla.

3.2.6

Validacin de los resultados en la JVM HotSpot o

HotSpot es otra implementacin de JVM que, junto con la JVM classic, Sun suministra con o el entorno de de ejecucin J2SDK. Esta JVM ha sido dise ada pensando en la ejecucin o n o de programas con mayor consumo de recursos.

Evaluacin del uso de la memoria virtual de los programas Java o

49

Hemos ejecutado los programas de prueba tambin sobre la JVM HotSpot para comprobar e el efecto que tiene sobre su rendimiento una gestin de memoria ms elaborada y para o a validar las conclusiones que hemos extra de la ejecucin sobre la JVM classic. do o Para ello, hemos comparado la cantidad de fallos de pgina provocados sobre la JVM a HotSpot y los provocados sobre la JVM classic, separando los fallos fallos de pgina a debidos al cdigo de gestin de los fallos de pgina debidos al cdigo del programa. Como o o a o ya se ha explicado en el cap tulo 2, la gestin de memoria implementada en HotSpot es o muy diferente de la implementada en la JVM classic, por este motivo, no hemos utilizado la subdivisin de tareas de gestin que hemos considerado durante la evaluacin de la o o o ejecucin sobre la JVM classic en la seccin 3.2.5. o o La JVM HotSpot ofrece dos posibles conguraciones: una para aplicaciones servidor y otra para aplicaciones cliente. Hemos seleccionado la conguracin para aplicaciones servidor o porque es la que est pensada para trabajar con mayor demanda de recursos. a Adems, como ya se ha explicado en la seccin 2.3.2, la JVM HotSpot permite que el a o usuario decida si la limpieza sobre la zona de objetos viejos debe ser incremental o no. En este experimento hemos lanzado los programas con las dos opciones, para comprobar si inu de alguna manera en el resultado. an En la grca 3.6 mostramos los resultados que hemos obtenido, tanto para la ejecucin a o con limpieza incremental (HS-incgc en la grca), como para la ejecucin con limpieza a o total (HS-noincgc), comparados con los resultados de la ejecucin sobre la JVM classic. o Slo presentamos los resultados para la cantidad de memoria f o sica que hace necesario el uso de la memoria virtual para cada programa. Por un lado, podemos observar que, excepto para MonteCarlo, el comportamiento de los tres tipos de ejecucin es muy similar. Como ya se ha dicho en la seccin 3.2.5, estas o o aplicaciones apenas requieren la ejecucin de la liberacin de memoria, lo cual tambin o o e simplica la reserva de memoria. Por lo tanto, la ejecucin del cdigo de estos programas o o son los causantes de la mayor de los fallos de pgina para las tres opciones y, aunque a a la JVM HotSpot implementa una gestin de memoria ms cuidadosa, esta mejora apenas o a

50

Cap tulo 3

Crypt SizeC (memoria fsica: 64Mb)


Fallos de pgina hard Fallos de pgina hard
1,00E+05 7,50E+04 5,00E+04 2,50E+04 0,00E+00 classic HS-noincgc HS-incgc

HeapSort SizeC (memoria fsica: 64Mb)


9,00E+06 6,75E+06 4,50E+06 2,25E+06 0,00E+00 classic HS-noincgc HS-incgc

JVM

JVM

MonteCarlo SizeA (memoria fsica: 64Mb)


Fallos de pgina hard
3,50E+05 2,80E+05 2,10E+05 1,40E+05 7,00E+04 0,00E+00 classic HS-noincgc HS-incgc Cdigo de gestin Aplicacin

JVM

FFT SizeA (memoria fsica: 32Mb)


Fallos de pgina hard Fallos de pgina hard
1,00E+07 7,50E+06 5,00E+06 2,50E+06 0,00E+00 classic HS-noincgc HS-incgc

Sparse sizeC (memoria fsica: 32Mb)


2,00E+06 1,50E+06 1,00E+06 5,00E+05 0,00E+00 classic HS-noincgc HS-incgc

JVM

JVM

Figura 3.6 HotSpot vs. classic

inuye en los resultados. Hay que recordar que la gestin de memoria de la JVM puede o inuir en el rendimiento de la memoria virtual no slo por su propia ejecucin sino tambin o o e a travs de la pol e tica que decide la situacin de los objetos en el espacio de direcciones. o Aunque HotSpot intenta adaptar la situacin de los objetos en el heap para favorecer la o localidad de referencia y agrupar en las mismas pginas objetos relacionados, esta pol a tica tampoco consigue mejorar el rendimiento con respecto a la ejecucin sobre la JVM classic. o

Evaluacin del uso de la memoria virtual de los programas Java o

51

En cuanto al programa MonteCarlo, que s requiere de una participacin activa del o garbage collector, se puede ver que se benecia de las mejoras introducidas en la gestin o de memoria de HotSpot, y la ejecucin sobre esta JVM reduce substancialmente el n mero o u de fallos de pgina provocados por el cdigo de gestin, aunque sigue superando al n mero a o o u de fallos de pgina provocados por el cdigo del programa. a o Por lo tanto, despus de ejecutar los programas de prueba sobre la JVM HotSpot, hemos e comprobado que unicamente uno de ellos (MonteCarlo) se ha visto beneciado por la gestin de memoria mejorada que ofrece HotSpot. De todas maneras, la ejecucin del o o cdigo de gestin sigue penalizando el rendimiento de MonteCarlo en mayor medida o o que el cdigo propio del programa. El resto de programas, se comportan de manera similar o en ambas JVM, independientemente del modelo de liberacin de memoria utilizado en la o JVM HotSpot. Es decir, mejorar las pol ticas de gestin del espacio de direcciones no ha o servido para mejorar el uso de la memoria virtual que estos programas hacen y, por lo tanto, es necesario buscar otras posibles v para optimizar su ejecucin. as o

3.3

RENDIMIENTO OPTIMO DE LA GESTION DE MEMORIA EN JAVA

El objetivo de la evaluacin que hemos realizado es determinar qu aspectos de la gestin o e o de memoria en un entorno Java son susceptibles de mejora. Para ello es necesario medir el rendimiento de la gestin actual, y determinar los aspectos que son ms cr o a ticos para el rendimiento de los programas. Pero tambin es necesario determinar si este rendimiento e es mejorable o si por el contrario no es posible ofrecer una mejor gestin a los programas. o En esta seccin presentamos los resultados que hemos obtenido al simular la ejecucin de o o los programas de prueba sobre un sistema de memoria ptimo. Este sistema de memoria o ofrece el mejor rendimiento terico, dado un patrn de accesos y una cantidad de memoria o o f sica. El rendimiento lo medimos en trminos de fallos de pgina, y nos centramos unie a camente en los producidos por accesos a la zona de objetos ya que los resultados indican que es la zona ms afectada. a

52

Cap tulo 3

Aunque no es factible implementar la gestin ptima que proponemos sobre un sistema o o real, nos sirve para obtener una cota superior del rendimiento de la gestin de memoria y o nos permite estimar el margen de mejora que existe para el rendimiento de esta gestin. o

3.3.1

Modelo de gestin de memoria ptima o o

La gestin de memoria ptima en un entorno Java ser la compuesta tanto de una gestin o o a o ptima de la memoria virtual como de una gestin ptima del espacio de direcciones del o o o proceso. La gestin ptima de la memoria virtual es la que minimiza el n mero de intercambios o o u con el rea de swap y consigue mantener en memoria las pginas que estn en uso. Esto es a a a posible combinando la paginacin bajo demanda con el algoritmo de reemplazo ptimo. o o Este algoritmo de reemplazo selecciona como pginas v a ctimas aqullas que el programa e va a tardar ms tiempo en referenciar. De esta manera, los accesos al rea de swap son a a slo los inevitables. Este algoritmo de reemplazo no es implementable en un sistema o real, ya que requiere conocer los accesos futuros de los programas para poder seleccionar adecuadamente las pginas v a ctimas. En cuanto al espacio de direcciones, los programas Java ejecutados sobre memoria virtual tendrn una gestin ptima si sta consigue que los objetos que ocupan la memoria f a o o e sica en cada momento sean los que se estn utilizando en ese instante y, adems, consigue a a que, si un objeto tiene que ser expulsado de memoria f sica, slo se almacene en el rea o a de swap si todav est vivo. Esto slo ser posible utilizando una pol a a o a tica de asignacin o de memoria que cambiara de posicin dinmicamente los objetos en funcin de su uso y o a o un algoritmo de liberacin de memoria perfecto. o La pol tica de asignacin de memoria ptima deber pues, estar vinculada al algoritmo o o a, de reemplazo y al mecanismo de paginacin bajo demanda. Cada vez que el algoritmo o de reemplazo seleccione una pgina v a ctima, la pol tica de asignacin de memoria lgica o o deber mover a esa pgina los objetos que se va a tardar ms tiempo en referenciar. De a a a la misma manera, cada vez que sea necesario cargar una pgina almacenada en el rea de a a

Evaluacin del uso de la memoria virtual de los programas Java o

53

swap, se deber mover a esta pgina todos los objetos del area de swap que se vayan a a a necesitar antes. El algoritmo de liberacin de memoria perfecto ser aquel capaz de detectar inmediatao a mente qu objetos dejan de ser necesarios, para liberar la memoria que ocupan y evitar e adems movimientos innecesarios al rea de swap. a a Aunque el coste de implementar esta gestin del espacio de direcciones no es asumible o por un sistema real, la simulacin de esta gestin, combinada con la gestin ptima de la o o o o memoria virtual, cumple con el objetivo de ofrecer una cota superior del rendimiento del sistema de memoria.

3.3.2

Implementacin del modelo de gestin de memoria o o o ptima

Para obtener el rendimiento del modelo de gestin de memoria ptima hemos implemeno o tado un simulador, que tiene como datos de entrada la traza que describe el uso de la memoria del programa que se quiere evaluar (ver gura 3.7), y que ofrece como resultado el n mero de accesos al rea de swap inevitables. u a

simulador ptimo traza del programa accesos a disco inevitables

Figura 3.7 Simulacin de la gestin ptima de memoria o o o

54

Cap tulo 3

La traza de entrada debe contener para cada objeto creado por el programa el instante de su creacin y su tama o, para poder simular en cada momento su situacin en el o n o espacio de direcciones. Adems, para poder simular el uso de la memoria virtual, la traza a debe describir todos los accesos a los objetos, es decir, el instante de cada referencia y, para poder tratar con objetos que ocupan ms de una pgina, la posicin concreta del a a o objeto accedida. Por ultimo, para poder implementar el algoritmo de reemplazo ptimo, o la agrupacin de objetos en pginas y la liberacin perfecta de memoria, la traza debe o a o contener tambin el instante de la prxima referencia de cada uno de los objetos. e o Para poder generar una traza con esta informacin hemos tenido que modicar la JVM, o introduciendo en el tratamiento de los bytecodes de creacin y de acceso a objetos el cdigo o o necesario para registrar los datos de la traza en un chero de salida. A continuacin describimos brevemente estas modicaciones, as como la implementacin o o del simulador.

Adquisicin de datos sobre el comportamiento de los o programas


La informacin que necesita el simulador de gestin ptima de memoria est asociada a o o o a la creacin de nuevos objetos y a todos los accesos a objetos. o Para cada bytecode de creacin de objetos (listados en la tabla 3.3) registramos en el o chero de trazas los datos que describen esta operacin. Es decir: o

Cabecera del objeto, que permitir identicar al objeto durante toda la simulacin. a o Direccin inicial asignada, que permitir localizar al objeto en el espacio de direccioo a nes. Tama o del objeto, para usar en el algoritmo de asignacin de memoria, es decir, dun o rante la creacin y en cada cambio de situacin del objeto en el espacio de direcciones. o o Instante de su prxima referencia, para simular el algoritmo de asignacin de memoria, o o los intercambios con el rea de swap y la liberacin de memoria. a o

Evaluacin del uso de la memoria virtual de los programas Java o

55

Bytecode new newarray anewarray multianewarray

Descripcin o Creacin de objeto o Creacin de array de escalares o Creacin de array de referencias o Creacin de array multidimensional o

Tabla 3.3 Bytecodes de creacin de objetos o

En cuanto a los bytecodes de acceso (ver tabla 3.4), necesitamos registrar la siguiente informacin: o

Cabecera del objeto, que lo identica durante la simulacin. o Posicin accedida, para determinar la pgina de memoria involucrada en el acceso, o a necesario si el objeto ocupa varias pginas. a Instante de su prxima referencia, necesario para simular la asignacin de memoria, o o los intercambios con el rea de swap y la liberacin de memoria. a o
Bytecode iload/istore lload/lstore oad/fstore dload/dstore aload/astore iaload/iastore laload/lastore faload/fastore daload/dastore aaload/aastore baload/bastore caload/castore saload/sastore geteld/puteld Descripcin o Lectura/escritura sobre escalares

Lectura/escritura sobre arrays

Lectura/escritura sobre campos de objeto

Tabla 3.4 Bytecodes de acceso a objetos

La gura 3.8 contiene el pseudocdigo que describe el cdigo que hemos a adido a la JVM o o n para generar la traza con el uso de la memoria del programa. Bsicamente, registramos a en un chero una l nea con los datos de cada nueva creacin o nuevo acceso, indicando o el tipo de l nea mediante el bytecode. Para registrar el campo que contiene la siguiente referencia al objeto, mantenemos siempre cul ha sido su ultimo acceso registrado. De a esta manera, dado un acceso podemos retroceder en el chero hasta la l nea del acceso

56

Cap tulo 3

previo, actualizar su campo de siguiente referencia para que sea el acceso actual, y marcar el acceso actual como ultimo acceso al objeto.

if (generacion trazas activada) { registrar(codigo operacion); registrar(objeto.cabecera); if (codigo operacion == creacion) { registrar(objeto.direccion inicial); registrar(objeto.tam objeto); marcar esta como ultima referencia(objeto); } else { registrar(desplazamiento acceso); marcar esta como ultima referencia(objeto); acceso previo=buscar acceso previo(objeto); accceso previo.proximo acceso = instante actual } }

Figura 3.8 Algoritmo para generar las trazas

Hay que tener en cuenta que los programas de prueba tienen un alto consumo de memoria y millones de referencias a objetos. Esto signica que guardar una l nea para cada acceso implicar una traza de gran tama o, lo que dicultar y ralentizar su procesado a n a a posterior, adems de hacer necesaria una gran cantidad de espacio de disco disponible. a Por este motivo, durante el registro de la traza, hemos ltrado informacin que no aporta o datos relevantes para la simulacin (ver gura 3.9). o El ltro que hemos implementado afecta unicamente a la informacin sobre los accesos a o objetos, y consiste en eliminar referencias consecutivas a un objeto que no inuyen sobre las decisiones de gestin. En particular hemos adoptado el siguiente criterio: si dado un o conjunto de referencias consecutivas a un objeto, la cantidad de memoria cargada entre la primera de ellas y la ultima es menor que la cantidad de memoria de la mquina, entonces a las referencias intermedias no son registradas en el chero de trazas. A continuacin demostramos intuitivamente que eliminar estas referencias del chero de o trazas no modica el resultado del simulador de memoria ptima. o

Evaluacin del uso de la memoria virtual de los programas Java o

57

bytecode() info. creacin

JVM
ejecucin bytecode

info. acceso filtro traza del programa

Figura 3.9 Esquema de la generacin de trazas o

Consideremos la siguiente secuencia de referencias de un programa:


L

Ref = {O1 , Xi , , O2 , , Yj , O3 , , Zk , O4}


N

donde L < M < N

Siendo O1 , O2, O3 y O4 cuatro accesos consecutivos al objeto O y M la cantidad de memoria f sica de la mquina. Suponiendo que la cantidad de memoria necesaria para a satisfacer las referencias entre O1 y O3 es L, y N es la cantidad de memoria implicada entre O1 y O4 . Despus de la referencia O1 el objeto O pasa a estar cargado en memoria f e sica. La referencia O2 ser relevante para el resultado de la simulacin si es la responsable de que a o el objeto permanezca en memoria hasta que ocurra la referencia O3 . Es decir, si eliminar la referencia O2 del chero de trazas puede hacer que la simulacin del algoritmo de o reemplazo seleccione a O como objeto v ctima entre las referencias O1 y O3 . Pero esto slo o podr ocurrir si a partir de O1 todos los objetos cargados en memoria son referenciados a antes de que ocurra O3 . Sin embargo, partiendo de la base de que la cantidad de memoria cargada entre O1 y O3 es menor que la cantidad de memoria f sica, si la memoria est llena a seguro que hay objetos cargados que no se han referenciado entre O1 y O3 , y por lo

58

Cap tulo 3

tanto son los candidatos a ser expulsados de memoria en este intervalo de referencias, independientemente de la presencia o no de O2 en la traza. Sin embargo, si ltramos tambin el acceso O3 , los dos accesos consecutivos a O pasan a e ser O1 y O4 . Entre estos dos accesos se est utilizando ms memoria (N) que la memoa a ria f sica del sistema, y ya no es posible asegurar que el comportamiento del simulador sea equivalente al que tendr en caso de disponer tambin de la informacin sobre O3 . a e o Esta equivalencia depende de la cadena concreta de referencias y de las cantidades de memoria involucradas y, por lo tanto, la decisin de ltrarlo requiere un anlisis de cada o a situacin particular. Para simplicar el algoritmo de ltrado y evitar hacer este anlisis o a para cada situacin hemos adoptado la opcin conservadora de grabar siempre este tipo o o de referencias. Es decir, dado un conjunto de referencias que involucren tantas pginas diferentes como a memoria f sica haya en el sistema, para cada uno de los objetos guardamos el primer y el ultimo acceso que se hace a ese objeto dentro de ese conjunto.
M

Ref = {O1 , Xi , , O2 , , O3 , Yj , , Wl , , Zk , O4 }

registramos O1 , O3 y O4

Aunque con este algoritmo es posible que conservemos algunos accesos no relevantes para la simulacin, el porcentaje de ltrado que hemos obtenido es suciente para hacer de las o trazas una informacin fcilmente manipulable. o a

Implementacin del simulador o


El simulador que hemos implementado recibe como parmetro el chero de trazas que a describe el comportamiento de los programas, y la cantidad de memoria f sica libre. Como resultado devuelve el n mero de fallos de pgina que requieren acceso a disco y que son u a inevitables. En la gura 3.10 mostramos el pseudocdigo del simulador. o

Evaluacin del uso de la memoria virtual de los programas Java o

59

if (!objeto.presente) { tam necesario = objeto.tam objeto; if (tam necesario > memoria libre) { memoria libre += liberar objetos inactivos(); while (tam necesario > memoria libre) { objeto victima = seleccionar objeto presente referenciado mas tarde(); objeto victima.presente=FALSO; memoria libre+=objeto victima.tam objeto; } } if (! primer acceso(objeto)) fallos de pagina hard += (tam necesario/TAM PAGINA); objeto.presente = CIERTO; memoria libre-= objeto.tam objeto; } actualizar informacion sobre proxima referencia() if (ultima referencia(objeto)) objeto.inactivo = CIERTO;

Figura 3.10 Simulador para la gestin de memoria ptima o o

Mientras haya memoria f sica disponible, se simula la carga de pginas a medida que se a referencian. Cuando la memoria libre no es suciente para satisfacer una carga, entonces primero se libera la memoria ocupada por objetos no necesarios (aquellos para los que ya se ha tratado su ultimo acceso). De esta manera simulamos la liberacin perfecta de o objetos. Si con la memoria obtenida por esta liberacin no es suciente, entonces se contin a con la o u liberacin de memoria mediante la simulacin del algoritmo de reemplazo, hasta obtener o o la suciente memoria libre. Este algoritmo de reemplazo libera la memoria ocupada por aquellos objetos que tardarn ms tiempo en ser referenciados. De esta manera se simula el a a reemplazo de memoria ptimo y el movimiento de los objetos en el espacio de direcciones o para agrupar en las pginas v a ctimas los que tardarn ms tiempo en ser necesarios. a a En el momento de cargar un objeto, si no es la primera referencia al objeto se debe actualizar el contador de fallos de pgina. Para simular la carga conjunta de objetos a

60

Cap tulo 3

utilizados al mismo tiempo, incrementamos ese contador con la fraccin de pgina ocupada o a por el objeto cargado.

3.3.3

Evaluacin del rendimiento de la gestin ptima de o o o memoria

En la gura 3.11 comparamos los resultados de la ejecucin real de los programas con los o resultados que hemos obtenido de la simulacin sobre el sistema de gestin de memoria o o ptimo. Como ya hemos dicho, medimos el rendimiento de ambos sistemas mediante los o fallos de pgina provocados por los accesos a la zona de objetos. a En las grcas presentamos los resultados para los diferentes tama os de memoria que a n hemos considerado durante toda la evaluacin, aunque los tama os relevantes para esta o n simulacin son los que hacen necesaria la utilizacin de la memoria virtual. Se puede ver o o que en estos casos, para todos los programas de prueba, el rendimiento de la ejecucin o real est muy lejos de acercarse al rendimiento ptimo. a o Este resultado hace que tenga sentido plantearse la b squeda de alternativas de gestin u o que mejoren el rendimiento de la memoria ya que, aunque el rendimiento de la gestin o ptima es inalcanzable, el margen existente para la mejora es considerable. o

3.4

EVALUACION DEL TIPO DE OBJETOS

Para completar la evaluacin del uso de la memoria que hacen los programas Java y o determinar las posibles mejoras que se pueden introducir en su gestin, hemos analizado o los objetos que estos programas crean durante su ejecucin. o Adems, este anlisis nos va a permitir determinar si la pol a a tica de asignacin de memoria o utilizada por la JVM est inuyendo de alguna manera en el rendimiento de los programas. a Aunque en las secciones 3.2.5 y 3.2.6 hemos visto que, para cuatro de los cinco programas evaluados, la ejecucin del cdigo de gestin de la JVM apenas inuye en el rendimiento de o o o la memoria virtual, los resultados obtenidos no nos permiten descartar que las decisiones

Evaluacin del uso de la memoria virtual de los programas Java o

61

Crypt SizeC
> 4,00E+07

HeapSort SizeC
4,00E+07

1,00E+05

Fallos de pgina hard

8,00E+04 6,00E+04 4,00E+04 2,00E+04


4

Fallos de pgina hard

3,00E+07 2,00E+07 1,00E+07 0 0 0,00E+00 16Mb 32Mb 64Mb 128Mb

0,00E+00 16Mb 32Mb 64Mb 128Mb

Tamao de memoria fsica

Tamao de memoria fsica

MonteCarlo SizeA
1,01E+06 7,67E+05 3,27E+05

2,00E+05

Fallos de pgina hard

1,50E+05 1,00E+05 5,00E+04


0

Ejecucin real Gestin ptima de memoria

0,00E+00 16Mb 32Mb 64Mb 128Mb

Tamao de memoria fsica

FFT SizeA
1,89E+07 9,32E+06

Sparse SizeC
1,53E+06

6,00E+06

2,00E+07

Fallos de pgina hard

Fallos de pgina hard

1,50E+07 1,00E+07 5,00E+06


0 0 0 0

4,00E+06

2,00E+06

0 0

0 0

0,00E+00 16Mb 32Mb 64Mb 128Mb

0,00E+00 16Mb 32Mb 64Mb 128Mb

Tamao de memoria fsica

Tamao de memoria fsica

Figura 3.11 Ejecucin real vs. gestin ptima o o o

sobre la situacin de los objetos en el heap no estn penalizando el rendimiento del sistema o e de memoria. El primer paso para este anlisis es saber qu tipo de objetos crean estos programas, cul a e a es su tama o, y qu uso se hace de ellos. Esto permite decidir si es posible obtener una n e agrupacin diferente de los objetos en pginas que sea ms favorable al rendimiento de la o a a memoria virtual.

62

Cap tulo 3

Esta informacin se puede obtener generando una traza durante la ejecucin de los proo o gramas, que registre todas las creaciones de objetos que hace el programa. Para cada nueva reserva guardamos en el chero de traza el objeto implicado, su direccin inicial, o su tipo y su tama o. De esta manera, se puede analizar la distribucin de objetos en el n o heap y cmo va evolucionando durante la ejecucin. o o Con la informacin de esta traza hemos clasicado a los objetos en funcin de su tama o, o o n considerando tres posibles grupos. El primer grupo es el de los objetos cuyo tama o es n menor que 4Kb (el tama o de una pgina de memoria en el procesador sobre el que n a trabajamos). El segundo grupo es el de los objetos cuyo tamao es menor que 64Kb (16 n pginas). Y el tercer grupo es el de los objetos mayores de 64Kb. a En la gura 3.12.a mostramos la cantidad de objetos de cada grupo que los programas reservan y en la gura 3.12.b, mostramos la cantidad de memoria ocupada por cada uno de los grupos de objetos. Slo mostramos los resultados para los programas de prueba o que necesitan poca participacin de las tareas de gestin de la JVM. o o Se puede observar que los programas de prueba reservan pocos objetos mayores de 64Kb: uno en los casos de HeapSort y FFT, tres en el caso de Crypt y cinco para Sparse. Sin embargo, prcticamente el 100 % de la zona de objetos est ocupada por este tipo de a a objetos para los cuatro programas de prueba. Esto signica que los objetos implicados en el uso de la memoria virtual ocupan ms de una pgina y, por lo tanto, la decisin a a o sobre cmo agrupar objetos en pginas no les afecta. Es decir, la pol o a tica de situacin de o objetos en el heap tampoco est inuyendo en el rendimiento de la memoria virtual. a Un posible camino para mejorar el rendimiento de la memoria en estos programas es aplicar la tcnica de prefetch en los accesos a estos objetos de grandes dimensiones. Para e que esta tcnica sea efectiva, es necesario anticipar las prximas referencias a memoria, e o para cargar esas pginas con antelacin y de forma solapada con el clculo y, de esta a o a manera reducir el n mero de fallos de pgina de los programas. u a La informacin de la traza que hemos generado indica que estos objetos de grandes dio mensiones son de tipo array y los trabajos previos nos dicen que este tipo de objetos se

Evaluacin del uso de la memoria virtual de los programas Java o

63

(a)
4010 Nmero de objetos 4000 3990 3980 3970 Heap Sort SizeC Sparse SizeC FFT SizeA Crypt SizeC

Benchmarks 4Kb > tamao 4Kb <= tamao <64Kb 64Kb <= tamao

Memoria ocupada por objetos (Kb)

160000 120000 80000 40000 0 Heap Sort SizeC

(b)

Sparse SizeC

FFT SizeA

Crypt SizeC

Benchmarks 4Kb > tamao 4Kb <= tamao <64Kb 64Kb <= tamao

Figura 3.12 Clasicacin de objetos por tama o o n

suelen utilizar con un patrn de acceso regular y, por lo tanto, predecible [GG97], lo que o facilita la implementacin de un prefetch efectivo. o Un anlisis ms detallado del uso que los programas de prueba hacen de los objetos nos ha a a mostrado que, la mayor parte de las instrucciones que acceden a los vectores de grandes dimensiones lo hacen mediante un patrn regular. La tabla 3.5 resume el tipo de acceso o que se utiliza en cada uno de los programas y a continuacin lo describimos brevemente. o

64

Cap tulo 3

HeapSort SizeC: este programa utiliza un unico vector de grandes dimensiones. Se trata del array que recibe como datos de entrada que tiene 25.000.000 enteros, es decir, ocupa 95,37Mb. De los accesos que este programa hace sobre el vector de entrada, la mayor parte son aleatorios y dependen del contenido del vector. Unicamente dos de las instrucciones utilizan un patrn predecible, basado en una separacin entre o o accesos consecutivos (stride) de valor -1. Hay que decir que el n mero de veces que se u ejecutan estas dos instrucciones hace que su inuencia sobre el comportamiento del programa se pueda ignorar. Sparse SizeC: este programa trabaja sobre 5 arrays de grandes dimensiones. Dos de ellos se recorren de forma aleatoria, y son la matriz dispersa que se utiliza como entrada y el vector resultado de la multiplicacin. Ambos arrays tienen 500.000 douo bles (ocupan 3,81Mb cada uno) y la posicin a la que se accede en cada momento o viene determinada por el contenido de otros dos vectores. Estos vectores de ndices se recorren de forma secuencial y tienen 2.500.000 elementos de tipo entero (cada uno ocupa 9,53Mb). El quinto array es el que se utiliza para almacenar el vector denso que se multiplica con la matriz dispersa. Este vector tiene 2.500.000 doubles (ocupa 19,07Mb) y se recorre de forma secuencial. FFT SizeA: el unico vector de grandes dimensiones que utiliza este programa es el que recibe como entrada. Este vector tiene 4194304 doubles (32Mb), que codican los n meros complejos sobre los que trabaja el programa. Este programa utiliza un patrn u o regular para acceder al vector, y los accesos se hacen desde instrucciones que forman parte de bucles anidados (hasta tres niveles de anidacin como mximo). El stride o a utilizado por cada instruccin en el acceso al vector depende del bucle anidado al que o afecte el cambio de iteracin. Es decir, las instrucciones que se utilizan como parte de o tres bucles anidados, pueden utilizar tres niveles diferentes de stride: uno para cada cambio de iteracin del bucle ms interno, otro diferente cuando el cambio de iteracin o a o afecta adems al segundo bucle, y el tercer stride cuando se cambia la iteracin del a o bucle exterior. Adems, para algunas de las instrucciones de este programa, el stride a utilizado en el bucle ms interno depende de la iteracin de los bucles externos que a o se est ejecutando. Es decir, algunos de los strides utilizados son dinmicos. e a Crypt SizeC: este programa, adems del vector de entrada, utiliza otros dos vectoa res donde almacena el resultado de encriptar los datos de entrada y el resultado de

Evaluacin del uso de la memoria virtual de los programas Java o

65

desencriptarlo. Cada vector tiene 50.000.000 elementos de tipo byte (en total suman 143,05Mb) y los tres se recorren de forma secuencial.
Programas HeapSort SizeC Sparse SizeC FFT SizeA Crypt SizeC Nmero de arrays u 1 2 3 1 3 Memoria ocupada 95,37Mb 7,62Mb 38,13Mb 32Mb 143,05Mb Tipo de acceso Strided y aleatorio Aleatorio Secuencial Strided dinmico (3 niveles) a Secuencial

Tabla 3.5 Uso de los arrays de grandes dimensiones

Por lo tanto, dotar al entorno de ejecucin de un prefetch de memoria que aproveche o la predictibilidad de los accesos strided sobre los arrays para cargar con antelacin sus o pginas, parece una alternativa viable para mejorar el rendimiento de la memoria virtual a de estos programas Java.

3.5

OPORTUNIDADES DE MEJORA

En este cap tulo hemos presentado una evaluacin completa y novedosa en el entorno de o ejecucin de Java, del rendimiento del sistema de memoria. En esta evaluacin hemos o o obtenido la penalizacin que involucra el uso de la memoria virtual en los programas de o computacin de altas prestaciones escritos en Java, distinguiendo entre la penalizacin o o debida al cdigo del programa y su patrn de acceso de la debida al cdigo de gestin o o o o necesario en el entorno de ejecucin de Java. o Hay que decir que, aunque esta evaluacin la hemos llevado a cabo sobre la versin de la o o JVM basada en la interpretacin, las conclusiones que hemos extra son independientes o do del modelo de ejecucin que se utilice, ya que este modelo no afecta a las caracter o sticas de los objetos que han determinado las conclusiones de la evaluacin. o Las principales conclusiones que hemos extra de la evaluacin son: do o

La memoria virtual inuye de forma signicativa en el rendimiento de los programas cuando stos trabajan sobre un conjunto de datos mayor que la memoria disponible. e

66

Cap tulo 3

La zona del espacio de direcciones que ms inuye en la prdida de rendimiento es la a e zona que contiene los objetos. Existen programas de clculo numrico que se ejecutan sin apenas participacin del a e o cdigo de gestin de la JVM que manipula el espacio de direcciones, y que slo deben o o o la penalizacin a la ejecucin de su propio cdigo. Para este tipo de programas, no o o o existen trabajos previos sobre cmo mejorar su rendimiento, ya que todos los trabajos o hechos sobre la gestin de memoria en Java se han centrado en optimizar las tareas o de gestin que implementa la JVM (ver cap o tulo 7). El rendimiento de los programas evaluados est muy lejos del rendimiento ptimo que a o se obtendr con la ejecucin sobre un sistema de memoria perfecto. Por lo tanto, el a o amplio margen de mejora invita a trabajar en posibles optimizaciones para el sistema de gestin de memoria en Java. o Estos programas ocupan la mayor parte del espacio de direcciones con pocos objetos de gran tama o y reservados al inicio de la ejecucin. Por lo tanto no es viable optimizar n o el rendimiento de la memoria virtual mejorando las tcnicas de gestin del espacio de e o direcciones, que apenas estn inuyendo. Adems, estos objetos grandes son de tipo a a array que t picamente tienen un patrn de accesos predecible. o

Por todo ello, en este trabajo proponemos mejorar el rendimiento del sistema de memoria dotando al entorno de ejecucin de Java de un mecanismo de prefetch de pginas, que o a aproveche las caracter sticas propias del entorno de ejecucin para adaptar sus decisiones o al comportamiento de los programas, y sea capaz de cargar, anticipadamente y de forma solapada con el tiempo de clculo, las pginas que el programa accede. a a

4
MEJORA DEL RENDIMIENTO DE LOS PROGRAMAS JAVA MEDIANTE EL PREFETCH DE MEMORIA

En el cap tulo 3 hemos visto que implementar una pol tica de prefetch efectiva en el entorno de ejecucin de Java puede mejorar el rendimiento de los programas de clculo o a cient co. Esto nos ha llevado a seleccionar esta pol tica como caso prctico para evaluar nuestra a propuesta. Por este motivo, hemos dise ado e implementado, dentro del entorno de ejen cucin de Java, una pol o tica de prefetch que, utilizando las caracter sticas propias del entorno, adapta sus decisiones al comportamiento de los programas. Antes de dise ar el mecanismo de prefetch es necesario analizar las tareas involucradas n en el prefetch y cules son los requerimientos impuestos por el entorno de ejecucin para a o que estas tareas sean efectivas. Tambin es necesario analizar las facilidades que ofrece cada componente del entorno de e ejecucin para desarrollar cada una de las tareas de prefetch. De esta manera, se puede o asignar cada una de ellas al componente ms adecuado para cumplir sus requerimientos. a Adems, partimos de la base de que, ante varias estrategias que ofrezcan un rendimiento a equivalente, el mtodo ideal es el que exija menos modicaciones sobre el entorno de e trabajo, ya que esto facilita la utilizacin de este mecanismo en diferentes plataformas. o En este cap tulo presentamos este anlisis previo. Vemos cmo el entorno de ejecucin a o o de Java ofrece una oportunidad en la asignacin de tareas, que no existe en los entornos o de ejecucin basados en compilacin, y que permite adaptar las decisiones de gestin al o o o 67

68

Cap tulo 4

comportamiento de los programas, de una forma eciente y totalmente transparente al usuario y al programador. Por ultimo, presentamos una visin general de la propuesta de prefetch, que desarrollare o mos en profundidad en los siguientes cap tulos.

4.1

TAREAS Y REQUERIMIENTOS PARA UN PREFETCH EFECTIVO

El objetivo de las tcnicas de prefetch de pginas es mejorar el rendimiento del sistema e a de memoria reduciendo el n mero de fallos de pgina provocados por los programas y, de u a esta manera, reduciendo el tiempo de bloqueo implicado en la carga en memoria f sica de las direcciones referenciadas mientras estaban almacenadas en el rea de swap. a Estas tcnicas se basan en determinar con anticipacin las referencias a memoria que hacen e o los programas para iniciar su carga antes de que se efect en, si es que se encuentran en el u rea de swap, y realizarla en paralelo con la ejecucin del cdigo del programa. Si cuando a o o el programa accede a las direcciones involucradas en el prefetch, stas ya estn cargadas e a en memoria f sica, se consigue solapar por completo el tiempo de clculo con el tiempo a de carga, con la potencial mejora que ese solapamiento puede tener en el tiempo total de ejecucin. o As pues, el prefetch de memoria se puede dividir en dos grandes tareas. La primera tarea consiste en seleccionar las pginas que se deben cargar con antelacin; la segunda en a o cargar las pginas seleccionadas de forma as a ncrona con la ejecucin del programa, para o que el solapamiento de carga y clculo sea real. a El primer requisito para que una pol tica de prefetch sea efectiva es que la seleccin de o pginas sea acertada y consiga anticipar las prximas referencias a memoria. Esto es a o necesario no slo para poder solapar el mayor n mero de cargas posibles sino, tambin, o u e para evitar sobrecargar el sistema con lecturas de disco errneas. Hay que tener en cuenta o que, las cargas errneas de pginas pueden ser las responsables de expulsar al rea de o a a

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

69

swap pginas que s son necesarias para el programa. Esto signica que estos errores a en la seleccin, no slo penalizan el rendimiento por la lectura de disco de las selecciones o o equivocadas sino que, adems, pueden ser los responsables de aumentar, innecesariamente, a el n mero de intercambios con el rea de swap realizados para satisfacer las referencias u a del programa. La precisin de esta seleccin depende de la cantidad de informacin disponible sobre o o o el comportamiento dinmico de los programas. Para poder automatizar la seleccin de a o pginas de prefetch es necesario obtener un patrn con los accesos a memoria realizados a o por el programa, que se puede aplicar para predecir los accesos futuros. Cunta ms a a informacin se tenga sobre estos accesos, ms preciso podr ser el patrn generado y, o a a o consecuentemente, ms precisas sern las predicciones efectuadas. a a Para que el prefetch sea efectivo no es suciente con detectar las prximas referencias a o memoria, tambin es necesario solicitar su carga con la antelacin adecuada (distancia e o de prefetch). Esta distancia se debe tener en cuenta durante la seleccin de pginas de o a prefetch y tiene que ser la suciente para completar la carga antes de que el programa referencie esa pgina. Pero este no es el unico condicionante ya que, adems, es necesario a a evitar que la pgina precargada sea expulsada de memoria antes de ser utilizada, situacin a o que podr darse si se utilizara una distancia de prefetch demasiado alta. a Para poder determinar el valor adecuado de la distancia de prefetch es necesario, una vez ms, conocer el comportamiento del programa (cdigo ejecutado antes de la referencia). a o Sin embargo, este no es el unico factor que inuye en este parmetro. Tambin hay que a e tener en cuenta las caracter sticas del sistema, tanto del hardware como del software, y las condiciones de ejecucin. As por ejemplo, inuye la velocidad del procesador, el tiempo o , necesario para acceder a disco, las pol ticas de planicacin de recursos implementadas o por el SO, la cantidad de procesos en ejecucin y su comportamiento, etc. o En cuanto a la carga de pginas, es necesario disponer de un mecanismo as a ncrono, que permita solicitar la carga de memoria y que el programa contin e en paralelo con su u ejecucin, sin esperar a que esta carga concluya. La carga de memoria requiere acceder o al disco y a memoria f sica y, como todo acceso al hardware, es primordial que respete

70

Cap tulo 4

la abilidad del sistema, y que no arriesgue la correcta ejecucin del resto de programas o de la mquina. Adems, este mecanismo tambin debe detectar si las condiciones de a a e ejecucin son las adecuadas para efectuar la carga anticipada o si, por el contrario, el o sistema est tan sobrecargado que hacerlo perjudicar al rendimiento de los programas a a y, por lo tanto, es mejor desestimar el prefetch. Otro aspecto a tener en cuenta en la implementacin del prefetch, es que su ejecucin o o debe ser eciente, de manera que no oculte los benecios de la carga solapada. Para ello, adems de implementar las tareas de prefetch mediante un cdigo eciente, es importante a o aplicar optimizaciones como, por ejemplo, desactivar el prefetch para aquellos casos en los que no se puede anticipar las prximas referencias a memoria, o evitar la solicitud de o carga para aquellas pginas que ya estn presentes en memoria. a a En el caso de las aplicaciones Java existe un requerimiento adicional, que no aparece en los entornos de ejecucin basados en la compilacin. Este requerimiento es garantizar la o o portabilidad de los programas, ya que stos deben poder ejecutarse en cualquier mquina e a sin tan siquiera ser compilados de nuevo. Por lo tanto, a adir prefetch al entorno de ejen cucin debe respetar este paradigma. En este sentido, hay que recordar que la ecacia del o prefetch depende de la mquina sobre la que se ejecuta y de las condiciones de ejecucin. a o Por lo tanto, es deseable que esta tcnica pueda auto congurarse en tiempo de ejecucin, e o adaptndose a las caracter a sticas del momento. Teniendo claras las tareas de prefetch y los requerimientos para que estas tareas sean ecaces, el siguiente paso consiste en determinar qu componente del entorno de ejecucin e o es el ms adecuado para cumplir los requerimientos de cada tarea. En las secciones 4.2 a y 4.3 presentamos esta discusin para cada una de las grandes tareas involucradas en el o prefetch: seleccin de pginas y lectura anticipada. o a

4.2

SELECCION DE PAGINAS DE PREFETCH

La tarea de seleccionar las pginas para el prefetch requiere un profundo conocimiento a sobre los accesos a memoria que hacen los programas.

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

71

La informacin sobre qu direcciones de memoria accede el programa permite generar un o e patrn de accesos que se puede utilizar para predecir los accesos futuros del programa. o Cuanta mayor sea la granularidad de esta informacin mayor precisin tendr el patrn o o a o generado y, por lo tanto, ms precisas sern las predicciones obtenidas a partir de esta a a prediccin. o Pero si, adems de las direcciones involucradas en los accesos, se tiene una informacin a o completa sobre estos accesos (objeto almacenado en la direccin, caracter o sticas del objeto e instruccin que efect a el acceso), entonces es posible mantener patrones de acceso o u independientes en funcin de las caracter o sticas de cada instruccin y de cada objeto, meo jorando a n ms la precisin de estos patrones y simplicando su generacin automtica. u a o o a Con esta caracterizacin completa, es posible, por ejemplo, tratar de una forma muy o simple con instrucciones que utilizan patrones de acceso muy diferentes. Por ejemplo, un programa puede tener instrucciones cuyos accesos son aleatorios y, por lo tanto, no siguen un patrn regular y predecible, mientras que otras instrucciones pueden utilizar un o patrn totalmente predecible (en la tabla 3.5 del cap o tulo 3 podemos ver que los programas HeapSort y Sparse tienen este comportamiento). En esta situacin, generar un patrn o o global es complicado, ya que los accesos aleatorios introducen ruido dif de aislar. Sin cil embargo, distinguiendo la instruccin que efect a cada acceso, es posible detectar y aislar o u los accesos aleatorios del resto de instrucciones, de manera que slo esa funcin sea tratada o o como impredecible. Es ms, tambin es posible utilizar funciones de prediccin espec a e o cas para cada tipo de acceso que tengan en cuenta sus caracter sticas. En particular, esto facilita la optimizacin o de evitar ejecutar el cdigo de prefetch para aquellas instrucciones que no siguen un patrn o o de accesos regular ya que, una vez detectada la situacin, se les puede asociar funciones o de prefetch nulas, lo cual permite desactivar el prefetch unicamente para las instrucciones que no se pueden beneciar de su ejecucin. o Por lo tanto, la automatizacin de la seleccin de pginas de prefetch se debe incluir en el o o a componente del entorno de ejecucin que tenga ms informacin sobre las caracter o a o sticas

72

Cap tulo 4

de los accesos de los programas, ya que, cuanto ms completa sea la caracterizacin de a o estos accesos, ms simple y efectiva podr ser la tarea. a a

4.2.1

Limitaciones del SO para la seleccin de pginas o a

La unica informacin que tiene el SO sobre los accesos a memoria de los programas es la o proporcionada por la excepcin de fallo de pgina. Esto signica que, de todos los accesos o a que hace un programa, slo ser informado sobre los que se reeren a pginas que en el o a a momento del acceso no estaban presentes en memoria f sica. Esta limitacin, reduce la o cantidad de datos que el SO puede utilizar para generar los patrones de acceso. Hay que destacar que hacer un trap al sistema para cada acceso del programa tendr un coste a inaceptable que, en ning n caso, podr ser compensado por los benecios del prefetch. u a Adems, para poder caracterizar estos accesos, el SO slo dispone de la informacin que l a o o e mantiene sobre el espacio de direcciones de los programas y la informacin proporcionada o por el hardware durante la excepcin de fallo de pgina. o a La unica informacin que tiene el SO sobre el espacio de direcciones de los programas es o la que describe qu regiones son vlidas y qu permisos de acceso tiene cada una de ellas, e a e pero no conoce las caracter sticas del contenido de cada regin, ya que es algo decidido o en el nivel de usuario de forma transparente al SO. Por otro lado, la informacin proporcionada por el hardware ante un fallo de pgina es o a unicamente la necesaria para resolver dicha excepcin. Es decir, identicador del proce o so (para localizar la informacin sobre su espacio de direcciones), direccin accedida al o o provocar el fallo de pgina (para poder resolver el fallo determinando si el acceso es coa rrecto y, en ese caso, cargando en memoria la pgina accedida), y direccin que ocupa a o la instruccin que ha provocado el fallo (para reanudarla, si el SO resuelve con xito la o e excepcin). o Es decir, ante un fallo de pgina el SO no puede determinar ni el tipo de instruccin que a o se estaba ejecutando, ni el objeto sobre el que estaba accediendo ni las caracter sticas del objeto. Con esta escasez de informacin sobre el comportamiento previo del programa es o

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

73

complicado determinar su patrn de accesos y, por lo tanto, anticipar cules sern sus o a a prximas referencias a memoria. o Por este motivo, las unicas pol ticas de prefetch implementadas dentro de los SO han sido pol ticas sencillas y genricas, que intentan favorecer comportamientos habituales en los e programas (como por ejemplo el acceso secuencial).

4.2.2

Limitaciones del compilador para la seleccin de o pginas a

El compilador, desde el nivel de usuario, puede extraer ms informacin sobre los accesos a o a memoria de los programas que la disponible en el nivel de sistema. A la hora de traducir el cdigo fuente, el compilador puede analizar el cdigo y sus accesos o o a memoria para determinar qu patrn siguen y a adir en el ejecutable generado las e o n operaciones necesarias para seleccionar las pginas que se quieren cargar con antelacin. a o Sin embargo, hay que tener en cuenta que este anlisis slo puede ser esttico y, por a o a lo tanto, carece de cualquier dato dependiente de la ejecucin como, por ejemplo, el o comportamiento dependiente del valor de los parmetros de la ejecucin. a o En tiempo de compilacin se desconocen tambin las caracter o e sticas de la mquina sobre la a que se va a ejecutar el programa y las condiciones de ejecucin que habr en ese momento, o a factores que inuyen en la distancia de prefetch y, por tanto, tambin determinan la e seleccin de pginas. Hay que tener en cuenta que una compilacin dependiente de la o a o plataforma f sica no respetar el paradigma de portabilidad de Java. a Una posibilidad para adaptar las decisiones tomadas por el compilador a las caracter sticas de cada ejecucin ser implementar las operaciones de prefetch dentro de librer o a as dinmicas y mantener una versin diferente de estas librer para cada plataforma f a o as sica donde se quisiera ejecutar el programa. De esta manera, en tiempo de ejecucin, el cdigo o o de prefetch podr acceder a la informacin sobre las condiciones de ejecucin para coma o o pletar las decisiones de prefetch. Sin embargo, esta opcin tampoco es suciente ya que o

74

Cap tulo 4

implicar poder acceder al cdigo fuente en la fase de compilacin para enlazarlo con las a o o librer correspondientes. Es decir, esta tcnica slo podr utilizarla aquellos usuarios as e o an que tuvieran acceso al cdigo fuente de los programas, lo que, en general, no se puede o suponer que vaya a ocurrir.

4.2.3

Superacin de las limitaciones mediante la JVM o

La JVM, como el compilador, tiene acceso a todo el cdigo y datos de los programas Java. o Esto se debe a que la JVM es la encargada de ejecutar cada instruccin del programa. o Por lo tanto, para cada una de ellas sabe si va a acceder a memoria, cul es el objeto a destino del acceso y cul es la posicin concreta del objeto. Adems, la JVM gestiona las a o a caracter sticas de todos los objetos, incluida la posicin que ocupan en memoria, y por o ello es capaz de determinar la direccin involucrada en el acceso. o Es decir, la JVM dispone de una informacin completa sobre todos los accesos, que le o permite realizar una caracterizacin detallada del comportamiento del programa. Esta o caracterizacin la puede utilizar para generar un patrn minucioso sobre los accesos del o o programa y para determinar las funciones de prediccin ms adecuadas. o a Adems, toda esta informacin se obtiene en tiempo de ejecucin. Esto signica que, a a o o diferencia del compilador, la caracterizacin se realiza sobre el comportamiento dinmico o a de los programas. Otra ventaja sobre la opcin de extraer esta informacin mediante el compilador, es que en o o el caso de la JVM estos datos se obtienen de forma totalmente transparente al programador de las aplicaciones y al usuario que las ejecuta, y slo necesita el cdigo generado por un o o compilador estndar. Es decir, ni siquiera es necesario disponer del cdigo fuente de los a o programas para poder obtener esta informacin. o Por lo tanto, en el entorno de ejecucin de Java, la JVM es el componente que dispone o de ms informacin sobre el comportamiento de los programas, y eso la convierte en la a o candidata ideal para contener el cdigo de seleccin de pginas de prefetch. o o a

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

75

As pues, nuestra propuesta consiste en modicar la JVM para que, para cada instruccin o de acceso a memoria, utilice la informacin sobre la referencia para actualizar el patrn o o de accesos del programa y, luego, aplique ese patrn para seleccionar las pginas que se o a deben cargar con anticipacin. o Hay que destacar que, como el anlisis que hace la JVM es en tiempo de ejecucin, es a o posible adaptar las decisiones de prefetch a las caracter sticas de la plataforma real de ejecucin y de las condiciones de cada instante, sin comprometer la portabilidad de los o programas. Por lo tanto podr utilizar estas caracter a sticas, por ejemplo, para determinar el valor adecuado de la distancia de prefetch y aplicarlo en la seleccin de pginas de o a prefetch. Adems, tener acceso a esta informacin puede ser util de cara a optimizar la a o ejecucin del cdigo de prefetch y, por ejemplo, evitar solicitar la carga anticipada de o o aquellas pginas seleccionadas que ya se encuentren presentes en memoria f a sica.

Prediccin a nivel de instruccin o o


Como ya hemos dicho, conocer la instruccin y el objeto relacionados con cada acceo so, permite una mayor granularidad en la prediccin, al poder tener patrones de acceso o independientes en funcin de las caracter o sticas de las instrucciones y de los objetos. Las ventajas de poder tener patrones independientes se ven claramente en el caso de los accesos a objetos de tipo array. Normalmente los arrays se utilizan desde instrucciones que forman parte de un bucle. Esto signica que cada una de estas instrucciones se ejecuta varias veces (tantas como indique la variable de control del bucle) y que, por lo tanto, se puede asociar un patrn independiente al conjunto de accesos de todas sus ejecuciones. En o este caso, la granularidad de los patrones de acceso es mxima, obteniendo una prediccin a o a nivel de instruccin y el consiguiente aumento de precisin en la seleccin de pginas. o o o a El anlisis que hemos efectuado sobre el comportamiento de los programas que se van a a beneciar del prefetch, nos ha demostrado que los accesos que estn provocando los a fallos de pgina son los asociados a arrays de grandes dimensiones, que se realizan desde a instrucciones que forman parte de bucles (ver la seccin 3.2.1 y la seccin 3.4 del cap o o tulo 3).

76

Cap tulo 4

Por lo tanto, en este trabajo nos hemos centrado en intentar optimizar el acceso a este tipo de objetos, y la solucin que hemos adoptado consiste en implementar la prediccin de o o accesos futuros a nivel de instruccin. Es decir, para cada instruccin de acceso a arrays, o o se intenta detectar el patrn de accesos que sigue, para utilizarlo en la prediccin de los o o accesos que realizar en sus prximas ejecuciones. a o Sin embargo, asociar un patrn de accesos a cada instruccin puede no ser suciente o o porque este patrn puede depender de las caracter o sticas del objeto que se est accediendo a y las instrucciones pueden acceder a varios objetos durante la ejecucin del programa. o Por ejemplo, consideremos el caso de una funcin de multiplicacin de matrices. Las o o instrucciones que recorren las matrices seguirn un patrn con varios strides, donde el a o valor de cada stride depender del tama o de cada columna y de cada la y, por lo tanto, a n depender de las caracter a sticas de las matrices que reciba como parmetro. a Por lo tanto, la prediccin a nivel de instruccin deber considerar tambin los objetos o o a e utilizados por cada una y la inuencia que pueden tener sobre el patrn de sus accesos. o Adems, para poder completar la seleccin de pginas de prefetch, es necesario tener en a o a cuenta la distancia de prefetch. Es decir, adems de predecir las referencias a memoria a de las prximas ejecuciones de una instruccin hay que determinar el instante apropiado o o para solicitar su carga anticipada. Esto depender del tiempo necesario para completar su a carga y del momento previsto para la ejecucin de las iteraciones de la instruccin que las o o referencian. A su vez, estos tiempos vienen determinados por el cdigo del programa, las o caracter sticas de la plataforma de ejecucin y las condiciones presentes en la ejecucin. o o Como la JVM conoce todo el cdigo del programa en ejecucin puede estimar fcilmente o o a el tiempo de ejecucin entre dos iteraciones de cada instruccin. En cuanto al resto de o o factores, se pueden averiguar, o aproximar de forma bastante precisa, desde el nivel de usuario. Sin embargo, para denir el mtodo para obtener este valor hay que tener muy e en cuenta su tiempo de clculo, ya que es importante no ralentizar innecesariamente la a ejecucin del mecanismo de prefetch. Por este motivo, puede ser necesario substituir parte o de la informacin real sobre la ejecucin por heur o o sticas que la aproximen.

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

77

Otro aspecto a considerar durante la seleccin de pginas de prefetch es el estado de o a las pginas seleccionadas. Puede ser que algunas de estas pginas seleccionadas ya estn a a e presentes en memoria y no sea necesario solicitar su carga. Hay que evaluar el tiempo involucrado en estas solicitudes y, si es relevante sobre el tiempo total, el mecanismo de prefetch deber comprobar el estado de las pginas antes de solicitar su carga y ltrar de a a la seleccin aqullas que ya estn presentes en memoria. o e e Desde el nivel de usuario no se tiene acceso a la informacin sobre el estado de las pginas. o a Por lo tanto, para que la tarea de seleccin de pginas pueda ltrar estas peticiones o a innecesarias, es necesario dotarla de un mtodo para obtener esta informacin. Para ello e o contamos con dos opciones. La primera es utilizar alg n tipo de heur u stica que permita aproximar el estado de las pginas desde el nivel de usuario. La segunda opcin consiste a o en modicar el SO para que exporte esta informacin. Para tomar esta decisin, hay que o o comparar, por una parte, el n mero de solicitudes innecesarias que se evitan con ambos u mtodos y, por otra parte, el tiempo necesario para aplicar el ltro en los dos casos ya e que, para que esta optimizacin tenga sentido, es necesario que el mtodo utilizado tenga o e una sobrecarga menor que el de solicitar pginas para prefetch. a

4.3

CARGA AS INCRONA Y ANTICIPADA

En cuanto a la tarea de cargar en memoria las pginas seleccionadas, como cualquier a acceso al hardware, tiene el requerimiento primordial de respetar la abilidad del sistema. Por este motivo, la solucin ms adecuada es que se lleve a cabo desde el nivel sistema. o a El otro aspecto relacionado con la carga es cmo solicitar desde el nivel usuario que el SO o inicie la carga de las pginas seleccionadas. a La carga anticipada debe ser as ncrona con respecto a la ejecucin de los programas. Es o decir, una vez solicitada la carga, el programa debe continuar la ejecucin sin bloquearse o hasta que la carga nalice. En los SO actuales, la gestin de memoria virtual slo dispone o o de un mecanismo que provoca la carga de memoria desde nivel de usuario, y es el fallo de pgina. El fallo de pgina es la excepcin que se produce cuando un programa accede a a a o

78

Cap tulo 4

una direccin de memoria que en ese momento no est presente en memoria f o a sica. Como consecuencia, el SO bloquea al programa y carga en memoria la pgina accedida. Hasta a que esta carga no naliza, el programa no puede continuar la ejecucin. Es decir, es un o mecanismo s ncrono. Por lo tanto, como el entorno de ejecucin no dispone de un interfaz para iniciar la carga o as ncrona de pginas residentes en el rea de swap, es necesario a adirle un mecanismo a a n que lo permita. En este punto nos planteamos dos alternativas. Una solucin es adaptar, desde el nivel de usuario, el mecanismo ya existente y dotarlo de o as ncrona con respecto a la ejecucin del programa. Esto se puede conseguir a adiendo a la o n JVM un nuevo ujo de ejecucin. Este ujo puede acceder a las pginas seleccionadas para o a provocar los fallos de pgina que desencadenarn su carga en memoria f a a sica. Mientras este ujo espera bloqueado a que nalice la carga de las pginas, el ujo del programa a puede continuar as ncronamente con su ejecucin. Esta solucin consigue que la carga o o anticipada sea transparente al SO, en el sentido de que el SO no distingue si las pginas a solicitadas son por carga anticipada o por fallo de pgina real. Por lo tanto, al no modicar a el SO, favorece el objetivo de minimizar el n mero de cambios introducidos en el sistema u y, de esta manera, la portabilidad del mecanismo. La otra solucin es a adir al SO un nuevo interfaz que permita que los programas soliciten o n la carga as ncrona y que, una vez solicitada, contin en la ejecucin concurrentemente con u o la carga de la pgina. Esta opcin implica modicar el SO para incluir este nuevo sevicio. a o Sin embargo, con esta alternativa, se involucra al SO en el mecanismo de prefetch y se le permite que distinga entre lecturas de disco relacionadas con prefetch del resto de lecturas, informacin que puede utilizar al aplicar las pol o ticas de gestin de acceso a disco. o Como ya hemos dicho, la estrategia que requiera menos modicaciones en el entorno de ejecucin es la que ms facilita su introduccin en diferentes plataformas de ejecucin. o a o o Por este motivo, en nuestro dise o inicial hemos adoptado la primera solucin, con el obn o jetivo de implementar un mecanismo totalmente transparente al SO (ver cap tulo 5). Este primer dise o nos ha permitido evaluar los aspectos dbiles de la estrategia de prefetch n e transparente al SO y determinar aqullos puntos es los que es aconsejable una mayor e

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

79

participacin del SO para dotar al mecanismo de una mayor estabilidad y eciencia. Coo mo consecuencia de este anlisis, nuestra propuesta nal propone modicar el SO para a implementar un estrategia de prefetch basada en la cooperacin entre el SO y la JVM, y o adopta la solucin de implementar un interfaz dedicado para el prefetch (ver cap o tulo 6). En cualquier caso, antes de llevar a cabo la carga anticipada de una pgina, es necesario a evaluar si las condiciones de ejecucin son favorables para la utilizacin de prefetch, ya o o que existen situaciones en las que la ejecucin del prefetch es incapaz de beneciar a o los programas y puede incluso perjudicar su rendimiento. Por ejemplo, si el sistema de memoria est sobrecargado, cargar de forma anticipada una pgina puede provocar que a a se expulsen pginas que todav estn en uso y que se vuelvan a referenciar incluso antes a a e de que se acceda a la pgina que provoc su expulsin. a o o Por lo tanto, la implementacin de esta tarea necesita utilizar la informacin sobre la o o carga del sistema para descartar las peticiones de prefetch no adecuadas. El mtodo para e obtener esta informacin depender de la estrategia que se utilice para solicitar la carga. o a El caso de la estrategia transparente al SO requiere consultar esta informacin desde el o nivel de usuario y, en este caso, hay que denir un mtodo para obtener estos datos o para e aproximarlos sin comprometer la eciencia del mecanismo. En la estrategia alternativa, que involucra al SO en la solicitud de carga, como el cdigo del SO tiene acceso directo o a esta informacin, no es necesario denir ning n nuevo mtodo y, simplemente, antes de o u e iniciar una carga anticipada, debe acceder a sus estructuras de datos para descartarla si las condiciones de ejecucin desaconsejan utilizar prefetch. o

4.4

VISION GENERAL DE LA PROPUESTA DE PREFETCH

En este cap tulo hemos analizado los requerimientos que debe cumplir la estrategia de prefetch para ser a adida en el entorno de ejecucin de los programas Java, y cmo esta n o o tcnica se puede beneciar de las caracter e sticas propias del entorno para optimizar el rendimiento del sistema de memoria. Este anlisis nos ha permitido obtener un primer a

80

Cap tulo 4

esbozo de la estrategia de prefetch, decidiendo qu componente del entorno de ejecucin e o debe encargarse de cada tarea involucrada en el prefetch, para maximizar su rendimiento. En esta seccin resumimos las principales conclusiones de este anlisis, presentando una o a visin general de la estrategia de prefetch que proponemos a adir al entorno de ejecucin o n o de Java (ver gura 4.1).
bytecode(pc, obj, pos, caract) pgina i soporte del SO predice(p) carga(p) disco

SO

JVM
soporte del SO i accede (i)

p memoria fsica

Figura 4.1 Visin general del mecanismo de prefetch o

Proponemos que la JVM se encargue de la tarea de seleccin de pginas de prefetch. Para o a ello, para cada bytecode de acceso a memoria, actualiza la informacin que tiene sobre el o patrn de accesos del programa y, utilizando este patrn, se encarga de predecir cules o o a sern las prximas referencias a memoria (ver gura 4.1). Hay que destacar que toda la a o informacin que tiene la JVM sobre los accesos a memoria de las instrucciones permite o obtener un patrn de accesos muy minucioso, y, por lo tanto, permite predecir de forma o muy precisa los prximos accesos de las instrucciones. o

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

81

Adems, esta estrategia permite mantener diferentes patrones de acceso en funcin de a o las caracter sticas de la instruccin y del objeto accedido, lo cual tambin simplica la o e obtencin del patrn de accesos y optimiza la ejecucin de la tarea de seleccin. En el caso o o o o de los accesos a arrays la seleccin que proponemos se ejecuta a nivel de instruccin. Es o o decir, para cada instruccin se mantiene un patrn de accesos independiente, que tambin o o e tiene en cuenta el objeto accedido, y que se utiliza para predecir las referencias de esa instruccin en sus prximas ejecuciones. o o Para completar la seleccin de pginas de prefetch, es necesario decidir la distancia de o a prefetch adecuada y aplicar el ltro para eliminar peticiones de prefetch innecesarias. Para ello, existen dos alternativas: se pueden utilizar heur sticas que aproximen el estado de la memoria o se puede modicar el SO para que exporte esta informacin al nivel de o usuario. Es necesario evaluar las dos alternativas para determinar si el uso de heur sticas es suciente para obtener un buen rendimiento o si, por el contrario, es necesario modicar el SO para poder acceder a la informacin real sobre el estado de la memoria. Por este o motivo, en la gura 4.1 hemos querido representar tambin la posible participacin del e o SO en la tarea de seleccin de pginas. o a En cuanto a la carga en memoria de las pginas seleccionadas, proponemos que sea el SO a en el encargado de llevarla a cabo (ver gura 4.1). De esta manera, se garantiza que los accesos al hardware involucrados respetan la integridad de la mquina y la proteccin del a o resto de procesos en ejecucin. Sin embargo, nos hemos planteado dos posibilidades para o la solicitud de esta carga. La primera opcin es que la JVM aproveche alg n mecanismo o u ya existente en el sistema para provocar la carga as ncrona de las pginas seleccionadas. a Esta opcin obtiene una carga anticipada transparente al SO y, por lo tanto, el SO no o puede colaborar para optimizar el mecanismo. La segunda opcin consiste en modicar el o SO con un interfaz dedicado para la carga as ncrona de memoria. Con esta opcin, el SO o puede participar tambin en las decisiones de carga anticipada, por ejemplo, descartando e las operaciones de prefetch si las condiciones de ejecucin as lo recomiendan. En la gura o 4.1 tambin hemos representado la posible participacin del SO en la solicitud de carga. e o Nuestra propuesta supera las desventajas de las estrategias de prefetch propuestas en los entornos tradicionales basados en compilacin en los siguientes aspectos: o

82

Cap tulo 4

Selecciona de forma precisa las pginas de prefetch. La JVM es el componente del a entorno de ejecucin capaz de predecir los prximos accesos con mayor precisin, ya o o o que dispone de ms informacin sobre los accesos: a o Conoce todos los accesos, a diferencia del SO, que slo es informado de los accesos o involucrados en fallos de pgina. a Conoce todas las caracter sticas de los accesos, a diferencia del SO, que slo tiene o la informacin proporcionada por la excepcin de fallo de pgina. o o a Y adems en tiempo de ejecucin, no como el compilador que slo puede hacer a o o un anlisis esttico de los programas. a a Respeta el paradigma de portabilidad de los programas Java. A diferencia del compilador, es capaz de adaptar las decisiones de prefetch, en tiempo de ejecucin, a las o caracter sticas de la plataforma f sica y a las condiciones de ejecucin sin necesidad o de regenerar el ejecutable del programa y de forma transparente al usuario. Es transparente al programador y al usuario. Cualquier programa se puede beneciar de esta tcnica sin participacin del programador, ni del usuario y sin requerir siquiera e o el cdigo fuente. o Respeta la abilidad del sistema, ya que el SO es el encargado de llevar a cabo la carga de las pginas. a

Como consecuencia del anlisis que presentamos en este cap a tulo, hemos visto factible la implementacin de un mecanismo ecaz de prefetch totalmente transparente al SO. Por o este motivo, nuestro dise o inicial evita cualquier modicacin del SO y utiliza slo el n o o interfaz existente, junto con las heur sticas necesarias para suplir, si es necesario, la falta de informacin exacta. o En el cap tulo 5 presentamos este dise o inicial, su implementacin y su evaluacin. Los n o o resultados de la evaluacin nos muestran que, aunque con esta estrategia hemos obtenido o un prefetch ecaz, es posible mejorar su estabilidad y eciencia si se a ade al mecanismo n cierto grado de cooperacin con el SO. o

Mejora del rendimiento de los programas Java mediante el prefetch de memoria

83

En el cap tulo 6 presentamos el dise o del prefetch cooperativo en el que se basa nuestra n propuesta nal. En este dise o introducimos los cambios necesarios en el interfaz del SO n para conseguir un mecanismo ms estable y poder eliminar algunas heur a sticas de las que, aunque han demostrado ser una buena aproximacin de la realidad en los programas que o hemos evaluado, no es posible asegurar su ecacia para el resto de programas. Mediante esta estrategia obtenemos un mecanismo ecaz y estable, que demuestra que es posible mejorar el rendimiento de los programas Java implementando la cooperacin entre el SO y o la JVM para obtener una gestin de recursos adaptada al comportamiento del programa. o

5
PREFETCH GUIADO POR LA JVM Y TRANSPARENTE AL SO

En este cap tulo presentamos el dise o y la implementacin de un prefetch a nivel de n o usuario, que se ejecuta de forma totalmente transparente al SO. En esta estrategia, la JVM utiliza la informacin que tiene sobre el comportamiento de los programas para predecir de o forma precisa las prximas referencias a memoria y solicitar su carga anticipada. Adems, o a para completar una seleccin eciente de pginas de prefetch sin modicar el SO, aproxima o a mediante heur sticas la informacin sobre el estado de la memoria. Una vez seleccionadas o las pginas, la JVM solicita su carga aprovechando el mecanismo ya existente para resolver a los fallos de pgina de los procesos, de manera que, aunque el SO es el encargado de leer a la pgina del rea de swap, no es necesario modicarlo con ninguna nueva funcionalidad. a a En las secciones 5.1 y 5.2 presentamos una discusin sobre los aspectos ms relevantes que o a hay que tener en cuenta durante la implementacin de las dos tareas principales del preo fetch (seleccin de pginas y carga as o a ncrona), y en la seccin 5.3 mostramos una visin o o general de la estrategia. A continuacin, explicamos detalladamente la implementacin o o de ambas tareas as como los puntos cr ticos de esta implementacin para obtener una o estrategia eciente (seccin 5.4). Completa este cap o tulo los resultados que hemos obtenido de la evaluacin de la estrategia de prefetch transparente al SO (seccin 5.5) y las o o conclusiones que hemos extra durante el desarrollo y la evaluacin de esta estrategia do o (seccin 5.6). o

85

86

Cap tulo 5

5.1

SELECCION DE PAGINAS DE PREFETCH

Como hemos visto en el cap tulo 4, la JVM es el componente del entorno de ejecucin o ms adecuado para predecir las prximas referencias a memoria que los programas van a a o realizar. Por lo tanto la estrategia de prefetch que proponemos se basa en introducir el cdigo de seleccin dentro de la JVM. La seleccin de pginas que proponemos consiste o o o a en utilizar la informacin sobre los accesos a memoria de cada instruccin para predecir o o las prximas referencias del programa, aplicar a las referencias predichas la distancia de o prefetch adecuada y ltrar del conjunto aquellas pginas que ya se encuentran presentes a en memoria f sica. En este trabajo nos estamos centrando en el tratamiento de los arrays de grandes dimensiones que provocan el uso intensivo de la memoria virtual. Por este motivo, proponemos una seleccin de pginas de prefetch a nivel de instruccin. Es decir, para cada instruccin o a o o predecimos las referencias a memoria que realizar en sus prximas ejecuciones. Esto ima o plica mantener para cada una de ellas la informacin sobre su patrn de accesos, teniendo o o en cuenta, adems, el objeto que est accediendo en cada momento. Adems, como hemos a a a visto en la seccin 3.4 del cap o tulo 3, normalmente el patrn de acceso a un array suele o ser strided, por lo que el algoritmo de prediccin que hemos implementado est orientado o a a detectar los strides de acceso de las instrucciones. Esta focalizacin en el uso de los o arrays nos permite tambin ligar la ejecucin de la seleccin de pginas slo a las instruce o o a o ciones que ejecutan bytecodes de acceso a arrays, sin afectar al tratamiento del resto de bytecodes (ver gura 5.1). Hay que destacar que esta simplicacin no cierra las puertas a aplicar nuestra propueso ta de prefetch a otro tipo de aplicaciones en un trabajo futuro. Recordemos que tener la informacin sobre las instrucciones que realizan los accesos a memoria, nos permite o utilizar varias funciones de prediccin en funcin de las caracter o o sticas del objeto o de la instruccin. Por lo tanto, ser posible mantener la prediccin strided para los bytecodes o a o de acceso a vectores y asociar al resto de bytecodes de acceso a memoria un algoritmo de prediccin ms genrico capaz de detectar su patrn de acceso. o a e o

Prefetch guiado por la JVM y transparente al SO

87

. . . iload . . . iaload . . . iastore . . .

Seleccin pginas

Cdigo bytecode

Figura 5.1 Prediccin a nivel de instruccin o o

5.1.1

Efectividad de la prediccin a nivel de instruccin o o

Para aproximar la efectividad de la seleccin de pginas a nivel de instruccin hemos o a o implementado un prototipo de prediccin. Este prototipo consiste en modicar la JVM o para que cada instruccin de acceso a array, antes de realizar el acceso correspondiente, o prediga y acceda tambin a la direccin que referenciar en su prxima ejecucin. Hay que e o a o o destacar que este acceso a la pgina predicha provoca un fallo de pgina, si la pgina se a a a encuentra en el rea de swap y, por lo tanto, la carga en memoria anticipada a la referencia a real del proceso. Sin embargo, no es una operacin de prefetch ya que la carga se hace de o forma s ncrona, es decir, el proceso se bloquea hasta que se completa el tratamiento de fallo de pgina y, por tanto, la lectura de disco asociada. a El algoritmo de prediccin que hemos implementado es muy sencillo y es capaz de detectar o un patrn con varios strides. Para ello, calcula el stride utilizado por cada instruccin o o (guardando siempre la direccin accedida por la ejecucin previa de la instruccin) y o o o almacena los valores de cada stride obtenido, el n mero de accesos consecutivos que se u realizan usando cada uno de ellos, y el orden de las transiciones entre los diferentes strides.

88

Cap tulo 5

En este prototipo, pues, cada instruccin de acceso a array realiza dos accesos a memoria: o primero, el que se corresponde con la direccin predicha y, luego, el correspondiente a la o instruccin en curso. Para aproximar la tasa de aciertos de la prediccin, hemos contado o o por separado los fallos de pgina producidos por el cdigo de prediccin y los fallos de a o o pgina producidos por el cdigo del programa. As es posible obtener el n mero terico a o , u o de fallos de pgina que el algoritmo de prediccin podr evitar. Para este recuento, hemos a o a adaptado el gestor de dispositivo implementado para la evaluacin del uso de memoria, o descrito en el cap tulo 3, al nuevo criterio de clasicacin de fallos de pgina. o a La plataforma que hemos utilizado para este experimento es la misma utilizada para la evaluacin del cap o tulo 3: PC con un procesador Pentium III a 500 Mhz y 128Mb de memoria f sica, la versin 2.2.12 del kernel de Linux y la versin 1.3.1 de la JVM HotSpot o o de Sun. En la gura 5.2 mostramos el resultado de este experimento para los cuatro programas que, seg n los resultados presentados en el cap u tulo 3, son candidatos a mejorar su ejecucin o mediante prefetch: Crypt, HeapSort, FFT y Sparse. Hemos ejecutado cada programa sobre la cantidad de memoria f sica que hace necesario el uso de memoria virtual para completar su ejecucin. Cada grca presenta el n mero de fallos de pgina de cada o a u a programa tanto en el entorno de ejecucin original (en la gura, Sin prediccin) como o o en el entorno modicado con el prototipo de prediccin (en la gura, Prediccin (instro o obj)). Los fallos de pgina en el entorno modicado aparecen divididos en dos tipos: los a provocados por el cdigo de prediccin y los provocados por el cdigo del programa. La o o o situacin ideal ser que en el entorno modicado el cdigo del programa no provocara o a o ning n fallo de pgina y todos fueran debidos a la ejecucin del cdigo de prediccin. u a o o o Se puede observar que, para tres de los cuatro programas evaluados (Crypt, FFT y Sparse), el resultado de este prototipo se acerca bastante al ideal y, aunque la ejecucin o del cdigo de prediccin no elimina por completo los fallos de pgina del cdigo del o o a o programa, consigue reducirlos considerablemente. As el porcentaje de fallos de pgina , a del programa no eliminados es de 9,7 % para el peor caso (FFT), de 3,46 % para Sparse y de 1,17 % en el mejor caso (Crypt).

Prefetch guiado por la JVM y transparente al SO

89

Crypt SizeC

HeapSort SizeC

Fallos de pgina hard

Fallos de pgina hard Sin prediccin

1,20E+05 8,00E+04 4,00E+04 0,00E+00 Prediccin (instr-obj)

1,60E+07 1,20E+07 8,00E+06 4,00E+06 0,00E+00 Sin prediccin Prediccin (instr-obj) Prediccin (instr-obj)

FFT SizeA

Sparse SizeC

Fallos de pgina hard

Fallos de pgina hard Sin prediccin Prediccin (instr-obj)

1,00E+07 7,50E+06 5,00E+06 2,50E+06 0,00E+00

2,50E+06 2,00E+06 1,50E+06 1,00E+06 5,00E+05 0,00E+00 Sin prediccin

Cdigo prediccin Cdigo aplicacin

Figura 5.2 Efectividad de la prediccin a nivel de bytecode o

En cuanto a HeapSort, en la gura 5.2, podemos observar que los fallos de pgina proa vocados por el cdigo de prediccin no consiguen evitar los fallos de pgina del programa, o o a ya que se deben a predicciones errneas. Es ms, al cargar la memoria con pginas no o a a necesarias, se incrementa el n mero de fallos de pgina del programa, lo cual penaliza el u a rendimiento del sistema. Este comportamiento se debe a que este programa no utiliza un patrn de accesos regular y, por lo tanto, no es posible anticipar cules sern sus accesos o a a

90

Cap tulo 5

futuros. La implementacin nal del cdigo de prediccin debe ser capaz de detectar esta o o o situacin y desactivar el prefetch, para no perjudicar el rendimiento del sistema. o Hemos querido aprovechar el prototipo para comparar la precisin de la estrategia a nivel o de instruccin con la que se podr obtener mediante una caracterizacin parcial de los o a o accesos. En particular, hemos implementado dentro del prototipo una prediccin a nivel o global, en la que el algoritmo de prediccin se comporta como si no tuviera la informacin o o sobre la instruccin que est realizando el acceso ni sobre el objeto situado en la direccin o a o accedida y calcula los strides en funcin de los ultimos accesos a arrays. Hay que destacar o que la prediccin a nivel global aproxima el tipo de prediccin que podr hacer el SO, ya o o a que ste slo dispone de informacin sobre la direccin accedida. Es ms, la informacin e o o o a o del SO es incluso menor ya que slo es informado sobre los accesos que provocan fallos de o pgina y en este prototipo se usa la informacin sobre todos los accesos. a o Adems de esta comparacin entre las dos estrategias extremo, hemos evaluado tambin la a o e tasa de aciertos que se tendr manteniendo el patrn de accesos slo a nivel de instruccin a o o o (sin tener en cuenta el objeto que utiliza en cada momento), y mantenindolo slo a nivel e o de objeto (sin tener en cuenta desde qu instruccin se accede al objeto). El objetivo e o de la evaluacin de estas estrategias intermedias es determinar si es posible optimizar la o seleccin de pginas reduciendo la cantidad de datos manejada, sin renunciar a la precisin o a o obtenida mediante la caracterizacin completa de los accesos. o En la gura 5.3 presentamos los resultados de emular estos tipos de predicciones sobre los tres programas con patrn de accesos predecible: Crypt, FFT y Sparse. Podemos o observar que, para los tres programas, la prediccin que tiene un peor comportamiento o (la que evita menos fallos de pgina del programa) es la que se ejecuta sin tener en cuenta a ni el objeto accedido ni la instruccin en ejecucin (en la gura 5.3, Prediccin global). Es o o o decir, intentar predecir los prximos accesos usando slo la informacin disponible en el o o o SO ofrece una baja tasa de aciertos. Los tres programas tambin coinciden en comportarse de forma similar tanto si se mane tiene el patrn a nivel de instruccin y teniendo en cuenta el objeto accedido (en la gura o o 5.3, Prediccin (instr-obj)), como si se mantiene unicamente a nivel de instruccin (en la o o

Prefetch guiado por la JVM y transparente al SO

91

Crypt SizeC

Fallos de pgina hard

8,80E+04 6,60E+04 4,40E+04 2,20E+04 0,00E+00


i n ( Pr ed inst r-o ic ci bj n ) Pr ed (in ic st Pr r) ed ci n ic (o ci bj n ) gl ob al

Cdigo prediccin Cdigo aplicacin

Pr ed ic c

FFT SizeA

Sparse SizeC

Fallos de pgina hard

7,20E+06 4,80E+06 2,40E+06 0,00E+00


i n ( Pr ed inst r-o ic ci bj n ) Pr ed (in ic st Pr r) ed ci n ic (o ci bj n ) gl ob al

Fallos de pgina hard

9,60E+06

2,12E+06 1,59E+06 1,06E+06 5,30E+05 0,00E+00


i n ( Pr ed inst r-o ic ci bj n ) Pr ed (in ic st Pr r) ed ci n ic (o ci bj n ) gl ob al

Figura 5.3 Informacin sobre accesos y ecacia de la prediccin o o

gura 5.3, Prediccin (instr)). Esto es debido a que, para estos tres programas, en la mayor o parte de casos una instruccin slo accede a un objeto, y por lo tanto no hay variaciones en o o el patrn obtenido en ambos casos. El unico caso en el que hay instrucciones que acceden o a varios objetos lo encontramos en el programa Crypt, en el que existe una funcin que o se ejecuta dos veces y cada una de ellas sobre objetos diferentes. Por lo tanto, para este programa, podr esperarse alguna diferencia entre ambas estrategias de prediccin. La a o explicacin para que esto no sea as la encontramos en el patrn de accesos de la funcin. o o o

Pr ed ic c

Pr ed ic c

92

Cap tulo 5

Esta funcin ejecuta un unico recorrido secuencial (stride 1) sobre cada objeto, ambos del o mismo tama o. Es decir, la caracterizacin correcta de los accesos de esta funcin, conn o o sistir en mantener dos patrones independientes idnticos: stride 1 que se aplica tantas a e veces como elementos tiene el objeto. Sin embargo, si no se distingue entre los objetos accedidos, se mantiene un unico patrn para cada instruccin que utiliza dos strides. El o o primero es el que se aplica para recorrer secuencialmente los dos arrays. El segundo es el que se detecta al cambiar el array que se est recorriendo, es decir, despus de usar tantas a e veces el primer stride como elementos tiene un array, y su valor es la separacin entre o los dos arrays. Hay que decir que este segundo stride slo se intentar aplicar una vez, al o a terminar el recorrido del segundo array, momento en el que se acaba la segunda y ultima invocacin de la funcin. Por este motivo, slo se realiza una prediccin errnea. o o o o o Generar los patrones de acceso considerando unicamente el objeto, sin tener en cuenta la instruccin desde la que se accede (en la gura 5.3, Prediccin (obj)), puede ser efectivo si o o todas las instrucciones que lo utilizan lo hacen con el mismo patrn. En el caso de Crypt o esto es as ya que todas las instrucciones acceden de forma secuencial a los objetos. El , programa Sparse accede siempre secuencialmente a tres de sus objetos mientras que otros dos pueden ser accedidos secuencialmente (durante la inicializacin) o de forma aleatoria o (durante el bucle de la multiplicacin). Sin embargo, debido al tama o de estos dos objetos o n y al uso que se hace de ellos, su impacto sobre el rendimiento de la memoria virtual es muy peque o, por lo que no se se aprecia diferencia entre la prediccin considerando n o slo el objeto o considerando tanto el objeto como la instruccin que accede. En cuanto a o o FFT, este programa accede desde varias instrucciones y con diferentes patrones de acceso al array de gran tama o que utiliza. Por este motivo, usar slo la informacin sobre el n o o objeto para generar el patrn de accesos no es suciente para predecir de forma correcta o los accesos futuros. Como conclusiones del anlisis de este prototipo inicial de prediccin podemos decir que, a o independientemente del cdigo y de los datos del programa, una prediccin global es la o o peor opcin para captar el patrn de accesos de los programas. Esta conclusin nos lleva a o o o conrmar que implementar la tarea de seleccin de pginas de prefetch dentro del SO no o a es una opcin adecuada, dado que, con la informacin que ste tiene sobre los accesos a o o e

Prefetch guiado por la JVM y transparente al SO

93

memoria de los programas, slo podr implementar una estrategia de seleccin de pginas o a o a basada en una prediccin global. o En cuanto a la ganancia de tener la prediccin a nivel de instruccin y objeto, con respecto o o a tenerla slo a nivel de instruccin o slo a nivel de objeto, depender del tipo de uso que o o o a las instrucciones hagan de los objetos. En cualquier caso, teniendo en cuenta slo uno de o los dos parmetros (objeto o instruccin) no se mejora la tasa de aciertos de usar ambos a o parmetros. a

5.1.2

Caracterizacin del patrn de accesos o o

La JVM tiene toda la informacin necesaria para poder caracterizar el patrn de acceso o o de las instrucciones y, en el caso de los accesos strided a arrays lo puede hacer de una manera muy simple. Para determinar el stride utilizado por una instruccin en el acceso a un array es suciente o con mantener almacenada la direccin referenciada por su ejecucin previa sobre ese array o o y calcular la separacin (stride) que esa direccin tiene con respecto a la direccin que o o o est referenciando en la ejecucin actual de la instruccin. a o o Si las instrucciones utilizaran slo un stride en sus accesos, la caracterizacin consistir o o a unicamente en calcular el stride que separa los accesos de sus dos primeras ejecuciones sobre el array. Sin embargo, para ser capaces de tratar con instrucciones que utilizan varios strides en los accesos a un vector, como ocurre, por ejemplo, en las instrucciones que forman parte de bucles anidados, la JVM tiene que ser capaz de detectar diferentes strides y de determinar cul debe usar en cada momento para predecir los prximos accesos. a o Es decir, los parmetros que sirven para caracterizar el patrn de accesos strided son el a o n mero de strides utilizados y el valor de cada uno, el n mero de veces consecutivas que u u se aplica cada uno de ellos y el orden de utilizacin entre ellos. o

94

Cap tulo 5

La caracterizacin se puede dar por nalizada al detectar una transicin que completa o o un ciclo entre los diferentes strides y comprobar que ese ciclo representa el patrn que la o instruccin aplica repetitivamente en el resto de sus accesos. o Por ejemplo, consideremos el algoritmo de multiplicacin de matrices almacenadas en o memoria por las. En este caso, cada matriz fuente es accedida mediante una instruccin o que utiliza tres strides diferentes (ver gura 5.4).

Matriz A
s2 s1 s3

Matriz B

FILAS_A

s1

FILAS_B

s2 COLS_A

s3

R[i,j] := R[i,j] + A[i,k]*B[k,j]

COLS_B

Figura 5.4 Patrn de accesos en la multiplicacin de matrices o o

Para acceder a la matriz que se recorre por las (matriz A en la gura 5.4), se utiliza un primer stride para recorrer de uno en uno todos los elementos de una la (s1 == 1). Despus de completar el acceso a cada la, utiliza un segundo stride que sirve para repetir e el uso de la la. Es decir, en cada ejecucin de la instruccin que sea m ltiplo del n mero o o u u de elementos de una la se utiliza como stride el valor adecuado para situarse de nuevo al inicio de la la (s2 == -(COLS A - 1)). El n mero de recorridos que se realizan sobre u cada la viene determinado por el n mero de columnas de la segunda matriz fuente (la u que es recorrida por columnas). Despus de este n mero de recorridos, se cambia la la e u fuente utilizando un tercer stride. Suponiendo que las matrices se almacenan por las, su

Prefetch guiado por la JVM y transparente al SO

95

valor es el mismo que para el stride de primer nivel (s3 == 1). Este patrn de accesos se o puede representar mediante el grafo de estados que aparece en la gura 5.5.
1

1 s1 !=COLS_A*COLS_B !=COLS_A COLS_A s2 s3

s1 == 1 s2 == -(COLS_A -1) s3 == 1

COLS_A*COLS_B

Figura 5.5 Grafo del recorrido por las en la multiplicacin de matrices o

En cuanto a la matriz que se recorre por columnas (matriz B en la gura 5.4), el primer stride es el que se utiliza para recorrer todos los elementos de una columna. Su valor depende del n mero de elementos de la la (s1 == COLS B). El segundo stride es el u que permite cambiar de columna, y su valor, depende del tamao de cada la y del de n cada columna (s2 == -((COLS B * FILAS B) - 1)). Se utiliza despus de haber recorrido e toda una columna, es decir, en cada ejecucin de la instruccin m ltiplo del n mero de o o u u elementos de la columna. El tercer stride es el se utiliza cuando se inicia el clculo de la a siguiente la destino, es decir, despus de haber utilizado tantas veces el primer stride e como elementos tiene la matriz, y sirve para volver a recorrer toda la matriz. Su valor es el tama o de la matriz, pero con signo negativo (s3 == -((COLS B * FILAS B) - 1)). n En la gura 5.6 representamos el grafo de estados que representa el patrn que siguen los o accesos a la matriz recorrida por columnas.

5.1.3

Consideraciones para la optimizacin de la seleccin de o o pginas a

Como ya se dijo en el cap tulo 4, un requerimiento importante para que la tcnica de e prefetch sea efectiva es que el tiempo involucrado en su ejecucin sea el menor posible, o para que no oculte los benecios de la carga anticipada.

96

Cap tulo 5

1 s1 !=FILAS_B*COLS_B !=FILAS_B FILAS_B s2 s3

s1 == COLS_B s2 == -(FILAS_B -1) s3 == -((FILAS_B*COLS_B)-1)

FILAS_B*COLS_B

Figura 5.6 Grafo del recorrido por columnas en la multiplicacin de matrices o

Existen varios aspectos relacionados con la seleccin de pginas que permiten la simplio a cacin del cdigo ejecutado para realizar esta tarea y que, por lo tanto, se deben tener en o o cuenta en su implementacin. o El primer aspecto es el que se reere a las instrucciones que siguen un patrn de accesos o irregular y, por lo tanto, impredecible. Estas situaciones se deben detectar durante la fase de generacin del patrn de accesos para poder desactivar la ejecucin del cdigo de o o o o prediccin para esa instruccin y, de esta manera, evitar la ejecucin de un cdigo incapaz o o o o de mejorar el rendimiento del programa. Otro aspecto a tener en cuenta para optimizar la ejecucin es evitar selecciones reduno dantes de pginas de prefetch. El objetivo del algoritmo de prediccin es seleccionar las a o pginas que vamos a cargar con antelacin. Esto signica que lo que nos interesa detera o minar es el stride en unidades de pgina, en lugar de unidades de elementos del vector, a para saber cuales son las pginas que se referenciarn despus de la actual. a a e Adems, si una instruccin tiene como prediccin la misma pgina en varias ocasiones a o o a diferentes, y entre las dos predicciones la pgina no ha sido expulsada de memoria, ena tonces la segunda prediccin es redundante y, por lo tanto, se podr evitar la ejecucin o a o del cdigo que la ha seleccionado. El cdigo necesario para prever esta situacin de forma o o o genrica es complicado, y no tiene sentido implementarlo si el objetivo es minimizar el e

Prefetch guiado por la JVM y transparente al SO

97

coste del cdigo de prediccin. Sin embargo existen situaciones particulares en las que se o o da esta redundancia y que son muy sencillas de determinar. Por ejemplo, si la ejecucin de una instruccin accede a la misma pgina que su ejecucin o o a o anterior, calculando el stride en unidades de pgina, el resultado de la prediccin ser el a o a mismo y, por lo tanto, no es necesario ejecutar ese cdigo. o Tambin existen patrones de acceso que permiten detectar de forma sencilla predicciones e idnticas y aproximar de forma bastante exacta si son redundantes o no. Se trata de las e instrucciones que dividen los vectores en subconjuntos de elementos, y cada uno de estos subconjuntos constituyen el working set de la instruccin durante un periodo de tiempo, o en el que accede de forma repetitiva a los elementos del working set. Si dos de los working sets caben en memoria, slo es necesario ejecutar el cdigo de prediccin para el primer o o o acceso a cada elemento del working set, para predecir el elemento del siguiente working set que se va a utilizar. Este tipo de patrn se da con frecuencia en las operaciones sobre matrices cuando la o unidad de trabajo es la la o la columna. Por ejemplo, si las matrices estn almacenadas a por las el mismo conjunto de pginas albergar varias columnas consecutivas. Mientras a a se acceda a esas columnas, se estar usando el mismo working set de pginas de forma a a repetitiva, hasta que la columna objetivo forme parte del siguiente working set de pginas a (ver gura 5.7). Un patrn de accesos que represente estrictamente este comportamiento tendr como o a primer stride el que se usa para recorrer todos los elementos de una columna y como segundo stride el que se usa para cambiar de columna. Sin embargo, si es posible mantener en memoria los dos working sets consecutivos al mismo tiempo, se puede optimizar el cdigo de prediccin utilizando unicamente un stride que permita predecir la pgina o o a equivalente del siguiente working set (la que contiene los elementos de la misma la en el siguiente conjunto de columnas) y aplicar este stride unicamente durante el recorrido de la primera columna de cada working set.

98

Cap tulo 5

s1

s1

pi

pi+1

s1

s1

wsi

wsi+1

Figura 5.7 Prediccin basada en working sets o

Para poder aplicar esta simplicacin en el patrn es necesario, adems de detectar el uso o o a de working sets con estas caracter sticas, comprobar que es posible mantener dos de ellos en memoria. Hemos basado esta simplicacin en dos heur o sticas. La primera heur stica es para decidir si es posible mantener simultneamente en memoria a dos working sets de una instruccin. Consiste en comprobar, una vez detectado el uso de o working sets, si los dos ultimos working sets cargados permanecen en memoria. Si es as se puede asumir que para el resto del recorrido se mantendr este comportamiento, y por lo a tanto, se puede aplicar el patrn de accesos simplicado. o La segunda heur stica es necesaria para determinar si un conjunto de pginas est cara a gado en memoria o no. Habitualmente esta informacin sobre el estado de las pginas o a no est disponible desde el nivel de usuario. Para poder utilizar estos datos sin modia car el SO, y as conseguir una estrategia de prefetch totalmente transparente al sistema, hemos implementado un bitmap en el nivel de usuario que representa de forma aproximada el estado de las pginas del heap de la aplicacin. Hay que decir que esta heur a o stica

Prefetch guiado por la JVM y transparente al SO

99

servir tambin para poder ltrar de las pginas seleccionadas para prefetch las que se a e a encuentran presentes en memoria f sica, y as evitar las peticiones innecesarias de carga. Respecto al resto de selecciones redundantes de pginas que no se pueden evitar de una a forma eciente, s que se puede evitar la solicitud de su carga utilizando esta segunda heur stica y consultando el bitmap que aproxima el estado de las pginas del heap. Es a decir, antes de hacer efectiva la solicitud de carga de una pgina seleccionada se debe a comprobar en el bitmap si ya est presente en memoria f a sica y, si es as se debe ltrar del conjunto de pginas seleccionadas. De esta manera, aunque no somos capaces de evitar a la ejecucin del cdigo de prediccin que ha generado estas solicitudes, s que evitamos la o o o sobrecarga asociada al intento innecesario de carga.

5.2

CARGA AS INCRONA Y ANTICIPADA

El acceso al rea de swap, para leer de forma anticipada las pginas seleccionadas por el a a cdigo de prediccin, permite completar el prefetch de memoria. o o Como ya hemos visto en el cap tulo 4, este acceso a disco debe realizarlo el SO, para garantizar de forma sencilla y eciente la abilidad de la mquina. Por lo tanto, es necea sario denir el mecanismo que se puede utilizar para solicitar esta lectura desde el nivel de usuario. Para evitar cualquier modicacin en el SO, y as conseguir una estrategia de prefetch o totalmente transparente al SO, hay que utilizar el mecanismo de fallo de pgina que, a aunque es un mecanismo s ncrono, es el unico interfaz que desde el nivel de usuario provoca la carga en memoria de pginas que estn en el rea de swap. a a a Debido a la sincron de este mecanismo, el ujo de ejecucin del programa no puede a o encargarse de provocar los fallos de pgina que desencadenen la carga anticipada, ya que a sta se debe realizar en paralelo con la ejecucin del programa. Por este motivo, hemos e o a adido un nuevo ujo de ejecucin en la JVM (prefetcher) que unicamente se encarga de n o solicitar las pginas seleccionadas. Es decir, este nuevo ujo accede a cada direccin que a o

100

Cap tulo 5

interesa cargar con antelacin, provocando el fallo de pgina que desencadena su carga o a y bloquendose hasta que la carga concluye, mientras el ujo de ejecucin del programa a o contin a la ejecucin. u o Adems del ujo de prefetch, hemos a adido las estructuras de datos y el cdigo necesario a n o para implementar la comunicacin y la sincronizacin necesarias entre el prefetcher y el o o ujo de ejecucin del programa. o El ujo de ejecucin debe comunicar al prefetcher las pginas que ha seleccionado para o a cargar con anticipacin. El mecanismo seleccionado para la comunicacin tiene que reso o petar la as ncron necesaria para que la carga sea efectiva. Es decir, el ujo de ejecucin a o del cdigo del programa no debe bloquearse tampoco para hacer efectivo este paso de o informacin. Este objetivo se puede conseguir fcilmente implementando la comunicacin o a o entre ambos ujos mediante un buer circular compartido, donde la JVM vaya dejando las direcciones que interesa cargar con antelacin, y el prefetcher las vaya recogiendo para o solicitar del SO su carga. La implementacin de este mecanismo de comunicacin lleva asociada la necesidad de o o decidir el comportamiento de ambos ujos si se da el caso de que no haya peticiones pendientes y si ocurre que el buer se llena porque la velocidad de generacin de peticiones o de la JVM es demasiado alta comparada con la velocidad con la que se pueden resolver esas peticiones. En el caso de que el prefetcher no tenga peticiones pendientes, para no consumir CPU innecesariamente, lo ms adecuado es bloquearlo hasta que la JVM tenga preparada a nuevas solicitudes. Por lo tanto, cuando el cdigo de seleccin de pginas de prefetch o o a introduzca una nueva peticin en el buer, deber comprobar si el prefetcher estaba o a bloqueado para, en ese caso, desbloquearlo y permitir que contin e con las solicitudes de u carga. Para tratar el caso del buer lleno, hay que tener en cuenta que el cdigo del prograo ma no deber bloquearse como consecuencia de una solicitud de carga anticipada, para a conseguir el solapamiento entre carga y clculo. Teniendo en cuenta, adems, que otro a a

Prefetch guiado por la JVM y transparente al SO

101

de los requisitos es obtener un cdigo eciente, la unica opcin es descartar alguna de o o las solicitudes de carga anticipada. Sin embargo, la prdida de peticiones de prefetch es e una situacin que se deber evitar en la medida de lo posible, ya que se pierden posibles o a puntos de optimizacin del rendimiento. Por este motivo, es importante dimensionar de o forma adecuada el buer de peticiones. El mecanismo de solicitud de carga descrito en esta seccin se puede implementar meo diante un cdigo muy simple. Sin embargo, para que la implementacin sea ecaz, debe o o tener en cuenta varios aspectos de bajo nivel, como por ejemplo, la inuencia que puede tener la pol tica de planicacin de ujos del SO, la inuencia en el rendimiento de los o cambios de contexto necesarios entre los dos ujos, o el coste de ejecutar las operaciones de sincronizacin. o Adems, hay que tener en cuenta que estamos implementando una pol a tica de prefetch totalmente transparente al SO. Es decir, el prefetcher, desde el nivel de usuario, toma decisiones que forman parte de la gestin de memoria de un programa y que, por lo tanto, o interaccionan con las decisiones de gestin de memoria que el SO sigue tomando sin tener o en cuenta este nuevo cdigo. Esto hace necesario analizar esta interaccin para comprobar o o su efecto sobre el rendimiento nal del programa.

5.3

VISION GENERAL: PREFETCH A NIVEL DE USUARIO

En la gura 5.8 presentamos una visin general de la estrategia de prefetch implementada o por completo en el nivel de usuario. En esta estrategia hemos modicado unicamente la JVM, de manera que el prefetch es totalmente transparente al SO. Adems, cualquier programa ejecutado sobre la JVM a puede beneciarse del prefetch, sin que sea necesario ni tan siquiera recompilarlo. Para cada bytecode de acceso a array se ejecuta el cdigo de seleccin de pginas que, si o o a es necesario, actualiza la informacin sobre el patrn de accesos de la instruccin usando o o o

102

Cap tulo 5

los datos del acceso actual y de la prediccin anterior, y se encarga de decidir si es o adecuado cargar anticipadamente alguna pgina. De ser as dejar la direccin de la a , a o pgina seleccionada en el buer compartido con el ujo de prefetch y continuar con la a a ejecucin normal del bytecode. Por su parte, el ujo de prefetch accede a este buer para o recoger las solicitudes de prefetch, y las lleva a cabo simplemente accediendo a la direccin o involucrada. Si la pgina est almacenada en el rea de swap, el acceso provocar un fallo a a a a de pgina que bloquear al prefetcher hasta que la rutina de atencin al fallo de pgina a a o a complete la carga. El cdigo de seleccin de pginas no dispone de una informacin exacta sobre las pginas o o a o a presentes en memoria, por lo tanto puede ser que se hagan solicitudes de prefetch para pginas ya presentes. En este caso, el acceso de prefetch se convierte en un acceso a a memoria normal, y por lo tanto no implica accesos a disco innecesarios.
bytecode(pc, obj, pos, caract) pgina i predice(p) fallo de pgina disco accede(p) i accede(i)

SO

JVM

p memoria fsica

Figura 5.8 Visin general del prefetch transparente al SO o

Prefetch guiado por la JVM y transparente al SO

103

5.4

IMPLEMENTACION DEL PREFETCH A NIVEL DE USUARIO

En esta seccin describimos de una forma detallada la implementacin del prefetch a nivel o o de usuario. Los algoritmos y las estructuras de datos involucradas en el prefetch son a priori sencillos. Sin embargo, para obtener una implementacin ecaz hemos tenido que o ser muy cuidadosos por dos motivos principales. El primer motivo es que el cdigo de prefetch, presumiblemente, se va a ejecutar con o mucha frecuencia y, por lo tanto, es primordial que sea eciente. Hay que tener en cuenta que recorrer un array de grandes dimensiones requiere millones de ejecuciones del bytecode de acceso. Por lo tanto, la repercusin de cualquier l o nea de cdigo a adida al tratamiento o n del bytecode viene multiplicada por ese factor. El segundo motivo es que estamos implementando una optimizacin del uso de recursos o de forma transparente al SO, lo que implica que el SO reacciona ante este cdigo de la o misma manera que ante cualquier cdigo de usuario, sin tener en cuenta su objetivo de o gestin, lo que le puede llevar a tomar decisiones de gestin que perjudiquen la ejecucin o o o del prefetch o que entren en conicto con las decisiones de prefetch y, por lo tanto, que perjudiquen su ecacia. Durante la fase de implementacin hemos analizado el tiempo de prefetch invertido en la o ejecucin de los programas, para determinar los posibles puntos de optimizacin, tanto los o o debidos a la ejecucin del propio cdigo de prefetch como los debidos a la interaccin con el o o o SO. Este anlisis nos ha permitido ajustar la implementacin hasta obtener un prototipo a o de prefetch ecaz capaz de mejorar el rendimiento de los programas tipo objetivo de nuestra propuesta. La implementacin que presentamos se ha hecho sobre la versin 2.4.18 del kernel de o o Linux. Hemos introducido el cdigo de prefetch en la JVM HotSpot, versin 1.3.1, que se o o distribuye con la Java 2 SDK Standard Edition de Sun para Linux. De las dos posibles conguraciones de esta JVM hemos seleccionado la conguracin server, que est sintonizada o a para favorecer la ejecucin de aplicaciones con alto consumo de recursos. Adems, para o a

104

Cap tulo 5

facilitar la fase de implementacin, hemos modicado unicamente el cdigo del intrprete o o e de la JVM. Sin embargo, las modicaciones que hemos introducido como parte del tratamiento de cada bytecode, podr formar parte tambin del cdigo generado por el JIT an e o asociado a cada bytecode, consiguiendo que el cdigo de prefetch se ejecutara igualmente. o En la seccin 5.4.1 detallamos todos los aspectos relacionados con la implementacin de o o la tarea de seleccin de pginas de prefetch y en la seccin 5.4.2 nos centramos en la tarea o a o de carga de las pginas seleccionadas. a

5.4.1

Implementacin de la seleccin de pginas o o a

Para poder introducir el cdigo de seleccin de pginas en la JVM hemos modicado el o o a tratamiento de aquellos bytecodes que acceden a arrays. En la tabla 5.1 se muestra cules a son estos bytecodes junto con una breve descripcin. o
Bytecode iaload/iastore laload/lastore faload/fastore daload/dastore aaload/aastore baload/bastore caload/castore saload/sastore Descripcin o Lectura/escritura Lectura/escritura Lectura/escritura Lectura/escritura Lectura/escritura Lectura/escritura Lectura/escritura Lectura/escritura sobre sobre sobre sobre sobre sobre sobre sobre un un un un un un un un array array array array array array array array de de de de de de de de enteros longs oats doubles referencias bytes caracteres shorts

Tabla 5.1 Bytecodes de acceso a arrays

En Java, el acceso a un array es traducido a un bytecode diferente en funcin del tipo o del array y del tipo de acceso que se intenta realizar. As cada tipo de array tiene su , propio bytecode de lectura de un elemento y su propio bytecode de escritura, con un cdigo espec o co asociado para su tratamiento. En todos los casos, en el momento de la ejecucin de uno de estos bytecodes, la pila de operandos de la JVM contiene la direccin o o base del array, el ndice del elemento sobre el que se quiere efectuar el acceso y, en el caso de los bytecodes de escritura, el valor que se quiere almacenar en esa posicin del o vector. Adems, durante el tratamiento del bytecode tambin se conoce la posicin de ese a e o bytecode dentro del cdigo del programa (es decir, un program counter lgico) y se tiene o o acceso a todas las caracter sticas del objeto como, por ejemplo, su tama o. n

Prefetch guiado por la JVM y transparente al SO

105

El cdigo que hemos introducido forma parte del tratamiento de cada bytecode y se o ejecuta previamente al tratamiento original. Lo primero que comprueba es que el tama o n del array objeto del acceso sea superior al umbral establecido. Si no se trata de un array grande se contin a con el tratamiento original del bytecode. u La siguiente comprobacin se utiliza para reducir la cantidad de cdigo de prediccin o o o ejecutada, y forma parte de las heur sticas que utilizamos para evitar selecciones redundantes de pginas. Esta comprobacin consiste en comparar la pgina del acceso de la a o a instruccin actual con la que accedi en su ejecucin previa sobre el mismo objeto: si la o o o pgina es la misma, se asume que el cdigo de prediccin seleccionar la misma pgina a o o a a de prefetch y, por lo tanto, no es necesario ejecutarlo y se contin a con el tratamiento del u bytecode. Si el acceso supera estos dos ltros, entonces se invoca a la funcin de prediccin coo o rrespondiente, pasndole como parmetros los datos necesarios para describir el acceso: a a instruccin desde la que se realiza (el program counter lgico), la direccin base del array, o o o el tama o de cada elemento del array y el n ndice del elemento accedido. Cuando la funcin o de prediccin retorna, se contin a con la ejecucin original del bytecode (ver gura 5.9). o u o
array pequeo || pg. previa == pg. actual

bytecode (pc,array,pos,caract)
iaload

seleccin de pginas

. . . . . . . . . . . .

filtro inicial prediccin informacin prediccin

pginas seleccionadas

cdigo bytecode

Figura 5.9 Visin general de la implementacin de la seleccin de pginas o o o a

106

Cap tulo 5

En este punto hay que comentar que la JVM que estamos modicando, inicia el tratamiento de cada bytecode con un cdigo que se ha escrito en ensamblador, con el objetivo o de que el ejecutable generado para la JVM sea ms optimizado que el generado por el a compilador. Slo para aquellos bytecodes que requieren un tratamiento complejo se ha o primado el objetivo de la portabilidad del cdigo de la JVM y se ha utilizado un lenguaje o de alto nivel para implementar las funciones que completan el tratamiento y que se llaman desde el cdigo inicial. El tratamiento adicional que hemos introducido para los bytecodes o de acceso a arrays sigue el mismo criterio: tiene los dos ltros iniciales implementados en ensamblador y slo si es necesario ejecutar el cdigo de prediccin se invoca a una funcin o o o o escrita en alto nivel. De esta manera optimizamos el cdigo necesario para descartar la o prediccin de las instrucciones que no superan los ltros: primero, porque el cdigo en o o ensamblador que hemos escrito est ms optimizado que el generado por el compilador y, a a segundo, porque evitamos ejecutar todo el cdigo necesario para gestionar la llamada a o la funcin y el correspondiente salto al cdigo de la misma. o o Para implementar la prediccin a nivel de instruccin, necesitar o o amos almacenar, para cada par instruccin-objeto los datos necesarios para predecir los accesos de esa instruccin o o sobre ese objeto. Sin embargo, para esta implementacin hemos optado por asociar para o cada instruccin los mismos datos de prediccin independientemente del objeto al que o o est accediendo. Los experimentos que hemos realizado previamente nos han mostrado que e para nuestros programas de prueba es suciente mantener esta informacin de prediccin. o o Esto es as porque para la mayor de estos programas cada instruccin utiliza slo un a o o objeto. Adems, para los casos en los que no es as el cambio de objeto se puede tratar a , como un nuevo stride cuyo valor sea la separacin entre el objeto anterior y el actual o (ver los resultados que se muestran en la gura 5.3, seccin 5.1.1). Esta simplicacin o o permite optimizar, sobre todo, la localizacin de la informacin que se debe usar en cada o o prediccin. o Los datos de prediccin incluyen, no slo el valor de los parmetros que determinan o o a el patrn de accesos de la instruccin sino tambin, la funcin de prediccin utilizada o o e o o para seleccionar las futuras referencias de la instruccin sobre el objeto. De esta manera o somos capaces de utilizar una funcin de prediccin adaptada a las caracter o o sticas de la instruccin y del objeto. o

Prefetch guiado por la JVM y transparente al SO

107

Para cada uno de los datos necesarios, hemos denido un array que contiene su valor para cada instruccin (ver gura 5.10). Se podr haber organizado toda esta informacin o a o en un unico array de estructuras, donde cada campo de la estructura fuera uno de los datos necesarios. Sin embargo, hemos observado que el compilador presente en nuestro entorno para compilar la JVM genera un cdigo menos eciente cuando el acceso a todos o los datos de la prediccin requieren acceder a campos de una estructura. Esta disminucin o o de la eciencia en el acceso a los datos adquiere una gran importancia cuando se trata de accesos que se realizan millones de ocasiones.

seleccin de pginas
array pequeo || pg. previa == pg. actual

bytecode (pc,array,pos,caract)

filtro inicial

i @

prediccin

i = HASH(pc) informacin prediccin pginas seleccionadas

Figura 5.10 Organizacin de la informacin de prediccin o o o

Con los datos de la prediccin organizados en arrays, dada una instruccin es necesario o o localizar de forma eciente sus datos. Hemos implementado la indexacin de estos arrays o mediante una funcin de hash. El comportamiento ideal de la funcin de hash es el que o o no genera ninguna colisin, es decir, el que establece una biyeccin entre instruccin y o o o posicin del array, ya que de esta manera se minimiza el coste de la indexacin. Experio o mentalmente, hemos obtenido una funcin de hash que exhibe este comportamiento ideal o

108

Cap tulo 5

para todos los programas que hemos evaluado. Esta funcin obtiene el o ndice del array basndose el valor del program counter lgico (ver gura 5.11). a o

#dene HASH(pc) ((pc & 0xF000)

1 ) | (pc & 0x7FF)

Figura 5.11 Funcin de hash para localizar la informacin de prediccin o o o

Implementacin del algoritmo de prediccin o o


En la implementacin de la prediccin, hemos simplicado el algoritmo de generacin de o o o patrones de acceso limitando el n mero mximo de strides considerados a tres. Por lo u a tanto, el algoritmo que hemos implementado es capaz de captar el patrn de acceso de las o instrucciones que forman parte de bucles de hasta tres niveles de anidacin como mximo. o a La generalizacin de este algoritmo no ser complicada. Es ms existen muchas propuestas o a a en la literatura sobre prediccin del comportamiento de los programas dedicadas a este o propsito [PZ91, CKV93, GA94, VK96]. Sin embargo, el algoritmo que proponemos es o capaz de detectar los patrones de todos los benchmarks que hemos utilizado y nos sirve para demostrar los benecios de nuestra propuesta. Por lo tanto, una implementacin ms o a genrica del algoritmo de prediccin queda fuera de los objetivos que nos hemos planteado e o en este trabajo. Este algoritmo, pues, intenta detectar hasta tres strides diferentes as como el n mero u de ejecuciones consecutivas de cada uno de ellos y las transiciones entre ellos. Para ello calcula, para cada instruccin, la separacin entre dos accesos consecutivos. Si el valor o o coincide con el stride utilizado para el acceso previo, entonces incrementa el n mero de u usos consecutivos del stride. Si por el contrario es un valor diferente, considera que es el siguiente nivel (cambio de iteracin en el bucle exterior) y registra el nuevo valor, o actualizando tambin la informacin sobre el orden de transiciones entre strides. e o Adems hemos querido que el algoritmo de prediccin fuera capaz de tratar con aquellas a o instrucciones que, a n usando un unico stride para cada recorrido del array implicado en u un bucle interno, el valor de este stride es diferente al cambiar de iteracin en alguno de los o bucles externos. Para tratar con este caso, al iniciar cada grupo de aplicaciones del primer

Prefetch guiado por la JVM y transparente al SO

109

stride se comprueba si el valor del stride ha cambiado y se actualiza en consecuencia los parmetros de la prediccin. a o El otro aspecto relacionado con el algoritmo de prediccin es el que se reere a las preo dicciones redundantes que, como comentamos en la seccin 5.1.2, se pueden dar en las o instrucciones cuyo patrn de accesos referencia repetitivamente pginas de un working set o a que cabe en memoria y se aplica sucesivamente sobre diferentes working sets. Si adems a del working set en uso, el sistema es capaz de mantener el siguiente working set en memoria, entonces se puede simplicar el algoritmo de seleccin para que el primer acceso a o una pgina de un working set provoque la carga anticipada de la pgina equivalente del a a siguiente working set. Para comprobar si la instruccin sigue este tipo de patrn, se debe cumplir que el uso o o del segundo stride sirva para repetir el acceso al mismo conjunto de pginas, situacin a o que se puede comprobar guardando la primera direccin referenciada por la instruccin y o o comparndola con la accedida despus de aplicar el segundo stride. Adems, el tercer stride a e a debe servir para cambiar el conjunto de pginas utilizadas, es decir, debe ser la distancia a entre la ultima pgina accedida del working set actual y la primera del siguiente. Despus a e del cambio de working set, se debe repetir el uso del nuevo subconjunto mediante los patrones determinados por los otros dos strides. Una vez comprobado que el acceso al vector viene determinado por este tipo de patrn, se o debe comprobar si es posible mantener en memoria simultneamente dos de los subcona juntos del vector. Como simplicacin, hemos supuesto que si los dos primeros working o sets se pueden mantener en memoria al mismo tiempo, entonces tambin ser posible e a hacerlo con el resto de working sets utilizados por la instruccin. Si esto es as se actuao , liza la informacin que describe el patrn de accesos, registrando como unico stride, la o o separacin entre las pginas equivalentes de los dos working sets y almacenando, adems, o a a el n mero de accesos repetitivos que se hacen sobre un working set, para detectar cundo u a la instruccin va a cambiar el working set y activar entonces la seleccin de pginas para o o a el primer acceso a cada pgina del nuevo working set. a

110

Cap tulo 5

Hay que decir que si se captan correctamente los parmetros que caracterizan el patrn a o de accesos de una instruccin, entonces no es necesario calcularlos para cada ejecucin de o o la instruccin, sino que es suciente con aplicarlos para predecir los prximos accesos de o o la instruccin. Este mtodo tambin permite reducir la cantidad de cdigo de prediccin o e e o o que se ejecuta para cada instruccin. Por este motivo, el clculo de cada parmetro pasa o a a por una fase inicial en la que se calcula y se comprueba la efectividad del valor captado. Si de estas comprobaciones se deriva que el valor del parmetro es estable a travs de a e las ejecuciones, entonces se considera validado y se pasa a la fase estabilizada, que simplemente, consiste en aplicar el valor captado sin repetir su clculo. Si por el contrario, a el cdigo de prediccin no es capaz de alcanzar la fase estabilizada, se supone que ese o o parmetro no tiene un comportamiento predecible y se desestima su uso para el resto de a ejecuciones de la instruccin. En particular, si no es posible estabilizar el clculo de los o a tres posibles strides que estamos considerando, entonces se desactiva la prediccin para o esa instruccin y la JVM pasa a ejecutar unicamente el tratamiento original del bytecode. o La gura 5.12 representa el grafo de estados por el que pasa el cdigo de prediccin asoo o ciado a cada instruccin. En esta gura podemos ver la evolucin del cdigo de prediccin o o o o a medida que se validan los diferentes parmetros del patrn de accesos. a o Hemos desglosado el algoritmo de prediccin en varias funciones, dependiendo del estado o en el que se encuentre la generacin del patrn de acceso de la instruccin y en funcin o o o o del tipo de patrn obtenido. El objetivo de esta separacin es conseguir reducir el cdigo o o o ejecutado en cada prediccin al estrictamente necesario seg n el estado en el que se eno u cuentre la caracterizacin de los accesos de la instruccin. As a medida que el cdigo de o o , o prediccin valida el valor de los parmetros de prediccin, tambin cambia la funcin de o a o e o prediccin asociada a la instruccin por otra en la que ya no aparece el cdigo de validao o o cin del patrn (ver gura 5.13). Se podr haber implementado con una unica funcin de o o a o prediccin que, mediante sentencias condicionales decidiera el fragmento de cdigo que se o o debe ejecutar para el estado actual de la prediccin de la instruccin. Sin embargo, hemos o o detectado que el coste de la ejecucin de los condicionales tiene suciente repercusin o o sobre el rendimiento nal como para recomendar su eliminacin. o

Prefetch guiado por la JVM y transparente al SO

111

S2 detectado D2 S1 estable E2

S2 estable D3

S3 detectado E3

S3 wset repet. wset repet. S3 estable y no opt. wset 3 strides

E1

S1 estable

S3 detectado

S2 estable

S3 descartado

S2 detectado

E1E2

E1E2E3 S3 detectado S1 estable

E2E3

1 stride S2 y S3 descartados

2 strides

S1, S2 y S3 descartados aleatorio

E1 Estabilizar stride 1 E1E2 Estabilizar stride1 y stride2 E1E2E3 Estabilizar stride1, stride2 y stride3 aleatorio no se ha podido estabilizar ningn stride E2E3 Estabilizar stride2 y stride3 (stride 1 estabilizado) 1 stride no se han podido estabilizar stride2 y stride3 D2 Detectar stride2 (stride1 estabilizado) E2 Estabilizar stride2 D3 Detectar stride3 (stride2 estabilizado) E3 Estabilizar stride 3 wset repet. Se puede simplificar el patrn de working set 3 strides No se puede simplificar el patrn 2 strides No se ha podido estabilizar stride3

Figura 5.12 Grafo de estados del algoritmo de prediccin o

Heur sticas para aproximar el estado de la memoria


La tarea de seleccin de pginas necesita tener informacin sobre el estado de la memoria o a o del programa en varias de las decisiones que debe implementar. Por ejemplo, esta informacin es imprescindible para evitar la peticin de carga para pginas ya presentes en o o a memoria f sica y puede ayudar en la decisin de la distancia de prefetch aconsejable para o la solicitud de carga anticipada.

112

Cap tulo 5

bytecode (pc,array,pos,caract)

@ E1

@ D2

E1

D2

E2

prediccin

Figura 5.13 Actualizacin de la funcin de prediccin asociada o o o

Como ya hemos dicho en la subseccin anterior, el cdigo de generacin de patrn de o o o o accesos es capaz de detectar algunos patrones que generan selecciones redundantes de pginas y de adaptar el patrn asociado a la instruccin para evitar estas selecciones en a o o las siguientes predicciones. Hay que destacar que, la solicitud de una pgina ya cargada en memoria f a sica, no implica ning n error en la ejecucin. Sin embargo, es importante evitarlas para optimizar la u o ejecucin de la tarea de seleccin de pginas. Adems tambin inuye en el rendimiento o o a a e de la tarea de carga anticipada ya que, aunque la peticin de una pgina ya presente en o a memoria f sica no involucra un acceso a disco, la solicitud tiene un coste asociado como, por ejemplo, el debido al cambio de contexto para ceder el uso de la CPU al ujo de prefetch. Por este ultimo motivo, tambin se intenta ltrar, de las pginas seleccionadas, aquellas e a que ya se encuentran en memoria f sica para evitar el coste de una peticin de carga o innecesaria. Para implementar estas dos optimizaciones, es necesario tener acceso, desde el nivel de usuario, a la informacin sobre el estado de la pgina en la memoria virtual. Los SO o a actuales no exportan esta informacin, por lo tanto, o bien se modica el cdigo del SO o o

Prefetch guiado por la JVM y transparente al SO

113

para introducir un interfaz que permita a la JVM consultar esta informacin, o bien se o utilizan heur sticas que permitan que la JVM aproxime esta informacin. o Uno de los objetivos de este cap tulo es comprobar si es factible dotar al entorno de ejecucin de Java de una pol o tica de prefetch efectiva y adaptada a las caracter sticas de cada programa, sin necesidad de modicar el cdigo del SO. Por este motivo, hemos o aproximado la informacin del estado de las pginas mediante una heur o a stica, que, aunque puede ser que no reeje el estado real de la memoria del programa, sirve para evitar sucientes peticiones redundantes como para ser beneciosa para la ejecucin de la tarea o de seleccin. o La implementacin de esta heur o stica consiste en mantener, dentro de la JVM, un bitmap que representa el estado en memoria virtual de todas las pginas del heap de un programa a (ver gura 5.14).

seleccin de pginas
prediccin

bytecode (pc,array,pos,caract)
informacin prediccin

predecir filtrar

estado pginas

cdigo bytecode

seleccionadas

Figura 5.14 Utilizacin de la heur o stica que aproxima del estado de la memoria

La JVM marca en el bitmap todas las pginas que son cargadas en memoria, basndose a a en la informacin que ella tiene sobre los accesos del programa (i.e. cada vez que una o instruccin accede a una pgina, la JVM actualiza el bit que representa el estado de esa o a

114

Cap tulo 5

pgina). Esta informacin representa de forma bastante el la carga en memoria de las a o pginas del programa. a El otro aspecto de la memoria virtual, la expulsin al rea de swap, est totalmente o a a controlado por el algoritmo de reemplazo que implementa el SO y que decide en cada momento qu pginas son las ms adecuadas para abandonar la memoria f e a a sica y ser almacenadas en el rea de swap. Este algoritmo se ejecuta de forma transparente a la a JVM, lo que signica que sta no conoce el instante en el que una pgina es expulsada e a y, por lo tanto, debe actualizar su estado en el bitmap. Si bien es cierto que se podr a implementar un simulador del algoritmo de reemplazo en la JVM para que aproximara el momento en el que una pgina abandona la memoria f a sica, el coste de ejecutar este cdigo anular las ventajas de tener esta informacin. Por este motivo, hemos optado o a o por una implementacin menos precisa, consistente en considerar que todas las pginas o a son expulsadas al rea de swap cuando es necesario ejecutar el algoritmo de reemplazo. a En la implementacin que evaluamos en este cap o tulo, se toma la decisin de suponer la o expulsin de todas las pginas en base a un nuevo parmetro que recibe la JVM y que o a a le indica la cantidad de memoria f sica disponible para almacenar los arrays de grandes dimensiones. Es decir, las pginas marcadas como presentes por el bitmap que hemos implementado son a un subconjunto de las pginas que realmente estn cargadas en memoria. Esto signica a a que el uso de este bitmap nunca ser la causa de no cargar anticipadamente una pgina, a a aunque s puede ser que no evite todas las peticiones redundantes. Para completar la seleccin de pginas, es necesario considerar la distancia de prefetch o a adecuada para solicitar aquellas pginas para las que el prefetch tenga opciones de ser a efectivo. El valor adecuado de la distancia viene condicionado por el propio cdigo del o programa y por las condiciones de ejecucin. Por lo tanto, es un valor que se deber o a reajustar en tiempo de ejecucin, para lo cual puede ser necesario utilizar la informacin o o sobre el estado de las pginas. Para la implementacin que evaluamos en este cap a o tulo, la distancia de prefetch es un valor esttico (no cambia durante la ejecucin) y global a o (se aplica el mismo valor para todas las instrucciones), que determinamos experimentalmente y que pasamos como parmetro al inicio de la ejecucin. Hay que decir que hemos a o

Prefetch guiado por la JVM y transparente al SO

115

adoptamos esta simplicacin temporalmente, y que, sobre la versin denitiva de nueso o tra propuesta de prefetch, hemos realizado un estudio sobre el mtodo apropiado para e obtener la distancia y la implementacin de su clculo dinmico (ver seccin 6.5.3 en el o a a o cap tulo 6).

5.4.2

Solicitud de carga as ncrona: prefetcher

En la seccin 5.2 hemos planteado las bases que va a seguir la implementacin de la o o carga anticipada en la estrategia de prefetch transparente al SO. El mecanismo de carga propuesto, aparentemente, se puede implementar de manera muy sencilla. Sin embargo, un anlisis detallado de la interaccin del mecanismo con el propio cdigo del SO, nos ha a o o desvelado que existen detalles en la implementacin del SO que pueden inuir en gran o manera sobre el rendimiento de la carga anticipada. En esta seccin describimos las decisiones que hemos tomado para la implementacin de o o este cdigo y cmo han venido inuidas por la implementacin del cdigo del SO presente o o o o en nuestro entorno de trabajo. Las modicaciones que hemos introducido en la JVM consisten en a adir el ujo de n ejecucin prefetcher que se encarga de hacer efectiva la carga anticipada de las pginas o a seleccionadas por el ujo de la JVM encargado de la ejecucin de los programas. o El cdigo que solicita la carga anticipada es un bucle muy sencillo que consiste en, mieno tras haya solicitudes pendientes, acceder a la direccin objetivo de la solicitud para que, o mediante el mecanismo del fallo de pgina, se provoque la carga anticipada de la pgina a a solicitada (ver gura 5.15). Si en alg n momento no hay peticiones pendientes, entonces u el cdigo de carga debe parar momentneamente su ejecucin, para evitar el consumo o a o innecesario de CPU, y reanudarlo en cuanto haya una nueva solicitud de prefetch. Para obtener las solicitudes de carga que debe realizar, el prefetcher accede al buer compartido con el ujo de ejecucin del programa. Extrae las peticiones del buer siguiendo o una pol tica FIFO, es decir, primero solicita la carga de la peticin ms antigua que ha o a recibido.

116

Cap tulo 5

JVM
seleccin de pginas cdigo bytecode
estado pginas

SO

bytecode (pc,array,pos,caract)
informacin prediccin

prediccin

seleccionadas fallo de pgina prefetcher

Figura 5.15 Mecanismo de carga as ncrona transparente al SO

Si en alg n momento el buer se queda vac es decir, no hay peticiones pendientes, el u o, prefetcher se bloquea sobre un semforo hasta que la JVM, al introducir una peticin a o en el buer y comprobar que el prefetcher est bloqueado, act a sobre el semforo para a u a desbloquearlo. La necesidad de esta operacin de sincronizacin involucra dos llamadas a o o sistema. Sin embargo, los experimentos que hemos realizado demuestran que esta sobrecarga es asumible por la tcnica de prefetch (ver seccin 5.5). e o En cuanto a la situacin complementaria, que se da cuando la JVM necesita depositar o una nueva solicitud de carga y el buer se encuentra lleno, lo ms rpido para el ujo de a a ejecucin del programa es, o bien descartar la peticin que lleva ms tiempo en el buer o o a esperando a ser servida, o bien descartar la nueva que no cabe en el buer. Hemos optado por descartar la peticin ms antigua y hemos decidido sobreescribirla con la nueva. Esta o a decisin la hemos tomado asumiendo que las peticiones que hace ms tiempo que se han o a solicitado son las que tienen menos margen para ser cargadas antes de que el programa las referencie y, por lo tanto, la probabilidad de no ser capaces de cargarlas a tiempo es ms alta que para el caso de las nuevas solicitudes. De todas maneras, consideramos a

Prefetch guiado por la JVM y transparente al SO

117

necesario evaluar este ultimo extremo para poder asegurar que esta opcin es la que o ofrece el mejor rendimiento posible. Adems, es deseable que esta situacin no se de con a o frecuencia, ya que implica la prdida de oportunidades en la carga solapada de memoria. e Sin embargo, se da la circunstancia de que, para los programas que hemos evaluado, hemos observado que el comportamiento habitual es tener una sola peticin pendiente o en el buer. Por lo que todos los parmetros de conguracin del buer (dimensin del a o o buer, orden de extraccin de las peticiones del buer y tratamiento del caso del buer o lleno), no inuyen en el rendimiento de los experimentos que vamos a realizar. Por lo tanto, en la implementacin evaluada en este cap o tulo no hemos profundizado ms en el a anlisis de esta estructura de datos. a

Caracter sticas del ujo de prefetch


El ujo de ejecucin que hemos a adido es un nuevo proceso ligero, que hemos creado o n mediante el interfaz que ofrece el SO de nuestro entorno. Por lo tanto, este nuevo ujo comparte todo el espacio de direcciones con el resto de ujos de la JVM. Esto signica que el prefetcher tiene acceso a todo el heap del programa, algo necesario para que pueda provocar la carga de direcciones usando el mecanismo de fallo de pgina. Adems, esta a a facilidad tambin permite optimizar la gestin del buer de peticiones. e o Implementar el prefetch mediante un proceso ligero tambin tiene repercusiones positivas e en la eciencia de la gestin de procesos implementada por el SO, ya que facilita la o optimizacin del uso de recursos y aumenta el rendimiento de algunas de las operaciones o de gestin. o La alternativa a la implementacin como proceso ligero habr sido la implementacin o a o como un proceso tradicional. En este caso, se tendr que haber usado alguna tcnica de a e memoria compartida entre procesos, para permitir que el prefetcher compartiera con el resto de ujos de la JVM tanto el heap como el buer de peticiones de prefetch. Hay que decir que en la gestin de memoria compartida entre procesos, el SO debe garantizar la o coherencia entre las visiones que ambos procesos tienen de la memoria, lo cual repercute en el tiempo de gestin de la memoria. Hemos evaluado la inuencia que el uso de este o tipo de memoria tiene sobre el rendimiento de los accesos a memoria de un proceso, y

118

Cap tulo 5

hemos comprobado que el tiempo de gestin de un fallo de pgina sobre una zona de o a memoria compartida es considerablemente mayor que el tiempo de gestin involucrado o cuando la zona es de memoria annima no compartida. Es ms, los accesos de escritura, o a aunque no impliquen un fallo de pgina, tambin tienen un coste mayor cuando se hacen a e sobre una zona de memoria compartida. As hemos observado que ejecutar un programa , que escribe sobre una zona de memoria compartida tiene un rendimiento 3,5 veces peor que el mismo programa accediendo a una zona de memoria annima. o Aunque todo parece indicar que la opcin de implementar el prefetcher como un proceo so tradicional se podr haber descartado sin ning n tipo de evaluacin previa, hemos a u o querido realizar esta evaluacin porque durante el desarrollo de este trabajo hemos obo servado cmo detalles de implementacin del SO pueden ser los responsables de que los o o resultados tericos esperados no se correspondan con la ejecucin real. En particular, en o o versiones anteriores del kernel de Linux, que hemos utilizado durante las fases iniciales de este trabajo (versiones 2.2.12 y 2.4.2), hemos observado un detalle de implementacin o de la rutina de tratamiento de fallo de pgina que podr perjudicar el rendimiento del a a prefetcher implementado como proceso ligero. En esas versiones, en el tratamiento de la excepcin del fallo de pgina se utilizaban locks de granularidad muy gruesa, para garano a tizar la consistencia en las estructuras de datos del sistema y evitar posibles condiciones de carrera. Este mtodo de sincronizacin era tan radical que no permit el tratamiento e o a simultneo de fallos de pgina de procesos ligeros que pertenecieran a la misma tarea. Por a a lo tanto, si mientras se estaba resolviendo un fallo de pgina, el kernel recib una excepa a cin debido a un acceso al mismo espacio de direcciones, el ujo que hubiera provocado el o segundo fallo de pgina se bloqueaba al inicio de la rutina de gestin de la excepcin. Esto a o o era as aunque se trataran de fallos de pgina totalmente independientes cuya resolucin a o no implicara a las mismas estructuras del sistema y, por lo tanto, no fuera posible una condicin de carrera que arriesgara la integridad de los datos del sistema. o Este detalle de implementacin interna del SO podr perjudicar el rendimiento de la o a estrategia de prefetch si se implementaba el prefetcher como un proceso ligero. Ya que los fallos de pgina provocados por el prefetcher, con el objetivo de solapar la carga de a memoria con el clculo del programa, podr ralentizar la resolucin de otros fallos de a an o pgina provocados por los ujos de la JVM y anular las ventajas de la carga anticipada. a

Prefetch guiado por la JVM y transparente al SO

119

En las siguientes versiones del kernel de Linux, el mecanismo de proteccin para evitar o las condiciones de carrera en la gestin de los fallos de pgina se ha renado, con lo que o a el problema que podr aparecer al usar un proceso ligero ha desaparecido haciendo que a sta sea la opcin ms eciente para la implementacin del prefetcher. Sin embargo, este e o a o ejemplo de la evolucin del cdigo del kernel y de su inuencia sobre el rendimiento del o o prefetch es interesante para mostrar la sensibilidad de la estrategia de prefetch al ser implementada de forma transparente al SO. Otras caracter sticas del ujo de prefetch que hay que tener en cuenta son las relacionadas con la pol tica de planicacin de ujos del SO. Para que el prefetch sea ecaz, es o importante que el SO asigne la CPU al prefetcher siempre que ste tenga una peticin e o pendiente, para que provoque su carga con la antelacin adecuada. Una vez solicitada la o carga el prefetcher se bloquear hasta que se complete el fallo de pgina que ha provocado, a a con lo que la CPU quedar libre para que el SO se la pueda asignar al resto de ujos del a sistema. Para lograr este efecto, hemos utilizado una funcionalidad que ofrece Linux y que permite dar prioridad al prefetcher en el uso de la CPU. Esta funcionalidad es la que sirve para asignar a un ujo la categor de ujo de tiempo real, convirtindolo en el candidato a e a ocupar la CPU siempre que est preparado para la ejecucin. a o Hemos comparado la inuencia de este cambio en la pol tica de planicacin del prefetcher o y la aplicacin que hemos evaluado mejora su rendimiento hasta un 2 % con respecto a o planicar al prefetcher mediante la pol tica de planicacin que usa Linux por defecto. o Este bajo porcentaje de mejora se debe a que la aplicacin que hemos utilizado tiene o un bajo porcentaje de clculo, lo que signica que se bloquea con mucha frecuencia, de a manera que, aunque se use la pol tica de planicacin por defecto, el prefetcher tiene o muchas opciones de ocupar la CPU en cuanto est preparado para ejecutarse. Por lo a tanto, en una aplicacin con mayor tiempo de clculo se espera que la inuencia del o a cambio de la pol tica de planicacin sea mayor. o

Inuencia de la gestin de memoria del SO o


Al a adir el prefetch de memoria al entorno de ejecucin, estamos introduciendo una n o nueva tarea en la gestin de memoria que, inevitablemente, interacciona con el resto de o

120

Cap tulo 5

tareas de gestin de memoria del entorno. Este efecto es ms acusado al hacer que la o a estrategia de prefetch sea transparente al SO. En este caso, el SO puede tomar decisiones genricas que perjudican el rendimiento del prefetcher y que podr evitar si, por ejemplo, e a fuera capaz de distinguir entre las pginas solicitadas por pura carga bajo demanda y las a pginas solicitadas por el prefetcher. a En la seccin anterior ya hemos visto un ejemplo de como la implementacin del mecao o nismo de fallo de pgina puede inuir en el rendimiento del prefetcher. Pero existen ms a a decisiones en la gestin de memoria de Linux que pueden perjudicar el rendimiento de o nuestra propuesta. Como ya hemos dicho, Linux implementa una estrategia de prefetch muy simple que intenta favorecer a las aplicaciones que usan un patrn de accesos secuencial (ver seccin o o 2.2 en el cap tulo 2). Esta estrategia consiste en, para cada fallo de pgina, adems de a a cargar la pgina que ha provocado la excepcin, cargar tambin las siguientes pginas a o e a consecutivas. Por lo tanto, Linux aplicar este prefetch tambin para las pginas cargadas a e a anticipadamente por nuestra estrategia de prefetch. En el mejor de los casos, si el programa que se est ejecutando sigue un patrn de accesos secuencial, la aplicacin simultnea a o o a del prefetch de Linux y de nuestra estrategia de prefetch, resulta redundante. Pero en general, para las aplicaciones que siguen patrones de acceso no secuenciales, el prefetch de Linux puede perjudicar el rendimiento de nuestra estrategia de prefetch, ya que para cada pgina que solicitemos con antelacin, Linux cargar otra serie de pginas, que a n siendo a o a a u innecesarias para el programa, pueden aumentar la presin sobre el sistema de gestin de o o memoria. Afortunadamente, Linux permite que su estrategia de prefetch se desactive desde el nivel de usuario, por lo que hemos adoptado esta posibilidad para las ejecuciones sobre nuestro entorno modicado con prefetch en el nivel de usuario. El otro aspecto de la gestin de memoria que interact a con la estrategia de prefetch es el o u reemplazo de memoria. Esta interaccin se puede manifestar de dos maneras diferentes: o primero, por la propia ejecucin del cdigo de reemplazo y, segundo, por las pginas que o o a selecciona para ser expulsadas al rea de swap. En este punto hay que comentar, una a

Prefetch guiado por la JVM y transparente al SO

121

vez ms, que hemos observado grandes diferencias en el efecto que esta interaccin tiene a o sobre rendimiento del prefetch, dependiendo de la versin de kernel de Linux presente en o el entorno de ejecucin. De esta manera, una evaluacin de nuestra estrategia sobre una o o versin anterior de kernel (versin 2.4.2), nos demostr que, comparado con los resultados o o o obtenidos sobre la versin de kernel 2.4.18, las interferencias con el reemplazo de memoo ria penalizaban hasta cuatro veces su rendimiento. Hay que decir que, incluso con esta mala interaccin con el algoritmo de reemplazo, nuestra estrategia de prefetch tambin o e consegu mejorar el rendimiento de los programas sobre la versin 2.4.2. a o

5.5

EVALUACION DEL PREFETCH A NIVEL DE USUARIO

En esta seccin presentamos la evaluacin de la implementacin nal que hemos propuesto o o o para la estrategia de prefetch transparente al SO. Recordemos que la versin de la JVM que hemos modicado con la estrategia de prefetch o es la JVM HotSpot, versin 1.3.1, que Sun distribuye como parte del entorno de desarrollo o del paquete Java 2 SDK Standard Edition para Linux. Adems el kernel de Linux sobre a el que ejecutamos los experimentos es el 2.4.18, el mismo que hemos utilizado durante la implementacin de esta estrategia. o La plataforma f sica sobre la que hemos ejecutado estos experimentos es un PC con un procesador Pentium III a 500 Mhz y 128Mb de memoria f sica.

5.5.1

Metodolog para los experimentos a

Para evaluar la efectividad de nuestra estrategia hemos evaluado los programas de prueba tanto en el entorno original de ejecucin como en el entorno modicado con nuestra o estrategia de prefetch. En el caso del entorno original, hemos analizado el rendimiento obtenido con el prefetch de Linux activado (comportamiento por defecto) y el obtenido al desactivar esa estrategia simple de prefetch. Para la evaluacin de nuestra propuesta o

122

Cap tulo 5

de prefetch, como ya hemos comentado en la seccin 5.15, hemos optado por desactivar o siempre el prefetch de Linux. La evaluacin ha consistido en contar los fallos de pgina provocados por la ejecucin o a o de los programas, separando los fallos de pgina provocados por el cdigo del programa a o de aquellos provocados por el prefetcher ya que, stos ultimos son los susceptibles de ser e resueltos en paralelo con la ejecucin del programa. Adems, tambin contamos de forma o a e separada aquellos fallos de pgina provocados por el acceso a direcciones que ya estn a a en proceso de carga. Esta segunda clasicacin tambin nos sirve para evaluar la ecacia o e del prefetch ya que estos fallos de pgina se deben a pginas que el prefetcher no ha sido a a capaz de cargar a tiempo. Adems, es importante tenerlo en cuenta a la hora de analizar a el tiempo de ejecucin ya que, habitualmente, el tiempo involucrado en resolver uno de o estos fallos de pgina es menor que el necesario para resolver un fallo de pgina completo. a a Tambin evaluamos el tiempo de ejecucin de los programas, distinguiendo el porcentaje e o de este tiempo que ha sido necesario para resolver cada uno de los tipos de fallos de pgina. Esto es necesario para asegurar que, en los casos en los que el prefetcher es capaz a de evitar los fallos de pgina de los programas, se obtiene la correspondiente reduccin a o en el tiempo de ejecucin. o Para efectuar estas medidas, utilizamos el mismo mecanismo, basado en los gestores de dispositivos de Linux, que hemos descrito en el cap tulo 3, pero adaptando el cdigo o a las necesidades de la nueva clasicacin. Para esta nueva clasicacin, simplemente o o necesitamos que el kernel considere dos grupos de contadores: los asociados al prefetcher y los asociados al ujo que ejecuta el cdigo del programa. Para ello, hemos introducido o una nueva variable de conguracin que la JVM inicializa con los identicadores de proceso o de los ujos que interesa distinguir.

5.5.2

Programas de prueba

Para efectuar esta evaluacin hemos seleccionado como programa de prueba el cdigo de o o la multiplicacin de matrices. El motivo de esta seleccin es que se trata de un kernel o o muy utilizado en las aplicaciones de clculo cient a co y, adems, se trata de un algoritmo a

Prefetch guiado por la JVM y transparente al SO

123

sencillo y muy controlado, que facilita el anlisis de los resultados. Hay que decir que a esta facilidad para el anlisis ha sido especialmente importante durante toda la fase de a desarrollo de la estrategia. Durante esta fase, el controlar perfectamente el cdigo del o programa de prueba, nos ha permitido entender aquellos puntos del cdigo a adido a la o n JVM que eran cr ticos para poder obtener un cdigo eciente. Y lo que es ms importante, o a nos ha facilitado la tarea de entender el comportamiento de las tareas de gestin de Linux o y su interaccin con nuestro cdigo, para as poder llegar a una implementacin que ofrece o o o un buen rendimiento para la estrategia de prefetch. Este programa lo hemos ejecutado con diferentes tama os para las matrices multiplicadas. n El objetivo es evaluar el comportamiento de nuestra estrategia bajo diferentes condiciones de presin para el sistema de memoria. A continuacin describimos brevemente los o o tama os seleccionados y la tabla 5.2 los resume. n

Matrices pequenas: el tama o de estas matrices se ha seleccionado para que el n sistema de memoria fuera capaz de albergar a las tres matrices durante todo el algoritmo de multiplicacin. Es decir, el programa no hace uso de la memoria virtual y, o por tanto, el prefetch de memoria no puede mejorar su rendimiento Matrices grandes: el tama o de estas matrices es tal que hace necesario el uso de la n memoria virtual y, por lo tanto, la estrategia de prefetch podr beneciarle, y adems a a permite guardar en memoria dos de los working sets que utiliza la multiplicacin, lo o que signica que el algoritmo de seleccin de pginas puede optimizar el cdigo de o a o seleccin. o Matrices extra-grandes: en este experimento se aumenta la presin sobre el o sistema de memoria. El tama o de los working sets del programa son demasiado n grandes como para mantener dos simultneamente en memoria, con lo que el algoritmo a de seleccin de pginas no puede aplicar la optimizacin de simplicar el patrn de o a o o accesos.

124

Cap tulo 5

Benchmark Matrices pequenas Matrices grandes Matrices extra-grandes

Matriz A (doubles) 500x500 (1,9Mb) 1024x4096 (32Mb) 128x28672 (28Mb)

Matriz B (doubles) 500x500 (1,9Mb) 4096x4096 (128Mb) 28762x2048 (448Mb)

Tabla 5.2 Tama os de las matrices de entrada para la multiplicacin (AxB) n o

5.5.3

Rendimiento del prefetch a nivel de usuario

En la gura 5.16 mostramos los resultados obtenidos en la evaluacin del prefetch sobre el o benchmark que utiliza la matriz que se mantiene por completo en memoria f sica durante toda la ejecucin. Es decir, la multiplicacin de matrices se completa sin provocar ning n o o u fallo de pgina. La gura 5.16.a mostramos el tiempo de ejecucin de este programa en el a o entorno original de ejecucin, tanto con el prefetch de kernel activado (en la gura, JVM o original (prefetch kernel)) como con esta estrategia desactivada (en la gura, JVM original (sin prefetch kernel)), separando el tiempo de fallo de pgina del resto del tiempo de a ejecucin del programa. En esta gura se puede observar como, efectivamente, el tiempo o de clculo ocupa el 100 % del tiempo de ejecucin del programa y, adems, dado que a o a se ejecuta sin provocar fallos de pgina, el prefetch de kernel no tiene ning n efecto a u sobre su ejecucin y el rendimiento del programa en los dos escenarios es idntico. Por el o e mismo motivo, nuestra estrategia de prefetch tampoco puede beneciar el rendimiento del programa. Es ms, en esta implementacin no hemos incluido todav la caracter a o a stica de desactivar el prefetch cuando las condiciones de ejecucin no lo hacen necesario, por lo que o la ejecucin de este programa nos sirve para evaluar la sobrecarga a adida por nuestro o n cdigo de prediccin. En la gura 5.16.b comparamos la ejecucin en el entorno original o o o con su comportamiento por defecto (i.e. con el prefetch de Linux activado, en la gura 5.16.b, JVM original (prefetch kernel)) con el comportamiento del entorno de ejecucin o modicado con nuestra propuesta de prefetch (en la gura 5.16.b, JVM con prefetch). Vemos que en la ejecucin sobre el entorno que hemos modicado igualmente el tiempo o de clculo representa el 100 % del tiempo total de ejecucin. Por otro lado, el incremento a o del tiempo total con respecto a la ejecucin en el entorno original representa un 12 %. o Hay que destacar que una versin denitiva de la estrategia de prefetch debe detectar si o un proceso no est utilizando el mecanismo de memoria virtual y entonces desactivarse, a con lo cual esta sobrecarga slo debe tenerse en cuenta para las situaciones en las que el o prefetch es benecioso. En la implementacin que presentamos en este cap o tulo no hemos

Prefetch guiado por la JVM y transparente al SO

125

incorporado esta desactivacin ya que su objetivo es evaluar si la estrategia de prefetch o transparente al SO puede mejorar el rendimiento de los programas que requieren el uso de memoria virtual, por lo que hemos pospuesto la implementacin de este detalle hasta o tener el dise o denitivo de la estrategia. n Este benchmark, adems de evaluar la sobrecarga del cdigo de prediccin, nos ha permia o o tido analizar los benecios de las optimizaciones que hemos implementado en la tarea de seleccin de pginas. Las instrucciones de la multiplicacin de matrices siguen un patrn o a o o de accesos repetitivo sobre cada uno de sus working sets, de manera que se puede aplicar la simplicacin que hemos descrito en la seccin 5.1.3 sobre el patrn aplicado en la o o o seleccin de pginas. o a Hemos observado que el rendimiento de este benchmark, aplicando estrictamente el patrn o de accesos en lugar de aplicar el patrn simplicado, es ms de 6 veces peor que el o a rendimiento de la estrategia que utiliza la seleccin optimizada. Si tampoco aplicamos la o optimizacin de evitar las predicciones consecutivas sobre la misma pgina, entonces el o a tiempo de ejecucin se multiplica por otro factor de 3. o Este alto incremento el tiempo de ejecucin demuestra la importancia de intentar evitar o la ejecucin de cdigo de prediccin que genera selecciones de pginas redundantes, y o o o a justica las simplicaciones implementadas en el algoritmo de seleccin. o En las guras 5.17 y 5.18 mostramos los resultados de la ejecucin del benchmark con el o siguiente conjunto de datos. Estos datos tienen la caracter stica de no caber en memoria, y por lo tanto, una tcnica de prefetch capaz de captar su patrn de accesos puede mejorar e o su rendimiento. Adems, las dimensiones de las matrices permiten mantener en memoria a al mismo tiempo varios working sets de las instrucciones, de manera que el algoritmo de seleccin de pginas, a medida que se referencian por primera vez las pginas de un o a a working set, puede ir solicitando la carga de las pginas del siguiente working set. a En la gura 5.17 podemos ver el tiempo de ejecucin del programa sobre el entorno o original de ejecucin. Podemos observar que para la ejecucin con el comportamiento o o por defecto (JVM original (prefetch kernel)), el porcentaje de tiempo dedicado a resolver

126

Cap tulo 5

Matrices: A(500x500) * B(500x500)


125 100 75 50 25 0 JVM original (prefetch kernel) JVM original (sin prefetch kernel)

Tiempo (segs.)

Tiempo clculo Tiempo fallo de pgina

(a) Comportamiento benchmark

Matrices: A(500x500) * B(500x500)


125 100 75 Tiempo ejecucin 50 25 0 JVM original (prefetch kernel) JVM con prefetch

Tiempo (segs.)

(b) Tiempo ejecucin

Figura 5.16 Multiplicacion de matrices pequenas

fallos de pgina alcanza el 52 % del tiempo total de ejecucin. En el caso de la ejecucin a o o desactivando el prefetch de kernel JVM original (sin prefetch kernel) este porcentaje se incrementa hasta el 84 %. Este porcentaje hay que tenerlo en cuenta a la hora de evaluar los benecios obtenidos por nuestra tcnica, ya que la ecacia del prefetch se basa en e el solapamiento del tiempo de carga con el tiempo de clculo, por lo tanto, los posibles a benecios vienen limitados por el tiempo de CPU consumido durante la ejecucin de los o programas.

Prefetch guiado por la JVM y transparente al SO

127

Matrices: A(1024x4096) * B(4096x4096)


120000
Tiempo (segs.)

90000
Tiempo fallo de pgina

60000 30000 0 JVM original JVM original (sin (prefetch kernel) prefetch kernel)

Tiempo clculo

Figura 5.17 Comportamiento de la Multiplicacion de matrices grandes

En la gura 5.18.a comparamos el tiempo de ejecucin sobre el entorno original, tanto o usando la conguracin por defecto (JVM original (prefetch kernel)) como desactivando el o prefetch de kernel (JVM original (sin prefetch kernel), y sobre el entorno modicado con nuestra propuesta (JVM con prefetch). El primer aspecto a destacar es que la ejecucin del o prefetch de Linux est perjudicando al rendimiento de este programa, y que, simplemente a desactivando esta pol tica ya se consigue una mejora en el rendimiento de los programas. Sin embargo, si ejecutamos el programa con nuestra estrategia de prefetch la mejora aumenta hasta un 43 %, comparado con la ejecucin sobre el comportamiento por defecto o del entorno original, y hasta un 30 % si se compara con la ejecucin sobre el entorno o original con el prefetch de kernel desactivado. En la gura 5.18.b mostramos los fallos de pgina provocados por el programa en los tres a entornos de ejecucin que estamos considerando. Hemos separado los fallos de pgina en o a funcin de su tipo: fallos de pgina que no implican acceso a disco y que incluyen los que o a se provocan por el acceso a direcciones que ya estn en proceso de carga (fp soft), o fallos a de pgina para los que el tiempo de espera incluye la carga completa de la pgina (fp a a hard). Adems, para la ejecucin sobre el entorno modicado con nuestra propuesta de a o prefetch, distinguimos entre los fallos de pgina provocados por el cdigo del programa a o (JVM) y los provocados por el prefetcher (prefetcher).

128

Cap tulo 5

Matrices: A(1024x4096) * B(4096x4096)


120000

Tiempo (segs.)

90000 60000 30000 0 JVM original (prefetch kernel) JVM original (sin prefetch kernel) JVM con prefetch Tiempo ejecucin

(a) Tiempo Ejecucin

Matrices: A(1024x4096) * B(4096x4096)


Nm. fallos pgina
32000000 24000000 16000000 8000000 0 JVM original (prefetch kernel) JVM original (sin prefetch kernel) JVM con prefetch JVM fp hard JVM fp soft prefetcher fp hard prefetcher fp soft

(b) Fallos de pgina

Figura 5.18 Resultados de la Multiplicacion de matrices grandes

Podemos ver cmo en el entorno original de Linux, el prefetch de kernel no consigue o eliminar los fallos de pgina del programa. Esto es debido a que su algoritmo de prediccin a o no representa los accesos a la matriz recorrida por columnas. Hay que decir que, por un efecto lateral, alguna de las pginas precargadas son utilizadas por el programa. Pero en a este caso incluso el rendimiento no es bueno, ya que el programa las necesita antes de que la carga se complete, provocando un fallo de pgina de los que hemos categorizado como a soft. Adems, la carga de pginas no necesarias incrementa el tiempo de ejecucin del a a o programa ya que provoca que el algoritmo de reemplazo se tenga que ejecutar con mayor frecuencia para devolver al rea de swap las pginas cargadas sin necesidad. a a

Prefetch guiado por la JVM y transparente al SO

129

En el caso de la ejecucin sobre el entorno modicado con nuestra estrategia de prefetch, o podemos ver que el prefetcher no es capaz de evitar todos los fallos de pgina del programa. a Hay que destacar que los fallos de pgina del programa son debidos a que el prefetcher a no carga a tiempo las pginas (son fallos de pgina soft). Sin embargo, la importante a a reduccin en el tiempo de ejecucin indica que el tiempo de resolucin de estos fallos es o o o muy bajo. Adems, debido al poco tiempo de clculo consumido durante la ejecucin de a a o este programa, no es posible obtener un mayor grado de solapamiento entre las lecturas de disco y el clculo del programa. Es decir, nuestra estrategia de prefetch se acerca a a la mxima mejora terica del rendimiento que se puede obtener utilizando prefetch de a o pginas. a El tercer caso que hemos considerado es aquel en el que la dimensin de los datos manio pulados solo permite mantener en memoria f sica un working set de cada instruccin de o acceso a una matriz fuente. Esto signica que no es posible aplicar la simplicacin en el o patrn de accesos de las instrucciones. En esta situacin el prefetcher slo puede solicitar o o o la carga de las pginas del siguiente working set de una instruccin cuando detecta que el a o working set actual ya no es necesario y, por lo tanto, puede ser expulsado al rea de swap a para liberar el espacio en memoria f sica y permitir que sea ocupado por el siguiente. Sin embargo, el espacio de tiempo que transcurre desde que el working set actual deja de ser necesario hasta que se inician los accesos al siguiente working set es demasiado peque o. n En las gura 5.19 y 5.20 mostramos los resultados de calcular slo una la de la matriz o resultado, porque estos resultados son representativos del comportamiento de toda la ejecucin. En la gura 5.19 aparece el tiempo de ejecucin de este benchmark, distinguiendo o o entre tiempo de fallo de pgina y resto del tiempo de ejecucin. Slo mostramos los rea o o sultados para la ejecucin sobre el entorno original con el prefetch de kernel desactivado. o El motivo es porque despus de 24 horas en ejecucin sobre el entorno original con el pree o fetch de kernel activado no se hab completado el clculo de la la resultado. Esta gran a a prdida de rendimiento provocada por el prefetch de kernel se debe a que la penalizacin e o debida a la carga de pginas innecesarias se incrementa a medida que lo hace la presin a o sobre el sistema de memoria.

130

Cap tulo 5

Matrices: A(128x28672) * B(28672x2048)


1500 1200

Tiempo (segs.)

900 600 300 0 JVM original (sin prefetch kernel)

Tiempo fallo de pgina Tiempo clculo

Figura 5.19 Comportamiento de la Multiplicacion de matrices extra-grandes

En cuanto a la ejecucin sobre el entorno modicado con nuestra propuesta, en la gura o 5.20.b podemos ver que el prefetcher no es capaz de evitar ning n fallo de pgina del u a programa, aunque todos ellos pasan a ser fallos de pgina soft. Esto es debido al poco a tiempo que pasa entre el momento en el que se puede iniciar la solicitud y el momento en el que las pginas son accedidas por el programa. Sin embargo en la gura 5.20.a a podemos ver que, aunque el escenario que representa este benchmark no es favorable para que nuestra propuesta sea ecaz, la ejecucin sobre nuestro entorno tiene el mismo o rendimiento que la ejecucin sobre el entorno sin prefetch. o

5.5.4

Conclusiones de la evaluacin o

En esta seccin hemos presentado los resultados de evaluar tres tipos de benchmarks sobre o el entorno modicado con nuestra propuesta de prefetch transparente al SO. El primer benchmark se ejecuta sin provocar fallos de pgina y, por lo tanto, la ejecucin a o del cdigo de prefetch simplemente selecciona pginas que, al comprobar que ya estn o a a cargadas en memoria, no solicita su carga. Por lo tanto nos ha servido para evaluar la sobrecarga de la ejecucin de este cdigo y cmo se consigue reducir al aplicar las o o o optimizaciones en el algoritmo de seleccin que hemos descrito en 5.1.3. Esta sobrecarga, o

Prefetch guiado por la JVM y transparente al SO

131

Matrices: A(128x28672) * B(28672x2048)


1500

Tiempo (segs.)

1200 900 600 300 0 JVM original (sin prefetch kernel) JVM con prefetch

Tiempo ejecucin

(a) Tiempo Ejecucin

Matrices: A(128x28672) * B(28672x2048)


Nm. fallos pgina
150000 120000 90000 60000 30000 0 JVM original (sin prefetch kernel) JVM con prefetch JVM fp hard JVM fp soft prefetcher fp hard prefetcher fp soft

(b) Fallos de pgina

Figura 5.20 Resultados de la Multiplicacion de matrices extra-grandes

como hemos visto en el anlisis del siguiente benchmark, es completamente asumible para a las aplicaciones penalizadas por el uso de la memoria virtual, ya que las ganancias de utilizar prefetch para este tipo de aplicaciones superan con creces la penalizacin de la o ejecucin del cdigo de prediccin. Adems, hay que destacar que la desactivacin del o o o a o prefetch para aquellas aplicaciones que no usan la memoria virtual es uno de los detalles pendientes de renar en la versin denitiva de la implementacin de nuestra estrategia. o o El segundo benchmark representa al conjunto de aplicaciones que hacen un uso intensivo de la memoria virtual y que son candidatas a ser mejoradas mediante un prefetch efec-

132

Cap tulo 5

tivo de memoria. Para este benchmark hemos demostrado que el entorno de ejecucin o modicado con nuestro prefetch mejora un 43 % el rendimiento obtenido sobre el entorno original. Y el tercer benchmark representa al conjunto de aplicaciones que elevan la presin sobre o el sistema de memoria a tal punto que es imposible cargar con anticipacin las siguientes o pginas referenciadas por las instrucciones, ya que el tama o de su working set impide a n ocupar la memoria f sica con ellas. En este caso, aunque las condiciones de ejecucin deo saconsejan la utilizacin del prefetch, nuestra tcnica iguala el rendimiento que se obtiene o e en el entorno original de ejecucin con el prefetch de Linux desactivado, y supera, con o creces, el rendimiento obtenido sobre el entorno de ejecucin original con la conguracin o o por defecto, que se ve muy penalizado por el uso del prefetch que implementa Linux. Por lo tanto, podemos armar que nuestra propuesta de prefetch transparente al SO consigue ofrecer a las aplicaciones el mejor rendimiento terico que las caracter o sticas de sus accesos a memoria pueden esperar.

5.6

PREFETCH TRANSPARENTE AL SO: SOLO UN PASO EN EL CAMINO

En este cap tulo hemos demostrado que es posible implementar una tcnica de prefetch e que, utilizando el conocimiento que tiene la JVM sobre el comportamiento de los programas, se ejecute de forma transparente al SO y mejore substancialmente el rendimiento de los programas que hacen un uso intensivo de la memoria virtual. Hemos dotado al entorno de ejecucin de Java de una tcnica de prefetch que cumple los o e requerimientos necesarios para que el prefetch sea ecaz ya que:

Implementa una seleccin precisa, como parte del tratamiento de los bytecodes, aproo vechando la informacin que tiene la JVM, en tiempo de ejecucin, sobre todos los o o accesos a memoria de los programas y sus caracter sticas.

Prefetch guiado por la JVM y transparente al SO

133

Respeta la portabilidad de los programas, ya que las modicaciones forman parte de la JVM, y cualquier programa ejecutado sobre ella se puede beneciar de esta tcnica. e Es transparente al programador y al usuario, ya que no es necesario ni modicar de ninguna manera el cdigo del programa ni recompilarlo. o Respeta la abilidad de sistema, ya que la operacin de carga la efect a el SO, como o u respuesta a la solicitud que hace la JVM usando el interfaz de la excepcin del fallo o de pgina. a

El objetivo de conseguir una tcnica totalmente transparente era favorecer la portabilidad e del mecanismo en s evitando tener que adaptarlo en funcin del SO presente en el sistema. , o Sin embargo, el desarrollo de este prototipo nos ha demostrado que esta tcnica es muy e sensible al resto del entorno de ejecucin. Por un lado, hay que tener en cuenta que el o prefetch es una tarea con importantes restricciones de tiempo: para que sea ecaz, la lectura de disco de la pgina seleccionada debe nalizar antes de que el programa la a acceda y, adems, si esto no es posible, puede ser preferible descartar esa lectura para a no penalizar al resto de accesos ni de peticiones de prefetch. Por otro lado, su ejecucin o est interaccionando con el cdigo del SO encargado del resto de decisiones de gestin de a o o memoria del programa, con lo cual es necesario que las decisiones de ambos niveles de gestin de memoria no se intereran. Pero, en esta estrategia, el SO no es consciente de las o tareas ejecutadas por el prefetcher, por lo que trata a las pginas de prefetch como al resto a de pginas cargadas bajo demanda y no hace ninguna comprobacin especial durante la a o ejecucin de su propio cdigo de gestin. o o o Por este motivo, durante la implementacin del prototipo hemos tenido que analizar, paso o a paso, la interaccin de cada una de nuestras decisiones de implementacin con el cdigo o o o del SO utilizado en nuestra plataforma de desarrollo. Es ms, hemos comprobado que a esta interaccin era diferente para diferentes versiones del kernel de Linux, y era necesario o adaptar el cdigo de prefetch de acuerdo a la nueva implementacin del kernel. o o Esto signica que el cdigo de la estrategia de prefetch a nivel de usuario, no slo depende o o del interfaz del SO como cualquier programa sino que, adems, depende tambin de la a e implementacin del SO. Por lo que, para obtener una estrategia eciente, es necesario o

134

Cap tulo 5

implementar un cdigo espec o co para la versin de SO utilizada. Es ms, un cambio en o a esta versin implica analizar de nuevo la ecacia del mecanismo de prefetch para, en caso o necesario, reajustar las decisiones a la nueva implementacin del SO. o Si se asume que la ecacia del prefetch depende de la implementacin del SO y que, por o lo tanto, no se garantiza la portabilidad de la estrategia, el siguiente paso consiste en analizar las posibles ventajas de involucrar al SO en la estrategia de prefetch guiada por la JVM, obteniendo una estrategia de prefetch basada en la cooperacin entre el SO y la o JVM. En el siguiente cap tulo presentamos este nuevo paso en la estrategia de prefetch.

6
PREFETCH COOPERATIVO ENTRE LA JVM Y EL SO

En este cap tulo presentamos el dise o y la implementacin de la estrategia de prefetch n o basada en la cooperacin entre el SO y la JVM. o En el cap tulo anterior hemos visto que es posible implementar una estrategia de prefetch transparente al SO, usando el conocimiento que tiene la JVM sobre el comportamiento del programa y substituyendo la informacin necesaria sobre las condiciones de ejecucin por o o el uso de heur sticas que aproximan esta informacin. Sin embargo, aunque las decisiones o de prefetch son transparentes al SO, su participacin en la carga es inevitable si se quiere o garantizar la abilidad del sistema. Para conseguir esta participacin, manteniendo el o prefetch transparente al SO, es necesario utilizar mecanismos ya existentes dentro del SO para otros propsitos, lo cual complica el cdigo de prefetch y lo hace sumamente sensible o o a cambios en la versin de kernel instalada en la plataforma de ejecucin. Es decir, la o o portabilidad del mecanismo, unica ventaja de su transparencia al sistema, no se puede garantizar. En este cap tulo proponemos una estrategia en la que el SO es consciente de las operaciones de prefetch que la JVM solicita, y colabora activamente en las decisiones asociadas. El mecanismo resultante de esta colaboracin es estable, eciente y no necesita el uso de o heur sticas para poder tomar las decisiones de prefetch. Adems, su implementacin es a o simple y sin los efectos laterales que sufre la estrategia transparente al SO. La gura 6.1 reeja la participacin que tienen tanto el SO como la JVM en la implemeno tacin del prefetch. En la tarea de seleccin de pginas, la JVM aporta su conocimiento o o a 135

136

Cap tulo 6

sobre el comportamiento del programa para predecir los prximos accesos a memoria, o y el SO aporta su conocimiento sobre el estado de la mquina para que la JVM pueda a optimizar la seleccin de pginas y decidir la distancia de prefetch adecuada. En cuanto a o a la carga anticipada, la JVM solicita al SO que inicie la carga as ncrona de las pginas que a ha seleccionado, aunque ste tiene la decisin nal sobre la conveniencia o no, de acuerdo e o a las condiciones de ejecucin, de completar cada operacin de prefetch. o o

prefetch

prediccin JVM carga SO

Figura 6.1 Cooperacin entre JVM y SO para la estrategia de prefetch o

En la seccin 6.1 y en la seccin 6.2 describimos en detalle estas dos tareas de la estrategia o o de prefetch (seleccin de pginas y carga as o a ncrona) y en la seccin 6.3 describimos el o interfaz que hemos a adido al SO para permitir la cooperacin entre la JVM y el SO en n o las decisiones de prefetch. Despus de estas secciones mostramos una visin general del e o funcionamiento de la estrategia de prefetch cooperativo (seccin 6.4), y presentamos sus o detalles de implementacin, tanto los relacionados con cdigo del SO como los relacionados o o con cdigo de la JVM (seccin 6.5). Para nalizar el cap o o tulo, en la seccin 6.6 presentamos o los experimentos que demuestran la efectividad de esta estrategia y en la seccin 6.7 o presentamos las conclusiones que hemos extra del desarrollo y evaluacin del prefetch do o cooperativo.

Prefetch cooperativo entre la JVM y el SO

137

6.1

SELECCION DE PAGINAS DE PREFETCH

En esta seccin presentamos qu aspectos de la tarea de seleccin de pginas de prefetch o e o a se deben modicar para aprovechar la posible participacin del SO dentro de la estrategia o de prefetch. Uno de los puntos importantes dentro de la tarea de seleccin es la prediccin precisa o o de los accesos futuros de las instrucciones. En esta prediccin no inuye el estado del o sistema, ya que slo depende del comportamiento del programa y, por lo tanto, no es o necesaria la participacin del SO. Esto ha quedado patente en los resultados que hemos o mostrado en el cap tulo anterior y en la alta tasa de aciertos que hemos obtenido con la prediccin transparente al SO (ver seccin 5.1.1 del cap o o tulo 5). Por lo tanto, dentro del prefetch cooperativo, hemos conservado la estrategia de prediccin de pginas utilizada o a como parte del prefetch transparente al SO (ver seccin 5.1 en el cap o tulo 5). Sin embargo, hay otros aspectos relacionados con la seleccin de pginas de prefetch que o a se pueden beneciar si el SO participa en la estrategia de prefetch. Un aspecto de la seleccin de pginas que se puede mejorar consiste en eliminar las o a heur sticas que necesitaba la estrategia de prefetch transparente al SO para aproximar la informacin sobre el estado de las pginas del proceso (si estaban presentes en memoria o a f sica o si, por el contrario se encontraban en el rea de swap). Hay que destacar que, a aunque la heur stica utilizada ha demostrado un buen comportamiento en los experimentos que hemos ejecutado, no se puede garantizar que esto sea as para otros benchmarks o entornos de ejecucin. o En la estrategia de prefetch basada en la cooperacin, hemos modicado el SO para que o exporte esta informacin al nivel de usuario. As la JVM de una manera eciente, puede o , consultar esta informacin y utilizarla para optimizar el algoritmo de seleccin y para o o evitar la peticin de carga de pginas ya presentes en memoria f o a sica. Otra modicacin que hemos introducido en la seleccin de pginas se reere a la distancia o o a de prefetch. En el caso de la estrategia de prefetch transparente al SO, el valor de la

138

Cap tulo 6

distancia es un parmetro de ejecucin y global para todas las instrucciones que utilizaban a o el mecanismo de prefetch. En la estrategia de prefetch basada en la cooperacin, la distancia de prefetch pasa a ser o una caracter stica ms del patrn de accesos de cada instruccin, que se calcula de forma a o o automtica y se ajusta dinmicamente para adaptarse a las condiciones de ejecucin. a a o Hemos basado este ajuste en el estado de la pgina que la instruccin referencia en cada a o momento. Si la distancia de prefetch es la adecuada, y asumiendo que la prediccin de o accesos es correcta, entonces los accesos realizados por la instruccin sern sobre pginas o a a ya presentes en memoria f sica. Por lo tanto, hemos incorporado, como parte de la seleccin o de pginas de prefetch, el cdigo que comprueba si la pgina que referencia la ejecucin a o a o actual de la instruccin est presente en memoria f o a sica y, de no ser as corrige el valor , de la distancia usado para esa instruccin, para adaptarlo a las condiciones de ejecucin. o o Adems, la cooperacin del SO en la estrategia de prefetch, permite que la JVM agrupe a o varias solicitudes de carga anticipada y, as se aumente la posibilidad de que el SO pueda , optimizar los accesos a disco debidos a sus peticiones de prefetch. Esto puede hacerse porque hemos a adido un nuevo interfaz al SO que permite que un ujo solicite la carga n de una pgina de forma as a ncrona, sin tan siquiera esperar a que se inicie el acceso a disco y, por lo tanto, un mismo ujo puede tener varias peticiones pendientes de carga al mismo tiempo.

6.2

CARGA AS INCRONA Y ANTICIPADA

En el cap tulo 4 hemos visto que era necesario decidir cmo efectuar la solicitud de carga o as ncrona y anticipada, porque los SO actuales no disponen de un interfaz dedicado a este objetivo, y planteamos dos posibles alternativas. La primera, se basaba en utilizar alg n mecanismo ya existente dentro del SO para conseguir as una estrategia totalmente u transparente al SO, y es la que hemos presentado en el cap tulo anterior (ver seccin 5.2 en o el cap tulo 5). La segunda, consiste en modicar el SO con un nuevo interfaz que permita la lectura as ncrona de pginas del rea de swap, y que est dedicado a la solicitud de a a e

Prefetch cooperativo entre la JVM y el SO

139

carga anticipada. Esta segunda opcin implica la modicacin del SO y es la solucin o o o adoptada en la estrategia de prefetch cooperativo que presentamos en este cap tulo. A adir un interfaz dedicado para la peticin de carga as n o ncrona tiene varias consecuencias positivas. La primera consecuencia es que el SO diferencia las peticiones debidas al mecanismo de carga bajo demanda y las peticiones debidas al prefetch. Esto signica que puede usar esta informacin para tratar cada tipo de carga de acuerdo a sus requerimientos. Por o ejemplo, para las solicitudes de prefetch, las condiciones de ejecucin del sistema pueden o aconsejar descartar la operacin de prefetch para no sobrecargar el sistema de memoria. o Sin embargo, ante un fallo de pgina no es posible descartar el acceso a disco involucrado, a ya que es imprescindible para permitir que el proceso pueda continuar la ejecucin. o Otra consecuencia positiva es que, la implementacin del mecanismo de carga anticipada o integrada dentro del SO, permite tener en cuenta la ejecucin del resto de tareas de gestin o o de memoria que implementa el SO, lo cual favorece el objetivo de evitar las interferencias entre las decisiones de las diferentes tareas. Por ultimo, adoptar esta solucin hace que deje de ser necesario el nuevo ujo de ejecucin o o dentro de la JVM, que se utilizaba para dotar de asincron al mecanismo de fallo de a pgina. Esto representa una simplicacin importante en el cdigo introducido dentro de a o o la JVM, y elimina la necesidad de ajustar la interaccin de este nuevo ujo con el SO, o con el consiguiente aumento de estabilidad y eciencia de la estrategia de prefetch (ver las secciones 5.4.2 y 5.6 del cap tulo 5).

6.3

INTERFAZ ENTRE EL SO Y LA JVM PARA PERMITIR LA COOPERACION

El interfaz que hemos a adido en el SO para implementar la estrategia de prefetch coopen rativo tiene dos propsitos principales. El primero es exportar al nivel de usuario la inforo macin sobre el estado de la memoria, necesaria para poder prescindir de las heur o sticas

140

Cap tulo 6

durante la tarea de seleccin de pginas de prefetch. El segundo propsito es permitir que o a o desde el nivel de usuario se pueda solicitar de forma as ncrona la lectura de una pgina a que se encuentra en el rea de swap. En las siguientes secciones describimos el interfaz a que hemos dise ado para cumplir ambos propsitos. n o

6.3.1

Exportacin del estado de la memoria o

Para permitir que el SO exporte la informacin sobre el estado de la memoria, hemos o implementado una zona de memoria compartida entre el nivel de sistema y el nivel de usuario, donde el SO mantiene la informacin que interesa hacer visible a la JVM. Esta o zona de memoria compartida, en la implementacin que hemos hecho, contiene un bito map que representa el estado de cada pgina de una regin determinada del espacio de a o direcciones. Es decir, para cada pgina nos indica si se encuentra en memoria f a sica o si se encuentra en el rea de swap. Sin embargo, dejamos como trabajo futuro el estudio de a la conveniencia de que el SO exporte otros parmetros sobre el estado de la memoria, que a puedan ayudar a la JVM en la toma de decisiones de prefetch. El SO es el encargado de mantener actualizado el bitmap ante cada solicitud de carga (debida a un fallo de pgina o a una solicitud de prefetch) y ante cada expulsin al rea de a o a swap realizada por el algoritmo de reemplazo. De manera que, desde el nivel de usuario, la JVM tiene una visin exacta del estado de la memoria del programa. o Por su parte, la JVM es la encargada de solicitar al SO la creacin e inicializacin de o o la zona de memoria compartida, y lo hace como parte de la inicializacin del heap del o programa. Para ello debe indicar al SO cules son los l a mites de la regin del espacio de o direcciones que interesa representar en el bitmap que, en nuestro caso, se corresponden con los l mites del heap del programa. Hemos implementado el interfaz para la conguracin del bitmap utilizando el mecanismo o que ofrece Linux para introducir nuevos gestores de dispositivos. Por lo tanto, hemos creado un dispositivo lgico nuevo, que representa la zona de memoria compartida, y que o permite que la JVM congure el bitmap mediante el interfaz de Linux para el acceso y control de dispositivos.

Prefetch cooperativo entre la JVM y el SO

141

Una vez congurado el bitmap, cuando la JVM necesite consultarlo, simplemente tiene que acceder a la zona de memoria compartida como a cualquier otra de sus variables. Hay que tener en cuenta que, presumiblemente, esta operacin de consulta se va a efectuar en o millones de ocasiones, para evitar la peticin de pginas ya presentes en memoria f o a sica y la entrada innecesaria en el sistema que estas peticiones involucran. Por este motivo, es especialmente importante utilizar un mtodo de consulta rpido y que no implique la e a entrada en el sistema. En la seccin 6.5.1 describimos detalladamente todos los aspectos relacionados con la o implementacin del bitmap que representa el estado de las pginas que albergan el heap o a del programa.

6.3.2

Solicitud de carga as ncrona

En esta seccin vamos a describir el interfaz que hemos a adido al SO para permitir o n que, desde el nivel de usuario, se pueda solicitar la carga as ncrona en memoria de una pgina que se encuentra en el rea de swap. De esta manera, la JVM podr solicitar a a a anticipadamente la carga de las pginas seleccionadas de prefetch y continuar con la a ejecucin del programa, en paralelo con la lectura de disco de las pginas. o a Este interfaz consiste en una nueva llamada a sistema que recibe como parmetro la a direccin de memoria que se quiere cargar de forma as o ncrona (ver gura 6.2).

int async page read(int *address) descripcin: solicita la carga as o ncrona de la pgina a la que pertenece la direccin address a o valores de retorno: 0: solicitud de carga en curso -1: solicitud de carga cancelada EINTRANSIT: pgina ya est en trnsito a a a ESATDISK: gestor de disco saturado ENOFREEMEM: memoria f sica libre escasa ENOLOAD: error en la carga de pgina a

Figura 6.2 Interfaz de la llamada a sistema de carga as ncrona

142

Cap tulo 6

Ante esta peticin, el SO comprueba si las condiciones de ejecucin son favorables para o o completar la operacin de carga anticipada y, si es as reserva una nueva pgina en o , a memoria f sica para albergar los datos que se van a cargar del rea de swap, entrega la a peticin al gestor de disco y retorna al nivel de usuario indicando que la carga est en o a curso, de manera que el programa puede continuar con la ejecucin en paralelo mientras o se realiza la lectura de disco. Sin embargo, si el SO determina que, dada las condiciones del sistema, efectuar esa carga anticipada puede perjudicar el rendimiento del proceso, entonces cancela la operacin y o retorna al nivel de usuario indicando que no ha sido posible iniciar la carga solicitada. Hemos detectado dos posibles situaciones que aconsejan la cancelacin de las peticiones o de prefetch: cuando la memoria f sica libre es muy escasa y cuando existen demasiadas peticiones pendientes de acceso a disco y, por lo tanto, el gestor de disco se encuentra saturado. Por lo tanto, mediante este interfaz de lectura as ncrona, estamos implementando un mecanismo de carga anticipada en el que la JVM indica al SO las pginas que ser a a benecioso para el proceso cargar con anticipacin, pero es el SO en ultima instancia el o que decide si esta carga es conveniente o no, en funcin de las condiciones de ejecucin. o o Adems, como el SO informa al nivel de usuario de que no ha sido posible completar la a solicitud, se da la opcin de gestionar dentro de la JVM las operaciones canceladas de o la manera ms adecuada para el comportamiento del programa. En la implementacin a o que hemos hecho del prefetch cooperativo, la JVM registra las operaciones canceladas y aprovecha los momentos en los que disminuye la carga del sistema para reintentar estas operaciones. En la seccin 6.5.2 describimos en detalle la implementacin de esta llamada a sistema, o o as como algunas alternativas de dise o que nos hemos planteado y que hemos descartado n debido a su bajo rendimiento.

Prefetch cooperativo entre la JVM y el SO

143

6.4

VISION GENERAL: PREFETCH COOPERATIVO

En la gura 6.3 presentamos una visin general de la estrategia de prefetch basada en la o cooperacin entre el SO y la JVM, que a continuacin explicamos. o o
bytecode(pc, obj, pos, caract) pgina i (2) Estado pginas predice (1)

SO
(a) reemplazo (b) (c) fallo de pgina (d) syscall i disco p memoria fsica

JVM

(4)

pide(p) (3)

accede(i) (5)

Figura 6.3 Visin general del prefetch cooperativo entre JVM y SO o

Para cada bytecode de acceso a array, como en el caso de la estrategia transparente al SO, la JVM ejecuta el cdigo de la tarea de seleccin de pginas (1). Este cdigo actualiza, o o a o si es necesario, el valor de la distancia de prefetch y la informacin sobre el patrn de o o accesos de la instruccin y aplica ese patrn para determinar los prximos accesos de la o o o instruccin sobre el array. Para dar la opcin de que el SO agrupe las peticiones de acceso o o a disco, la JVM aplica varias veces el patrn para predecir un conjunto de pginas. o a Adems, la JVM utiliza la informacin sobre el estado de la memoria para ltrar, del a o conjunto de pginas seleccionadas, las que ya se encuentran presentes en memoria f a sica y, por lo tanto, no es necesario solicitar su carga anticipada (2). El SO es el encargado de mantener actualizada la informacin sobre el estado de las pginas, ante cualquier o a

144

Cap tulo 6

operacin de intercambio con el rea de swap (algoritmo de reemplazo (a), fallo de pgina o a a (b) o llamada a sistema de peticin de prefetch (c)), y de hacerla visible al nivel de usuario o a travs del interfaz de memoria compartida que hemos implementado. e Una vez nalizada la seleccin de pginas de prefetch, la JVM utiliza la llamada a sistema o a para pedir la lectura as ncrona de las pginas que ha seleccionado como candidatas a ser a cargadas anticipadamente (3). Ante esta peticin, si las condiciones de ejecucin son favorables, el SO inicia la carga o o de los datos solicitados (d), reservando una nueva pgina f a sica para ellos, entregando al gestor del disco la solicitud de acceso e informando a la JVM de que el proceso de carga se ha iniciado de forma satisfactoria. Si, por el contrario, las condiciones de ejecucin o desaconsejan iniciar la operacin de prefetch, el SO retorna a usuario indicando que la o solicitud ha sido cancelada. Al retornar de la llamada a sistema, la JVM comprueba cul ha sido el resultado de a la solicitud (4). Si el SO ha decidido cancelarla, la JVM la almacena en un buer de peticiones pendientes para reintentar la operacin si las condiciones de carga del sistema o mejoran. Si, por el contrario, la carga anticipada est en curso, la JVM comprueba si tiene a pendiente alguna operacin cancelada previamente para reintentar su solicitud. o Finalmente, la JVM contin a con la ejecucin del cdigo del programa (5), de manera u o o que, cuando ste intente acceder a a los datos que se han podido cargar con antelacin, si e o la distancia de prefetch ha sido la adecuada, el acceso se podr efectuar sin generar una a excepcin de fallo de pgina. o a

6.5

IMPLEMENTACION DEL PREFETCH COOPERATIVO

En esta seccin describimos las modicaciones que hemos introducido tanto en la JVM o como en el SO para implementar la estrategia de prefetch cooperativo. La versin de o kernel de Linux que hemos modicado es la 2.4.18-14 y la versin de la JVM que hemos o

Prefetch cooperativo entre la JVM y el SO

145

utilizado es la 1.3.1 de HotSpot que se distribuye con la Java 2 SDK Standard Edition de Sun para Linux Adems de las soluciones nales que hemos adoptado para la implementacin, tambin a o e presentamos algunas alternativas que nos hemos planteado as como el motivo que nos ha llevado a descartarlas. En la seccin 6.6, como parte de la evaluacin de la estrategia, o o presentamos los resultados de unos experimentos que sirven para validar las decisiones que hemos tomado durante la implementacin del prefetch cooperativo. o En las secciones 6.5.1 y 6.5.2 describimos la implementacin del interfaz que hemos ino corporado en el SO, para permitir su participacin en el prefetch guiado por la JVM. En o cuanto a la seccin 6.5.3, describe las modicaciones que hemos introducido en la JVM o para utilizar este interfaz en la solicitud de carga anticipada, substituyendo el uso del prefetcher y de las heur sticas que formaban parte de la estrategia de prefetch transparente al SO.

6.5.1

Implementacin para exportar el estado de la memoria o

La implementacin del interfaz del SO que permite exportar el estado de la memoria se o puede dividir en dos partes diferentes. La primera parte consiste en el cdigo necesario para crear la zona de memoria compartida o entre el SO y la JVM, y para congurar el bitmap que se guarda en esta zona y que representa el estado de las pginas de una regin de memoria. La segunda parte es la a o necesaria para mantener actualizada la informacin que contiene el bitmap. Este cdigo o o se ha introducido en el SO, como parte de la implementacin de la carga de memoria y o como parte de la liberacin de memoria f o sica.

Inicializacin y conguracin del bitmap o o


Como ya hemos adelantado en la seccin 6.3.1, hemos basado la implementacin de la o o zona de memoria que soporta el bitmap en el mecanismo que ofrece Linux para incorporar nuevos gestores de dispositivos. Por este motivo, hemos creado un nuevo dispositivo lgico o

146

Cap tulo 6

que representa al bitmap y hemos implementado el gestor de este nuevo dispositivo, con las funciones del interfaz de manipulacin de dispositivos necesarias para que la JVM cree o y congure este bitmap. Para congurar el bitmap lo unico necesario es asociarle la regin que va a representar, o para que as el SO pueda determinar las pginas cuyo cambio de estado debe reejar en el a bitmap. Es decir, hay que registrar los parmetros que caracterizan la regin: direcciones a o que la limitan y espacio de direcciones al que pertenece. Para ello, hemos creado una nueva estructura de datos en el kernel que contiene las caracter sticas del bitmap y la posicin o que ocupa en el espacio de direcciones del kernel, y que la JVM inicializa durante la fase de conguracin (ver gura 6.4). o

struct bitmap struct { /* estructura de datos que describe al proceso que usa el bitmap */ struct task struct *bitmaptask; /* direccin inicial de la regin representada por el bitmap */ o o unsigned long initAddr; /* direccin nal de la regin */ o o unsigned long lastAddr; /* tamao de la regin */ n o unsigned long length; /* posicin que ocupa el bitmap en el espacio del kernel */ o unsigned char *kernelBitmapAddr; }

Figura 6.4 Estructura de datos que caracteriza al bitmap dentro del SO

A continuacin se describe brevemente las funciones que hemos implementado como parte o del gestor del bitmap.

open: recibe como parmetro el dispositivo lgico asociado al bitmap y simplemente a o registra al proceso que la utiliza como espacio de direcciones que se quiere representar en el bitmap. bitmapFd = open(" /dev/bitmap ", O RDONLY)

Prefetch cooperativo entre la JVM y el SO

147

ioctl: esta es la llamada a sistema que se utiliza para congurar los dispositivos lgicos. La implementacin que hemos hecho de esta funcin permite hacer dos opeo o o raciones de conguracin diferentes que describimos a continuacin. o o Inicializacin del bitmap: esta operacin reserva la zona de memoria en el eso o pacio de direcciones del kernel que soporta el bitmap y le asocia los datos que caracterizan la regin que representa. Los parmetros que recibe esta llamada a o a sistema son la direccin inicial de la regin que se quiere representar en el bito o map (es decir, la direccin base del heap) y el tama o de esa regin (es decir, o n o el tama o mximo del heap). Utilizando estos parmetros calcula el tama o que n a a n debe tener el bitmap y reserva la cantidad de memoria necesaria para soportarlo, jndola, adems, de forma permanente en memoria f a a sica. Por ultimo, inicializa todos los bits a 0, ya que se parte del estado en que ninguna pgina de la regin a o est presente (se supone que la inicializacin del bitmap se realiza al mismo tiema o po que la inicializacin de la regin que va a representar). Como valor de retorno, o o esta funcin devuelve el tama o de la zona compartida con el kernel que se ha o n reservado. bitmapSize = ioctl(bitmapFd, BITMAP CONFIG, regionInfo) Desactivacin del uso del bitmap: en este caso, la llamada ioctl no necesita o ning n parmetro ya que, simplemente, desactiva el uso del bitmap, eliminando u a la asociacin con la regin que representaba y liberando la memoria que ocupaba o o en el kernel. ioctl(bitmapFd, BITMAP DEACT, 0) mmap: mediante esta funcin es posible mapear en el espacio de direcciones de usuario o un dispositivo lgico, y permitir que el programa acceda a este dispositivo a travs de o e la memoria donde est mapeado. La llamada mmap consigue este efecto reservando a una nueva regin y asociando a esta regin las funciones que, mediante el mecanismo o o de fallo de pgina, permitirn traducir los accesos a memoria en los correspondientes a a accesos al dispositivo. Estas funciones deben formar parte tambin de la implemene tacin del gestor del dispositivo mapeado. En nuestro caso, utilizamos la llamada a o mmap dentro de la JVM para reservar una nueva regin en su espacio de direccioo nes y mapear en ella el dispositivo del bitmap. La implementacin espec o ca de la llamada mmap, que hemos hecho dentro del gestor del bitmap, marca a las pginas a

148

Cap tulo 6

de la nueva regin para que no sean candidatas a ser expulsadas al rea de swap, a o a continuacin asocia a la regin las funciones que hemos implementado para vincularla o o con la regin del bitmap reservada en el kernel y, por ultimo, devuelve, como valor de o retorno, la direccin base de la regin reservada en el espacio de usuario, que la JVM o o podr utilizar para acceder al bitmap. a bitmapAddr = mmap(0, bitmapSize, PROT READ, MAP SHARED, bitmapFd, 0); Respecto a la funcin que establece el v o nculo entre la regin reservada y el dispositivo o mapeado, forma parte del tratamiento de los fallos de pgina que se producen por el a primer acceso a una pgina lgica. Esta funcin es invocada por la rutina de gestin de a o o o fallo de pgina del SO, una vez que ha comprobado la validez del acceso, para obtener a la pgina con la que debe actualizar la tabla de pginas del proceso y completar a a as la resolucin de la excepcin. En el caso del dispositivo del bitmap, para poder o o convertir los accesos a la regin de la JVM en los correspondientes accesos a la regin o o del bitmap, lo unico necesario es asociar las mismas pginas f a sicas a ambas regiones. Por lo tanto, la funcin de fallo de pgina inicial que hemos implementado se encarga o a de determinar la pgina f a sica correspondiente y devolverla a la rutina de fallo de pgina para que actualice con ella la tabla de pginas de la JVM. Hay que decir que a a los unicos fallos de pgina provocados por accesos a la regin que mapea el bitmap a o sern los debidos al primer acceso a cada pgina, ya que las pginas que soportan a a a el bitmap no son candidatas a ser expulsadas al rea de swap. Por lo tanto, slo es a o necesario establecer el v nculo entre ambas regiones durante el primer acceso. close: se libera el uso del dispositivo virtual asociado al bitmap. close(bitmapFd);

En la gura 6.5 mostramos el cdigo que debe ejecutar la JVM, como parte del tratamiento o de inicializacin del heap del programa, para inicializar y congurar el uso del bitmap, y o en la gura 6.6 representamos el resultado de esta inicializacin. Podemos ver que la JVM o le pide al gestor del bitmap, mediante la llamada a ioctl, que cree la zona de memoria compartida y la congure para representar el estado del heap del programa y, mediante la llamada a mmap, le pide que mapee el bitmap en su propio espacio de direcciones.

Prefetch cooperativo entre la JVM y el SO

149

... bitmapFd = open(/dev/bitmap , O RDONLY); /* tamao mximo del heap */ n a regionInfo[0] = maxHeapAddr-minHeapAddr; /* direccin base del heap */ o regionInfo[1] = minHeapAddr ; /* crea la regin en el espacio del kernel para representar el estado del heap */ o bitmapSize = ioctl(bitmapFd, BITMAP CONFIG, regionInfo); /* mapea el bitmap en una nueva regin del espacio de la JVM */ o bitmapAddr = mmap(0, bitmapSize, PROT READ, MAP SHARED, bitmapFd, 0); /* completar la inicializacin del heap */ o ...

Figura 6.5 Conguracin del bitmap en la JVM o

SO
ioctl

JVM

mmap

gestor bitmap
mmap ioctl kernelBitmapAddr

bitmapAddr minHeapAddr

maxHeapAddr

espacio de direcciones

Figura 6.6 Resultado de la inicializacin del bitmap o

Una vez congurado el bitmap, la JVM puede comprobar el estado de cualquier pgina del a heap accediendo a la regin que la llamada mmap ha reservado en su espacio de direcciones. o

150

Cap tulo 6

Para ello slo debe calcular la posicin del bitmap que representa el estado de la pgina o o a y consultar el valor de ese bit, lo que, sabiendo cul es la pgina inicial representada por a a ese bitmap, se reduce a una operacin aritmtica muy sencilla (ver gura 6.7). o e

ix = (p - minHeapPage) 3; pos = (p - minHeapPage) & 0x7; present = (bitmapAddr[ix] & (1

pos));

Figura 6.7 Acceso al estado de la pgina p a

Cdigo del SO para mantener el estado de las pginas o a


El SO es el responsable de mantener actualizada la informacin del bitmap, para que ste o e reeje en todo momento el estado de las pginas del heap del programa. Para ello, hemos a introducido en el SO el cdigo necesario para modicar el bitmap cada vez que cambia el o estado de una de las pginas que representa. Es decir, hemos modicado tanto la rutina a que libera pginas f a sicas y que, por lo tanto, provoca que una pgina lgica deje de estar a o presente en memoria f sica, como las rutinas que cargan en memoria f sica las pginas a lgicas que no estaban presentes. o Lo primero que hace el cdigo que hemos a adido es comprobar si la pgina cuyo estado o n a va a cambiar forma parte de la regin representada por el bitmap. Para ello basta con o acceder a las variables de conguracin del bitmap (ver gura 6.4), que contienen los o datos que caracterizan la regin, y que son inicializadas por la JVM en el momento de o creacin del bitmap. o La liberacin de memoria, en la versin de kernel que estamos utilizando, se hace efectiva o o en una unica rutina (try to unmap one) que recibe como parmetro la pgina que se a a quiere liberar y la entrada de la tabla de pginas a la que pertenece (ver gura 6.8). A a travs de esta entrada, es posible obtener la estructura de datos que describe el espacio e de direcciones al que pertenece la pgina, de manera que somos capaces de comprobar si a es el mismo espacio de direcciones que se est representando en el bitmap. Por otro lado, a mediante la direccin lgica involucrada en la liberacin de memoria, se puede comprobar o o o si adems se trata de una pgina de la regin, y en ese caso, calcular la posicin que a a o o

Prefetch cooperativo entre la JVM y el SO

151

int try to unmap one(struct page * page, pte t * ptep) { /* obtiene la direccin lgica a partir de la entrada de la TP */ o o unsigned long address = ptep to address(ptep); /* obtiene la estructura del espacio de direcciones a partir de la entrada de la TP */ struct mm struct * mm = ptep to mm(ptep); ... if (bitmap.bitmap task->mm == mm) { if ((address >= bitmap.initAddr) && (address<=bitmap.lastAddr)) { ix = ((address 12) 3); pos = ((address 12) & 0x7); bitmap.kernelBitmapAddr[ix] &= (1 pos); } } ... }

Figura 6.8 Actualizacin del bitmap en la liberacin de memoria o o

ocupa el bit que la representa para poner a cero su valor, y marcar as que la pgina ya a no est presente en memoria f a sica. El otro cambio de estado de las pginas que el SO debe registrar en el bitmap es el a correspondiente a su carga en memoria f sica (ver gura 6.9). Esto puede ocurrir como consecuencia de un fallo de pgina o como consecuencia de una peticin de carga ana o ticipada. En cualquiera de las dos situaciones, la rutina ejecutada tiene acceso tanto al proceso que solicita la carga como a la pgina que se quiere cargar en memoria f a sica. Por lo tanto se puede comprobar si se trata de una pgina representada por el bitmap y, de a ser as calcular el bit que la representa para activar su valor y marcar que la pgina ya , a se encuentra presente en memoria f sica. En ambas situaciones actualizamos el bitmap antes de nalizar la rutina y de retornar al nivel de usuario. Sin embargo, hay que destacar que en el caso de la llamada a sistema de carga as ncrona la rutina naliza al entregar la solicitud de carga al gestor de disco y, por lo tanto, se est marcando como presente en memoria f a sica una pgina que todav a a est en proceso de ser cargada. Esta decisin se ha tomado para permitir que la JVM a o evite tambin la solicitud de pginas que ya se encuentran en trnsito. e a a

152

Cap tulo 6

... /* macro current del kernel devuelve la estructura del proceso actual */ if (bitmap.bitmap task->mm == current->mm) { if ((address >= bitmap.initAddr) && (address<=bitmap.lastAddr)) { ix = ((address 12) 3); pos = ((address 12) & 0x7); bitmap.kernelBitmapAddr[ix] |= (1 pos); } } ...

Figura 6.9 Actualizacin del bitmap en la carga de memoria o

6.5.2

Implementacin de la llamada a sistema para la carga o as ncrona

El interfaz que hemos implementado para permitir la peticin as o ncrona de carga desde el nivel de usuario consiste en una nueva llamada a sistema. Esta llamada recibe como parmetro una direccin de memoria de la pgina que se quiere cargar de forma as a o a ncrona y su ejecucin se completa o bien con la entrega de la peticin al gestor de disco o bien o o con la cancelacin de la solicitud, si el SO considera que llevarla a cabo puede perjudicar o el rendimiento del programa. Bsicamente, el cdigo de esta nueva llamada a sistema sigue el mismo camino de ejecucin a o o que la rutina del kernel responsable de cargar una pgina como respuesta a un fallo de a pgina. La principal diferencia entre ambos cdigos radica en que la carga as a o ncrona evita todas las situaciones que, para poder continuar con la carga de memoria, requieren bloquear al proceso que efect a la llamada. Ante una situacin de este tipo, la llamada a u o sistema cancela la solicitud de carga y retorna al usuario informando de que no ha sido posible completar la peticin, ya que ello implicar el retardo asociado a los bloqueos y o a la consiguiente prdida de rendimiento de la estrategia de prefetch. Hay que destacar que e la opcin de cancelar la peticin de carga no es viable para la rutina de gestin de fallo o o o de pgina ya que el proceso que ha provocado esa excepcin necesita que se complete la a o carga de la pgina para poder continuar la ejecucin. a o

Prefetch cooperativo entre la JVM y el SO

153

En la gura 6.10 mostramos el camino de ejecucin tanto para el mecanismo de fallo de o pgina (a) como para la peticin de carga as a o ncrona (b), para poder se alar las diferencias n entre ambos cdigos. o En ambos casos suponemos que ya se ha validado el acceso a la direccin. Es decir es una o direccin vlida y el tipo de acceso est permitido por los permisos de acceso asociados a la o a a regin a la que pertenece. Por lo tanto, lo primero que hacen ambas rutinas es comprobar o que la pgina realmente se encuentra en el rea de swap. Es decir, que no est ya cargada a a a en memoria f sica (1) ni se encuentra en proceso de carga (2). En cualquiera de las dos situaciones, ambas rutinas nalizan la ejecucin indicando que no es necesario efectuar la o lectura de disco de los datos. Si la pgina est en el rea de swap, el siguiente paso necesario para poder cargarla en a a a memoria consiste en asignarle una pgina f a sica libre. En la rutina de reserva de memoria libre es donde aparece la primera diferencia entre ambas situaciones de carga, si la cantidad de memoria f sica es inferior a un determinado umbral (cuyo valor es congurable por el administrador de la mquina) y, por lo tanto, se considera muy escasa (3). a En esta situacin, la rutina de gestin de fallo de pgina bloquea al proceso hasta que el o o a algoritmo de reemplazo de memoria de Linux consigue liberar memoria, enviando al rea a de swap las pginas que se consideran menos necesarias para los procesos en ejecucin. a o Por el contrario, la llamada a sistema de carga as ncrona cancela la peticin de carga, y o retorna al usuario indicando que la cantidad de memoria libre hace imposible iniciar la carga anticipada sin bloquear al proceso. Si la reserva de memoria naliza con xito, a continuacin hay que entregar al gestor de e o disco la peticin de lectura de los datos. Este paso tambin puede necesitar el bloqueo o e del proceso en situaciones de alta presin para el sistema y, por lo tanto, el cdigo de o o la llamada a sistema se vuelve a diferenciar del cdigo de resolucin de fallo de pgina. o o a La operacin consiste en inicializar una estructura de datos, que describe el acceso que o se quiere realizar, y en introducir esa estructura en una cola de peticiones pendientes asociada al gestor de disco, para que ste la atienda cuando le sea posible. El n mero e u de peticiones pendientes que puede contener esta cola est limitado por una variable del a

154

Cap tulo 6

FP pgina presente?

async_page_read pgina presente?

1
si

no pgina en trnsito? si

no pgina en trnsito?

2
si

no memoria libre muy escasa? no si

no memoria libre muy escasa? no

3
si soft FP

3
si

espera

reserva pgina demasiadas peticiones pendientes?

reserva pgina demasiadas peticiones pendientes?

4
si espera

no si retorno (prefetch cancelado)

no

peticin disco

peticin disco

espera interrupcin de disco actualizacin TP y retorno interrupcin de disco

retorno (prefetch en curso)

actualizacin TP y retorno

(a) fallo de pgina

(b) llamada a sistema de lectura asncrona

Figura 6.10 Fallo de pgina vs. carga as a ncrona

kernel. Cuando este l mite se supera, se asume que el gestor de disco est saturado y, a por lo tanto, el cdigo original de Linux bloquea al proceso que solicita el acceso a disco o

Prefetch cooperativo entre la JVM y el SO

155

hasta que alguna de las peticiones pendientes se completan (4). Hemos modicado este comportamiento slo para las solicitudes de acceso debidas a una carga anticipada de o manera que, si no es posible encolar la peticin para el gestor de disco sin bloquear antes o al proceso, se descarta el acceso. En esta situacin, se cancela la operacin de prefetch, o o liberando la pgina que se hab reservado para soportar los datos y retornando al usuario a a el motivo de la cancelacin. o Finalmente, si es posible entregar la solicitud de acceso a disco al gestor, en el caso de la rutina de fallo de pgina, el proceso se bloquea hasta que la lectura de la pgina se a a completa. Cuando eso ocurre, el controlador del disco genera una interrupcin que el SO o gestiona desbloqueando al proceso que estaba esperando este evento. El proceso, entonces, contin a la ejecucin completando la rutina de gestin de fallo de pgina, que actualiza u o o a la tabla de pginas del proceso antes de retornar al cdigo de usuario. En el caso de la a o carga as ncrona, el SO naliza inmediatamente la llamada a sistema, informando al nivel de usuario de que la carga est en curso. Cuando el controlador de disco genere la a interrupcin para noticar al SO la nalizacin del acceso, el SO debe comprobar si se o o trata de una lectura as ncrona y, en ese caso, debe gestionar la interrupcin completano do el tratamiento de la carga anticipada. Es decir, debe ser capaz de identicar la tabla de pginas y actualizar la entrada asociada a la pgina cargada. Para esta actualizacin a a o necesita, adems de la direccin f a o sica, los permisos de acceso de la regin a la que pero tenece. Adems este cdigo debe respetar el tratamiento que hace Linux para evitar las a o condiciones de carrera que podr da ar la integridad de sus estructuras de datos. En an n este sentido ha sido necesario proteger el acceso a la estructura de la pgina, y a la tabla a de pginas. Adems, ha sido necesario liberar el acceso a la entrada del rea de swap a a a que conten la pgina cargada. Para ello, hemos a adido en la estructura de datos que a a n representa una pgina en Linux todos los campos necesarios (ver gura 6.11). Antes de a nalizar la llamada a sistema, se actualizan estos campos con los valores adecuados, ya que desde la llamada a sistema, igual que desde la rutina de fallo de pgina, se tiene acceso a a todas las variables necesarias.

156

Cap tulo 6

typedef struct page { ... pte t * page table; /*puntero a la entrada de la TP involucrada */ pgprot t prot; /* permisos de acceso asociados a la pgina */ a swp entry t entry; /* para liberar uso de la entrada del rea de swap*/ a struct mm struct * mm; /* para liberar uso de la TP*/ }

Figura 6.11 Campos a adidos a la estructura que representa una pgina en Linux n a

Alternativas para la implementacin de la carga as o ncrona


Durante la implementacin de esta llamada a sistema, nos hemos planteado dos alternao tivas que hemos considerado interesante evaluar. La primera de ellas afecta al interfaz de la llamada, y se reere a la cancelacin de la o solicitud de prefetch que puede hacer el SO. La alternativa es no permitir esta cancelacin o y dejar que la JVM decida qu operaciones de prefetch se inician, aprovechando que conoce e exactamente las pginas que el proceso necesita en un futuro inmediato. De manera que, a si la solicitud de carga as ncrona respeta la integridad del sistema, siempre se naliza la llamada con el proceso de carga preparado para ser iniciado. Por lo tanto, con esta alternativa, puede ser necesario que el SO bloquee al proceso tanto durante la asignacin o de memoria libre como durante la introduccin de la peticin de lectura en la cola del o o gestor de disco. En la seccin 6.6.2 presentamos los resultados de evaluar esta alternativa, o y vemos que el tiempo de bloqueo implicado en las solicitudes de carga impiden que el programa extraiga todos los benecios posibles de la estrategia de prefetch. La segunda alternativa no afecta al dise o del interfaz y es slo una decisin de implemenn o o tacin en la carga anticipada. Se trata de no actualizar la tabla de pginas del proceso o a en la rutina de atencin al disco, sino esperar hasta que el proceso acceda por primera o vez a la pgina cargada as a ncronamente provocando, de esta manera una excepcin de o fallo de pgina. Hay que destacar que esta es la opcin utilizada por Linux para gestionar a o las pginas cargadas por su estrategia de prefetch secuencial, y que estos fallos de pgina a a

Prefetch cooperativo entre la JVM y el SO

157

se resuelven simplemente actualizando la tabla de pginas del proceso. Esta alternativa a simplica el cdigo de gestin de la carga as o o ncrona y, adems, evita las posibles actuaa lizaciones innecesarias de la tabla de pginas que pueden hacerse debido a predicciones a errneas durante la fase de estabilizacin de los patrones de acceso. Sin embargo, hemos o o evaluado esta alternativa para la implementacin y hemos observado que, en situaciones o de alta presin para el sistema de memoria, retrasar el momento de la actualizacin de la o o tabla de pginas puede provocar un bajo rendimiento en la estrategia de prefetch (ver la a seccin 6.6.2). o

6.5.3

Modicaciones de la JVM para usar el prefetch cooperativo

En esta seccin describimos las modicaciones que se han introducido en la JVM para o usar el interfaz de prefetch que hemos denido en el SO, y optimizar el rendimiento de la estrategia de prefetch explotando las posibilidades que ofrece el nuevo interfaz. Hay que destacar que, como ya hemos dicho en la seccin 6.1, el mecanismo de prediccin o o que utilizamos contin a siendo el mismo que describimos para la estrategia de prefetch u transparente al SO (ver la seccin 5.4.1 del cap o tulo 5), ya que la JVM dispone de toda la informacin necesaria para obtener una prediccin precisa y el SO no puede aportar o o ning n dato que la mejore. u La primera modicacin necesaria consiste en la inicializacin y conguracin del bitmap, o o o utilizando el interfaz de manipulacin del dispositivo lgico bitmap de la manera que se o o indica en la gura 6.5. Estas operaciones forman parte de la inicializacin del heap y o permiten que, a partir de ese momento, la JVM pueda consultar el estado de cualquier pgina del heap en lugar de intentar aproximarlo mediante heur a sticas. As en la tarea de seleccin de pginas, hemos substituido el uso de heur , o a sticas por la consulta de este bitmap en todos los puntos donde la JVM necesita conocer el estado de alguna pgina del heap. Esto es, durante la generacin del patrn de accesos, para a o o aplicar la simplicacin relacionada con el uso de working sets que describimos en la o seccin 5.11, y antes de solicitar al SO la carga as o ncrona de una pgina, para evitar las a peticiones redundantes. En la seccin 6.6.2, mostramos los resultados de un experimento o

158

Cap tulo 6

que demuestran la relevancia que tiene para el rendimiento de prefetch el uso del bitmap, para evitar las peticiones de prefetch que se reeren a pginas ya presentes o que ya se a encuentran en proceso de carga. Tambin hemos a adido la automatizacin del clculo de la distancia de prefetch. Como e n o a ya hemos dicho en la seccin 6.1, asociamos un valor de distancia de prefetch a cada inso truccin como un parmetro ms de su patrn de accesos, que ajustamos dinmicamente o a a o a para adaptarse a las condiciones de ejecucin. o Esta distancia indica la anticipacin con la que se debe solicitar la carga as o ncrona de una pgina para que cuando la instruccin acceda a esa pgina se haya podido completar su a o a carga. Habitualmente, su unidad de medida es una iteracin, es decir, su valor indica el o n mero de ejecuciones de la instruccin asociada que deben ocurrir desde que se solicita u o la carga de la pgina hasta que se accede. Sin embargo, el cdigo de seleccin de pginas a o o a de prefetch no se ejecuta para cada ejecucin de la instruccin, sino slo cuando esa o o o instruccin cambia la pgina destino de su acceso. Por este motivo, nosotros usamos o a como unidad para la distancia una ejecucin de cdigo de seleccin. Es decir, el valor de o o o la distancia indica el n mero de pginas diferentes que la instruccin accede desde que se u a o solicita la carga de una pgina hasta que la instruccin la referencia. a o Existe una excepcin en el uso que hacemos de la distancia. Se trata de los patrones de o acceso simplicados que representan el uso de working sets. En este caso, la unidad de medida de la distancia es el working set de la instruccin. Adems, para este patrn de o a o accesos, el valor de esta distancia siempre es un working set, ya que, durante los accesos a un working set predecimos las pginas que forman parte del siguiente working set que a se va a referenciar. Para el resto de patrones de acceso, ajustamos el valor de la distancia utilizando la siguiente estrategia. Antes de predecir se comprueba si la prediccin anterior fue efectiva, o consultando si la pgina que la ejecucin actual referencia ya est cargada en memoria. a o a Para ello, el cdigo de seleccin de pginas se adelanta al acceso que hace el cdigo de o o a o tratamiento del bytecode y mide el tiempo necesario para ese acceso, de manera que puede determinar si se trata de un fallo de pgina o no. Hay que destacar que este mtodo no a e

Prefetch cooperativo entre la JVM y el SO

159

perjudica el rendimiento de los programas, ya que lo unico que hace es adelantar unas instrucciones el momento en el que se lleva a cabo el acceso que el propio programa necesita. El motivo por el que hemos utilizado este mtodo en lugar de consultar el bitmap e con el estado de las pginas, es que la informacin del bitmap est orientada a evitar las a o a peticiones de carga redundante, que son las que se reeren tanto a pginas ya presentes a como a pginas en proceso de ser cargadas y, por lo tanto, no distingue entre estos dos a estados. Sin embargo, un acceso a una pgina en trnsito tambin indica que la distancia a a e de prefetch no ha sido suciente. Si la pgina no est cargada, entonces se asume que la distancia de prefetch no es suciente a a para las condiciones de ejecucin actuales y se incrementa hasta que su valor alcanza una o cota superior. Recordemos que el valor de la distancia tambin inuye en la cantidad e de pginas cargadas con antelacin: cuanto mayor sea menos operaciones de prefetch se a o efect an y, por lo tanto, ser menor la cantidad de lecturas que se pueden solapar con el u a tiempo de clculo. a Para poder implementar esta estrategia es necesario decidir el valor de tres parmetros: a valor del incremento, valor inicial de la distancia y valor mximo que puede alcanzar. En a la implementacin que evaluamos en este trabajo, cada vez que se debe incrementar la o distancia multiplicamos por dos su valor, porque esta operacin es muy rpida de efectuar. o a Como valor mximo hemos seleccionado 1024 pginas, porque experimentalmente hemos a a comprobado que este valor queda lejos del que ofrece mejor rendimiento para todos los programas que hemos evaluado. Y el valor inicial viene determinado por la cantidad de pginas que se piden para cada ejecucin de la seleccin de prefetch que, como explicamos a o o a continuacin, es 16 pginas. En la seccin 6.23, se puede ver los resultados de aplicar o a o esta heur stica tan sencilla ofrece un buen rendimiento para todos los programas que hemos evaluado, sin que el tiempo de clculo involucrado perjudique el rendimiento de a los programas. Otra modicacin que hemos introducido en la tarea de seleccin de pginas consiste en o o a aprovechar el uso de la llamada a sistema de lectura as ncrona para seleccionar varias pginas en cada ejecucin de una instruccin y, as facilitar las optimizaciones del SO en a o o el acceso a disco. Hay que decir que, mientras el patrn de accesos de una instruccin no o o

160

Cap tulo 6

se considera estabilizado slo se solicita la carga anticipada de una pgina, para evitar o a peticiones de prefetch errneas (ver gura 6.12). o
JVM SO

Estado pginas
ajustar distancia informacin prediccin

bytecode (pc, obj, pos, caract)

predecir

prediccin
pgina predicha

Figura 6.12 Prediccin de accesos no estabilizada o

El cdigo necesario para implementar esta funcionalidad consiste simplemente en aplicar o el patrn de accesos varias veces para predecir el prximo conjunto de pginas que interesa o o a cargar anticipadamente (cluster). Por lo tanto, el n mero de ejecuciones que provocan la u prediccin de pginas para una instruccin se divide por el tama o del cluster (ver gura o a o n 6.13). En la implementacin actual de nuestra estrategia hemos seleccionado como tama o de o n cluster 16 pginas y ste es tambin el valor inicial de la distancia de prefetch. El motivo a e e para seleccionar este valor es que es el n mero de pginas que se aconseja utilizar como u a mximo en la estrategia de prefetch secuencial implementada en Linux, ya que ms all de a a a esta cantidad no es posible optimizar el n mero de accesos al rea de swap. u a Una vez obtenido el conjunto de pginas que interesa cargar con antelacin, para cada a o pgina de ese conjunto que se encuentra en el rea de swap la JVM solicita su carga a a as ncrona, mediante la nueva llamada a sistema. En este punto, hay que destacar que

Prefetch cooperativo entre la JVM y el SO

161

JVM

SO
Estado pginas prediccin
ajustar distancia

bytecode (pc, obj, pos, caract)

informacin prediccin

saltar == 0 saltar -saltar>0 predecir (saltar = cluster)

cdigo bytecode

cluster pginas predichas

Figura 6.13 Prediccin de accesos estabilizada o

hemos eliminado de la JVM el ujo que se encarga del prefetch en la estrategia de prefetch transparente al SO, y todo el cdigo necesario para gestionarlo. Esto supone una gran o simplicacin del cdigo de prefetch y permite aumentar la estabilidad y eciencia del o o mecanismo. Una vez ejecutada la llamada a sistema de peticin de carga, la JVM comprueba el o resultado de la solicitud. En caso de que el sistema se encuentre sobrecargado y, por lo tanto, haya cancelado la operacin de prefetch, la JVM almacena la peticin en un o o buer de pginas pendientes de prefetch (ver gura 6.14). Si, por el contrario, el sistema a indica que ha entregado con xito al gestor de disco la peticin de carga, entonces la JVM e o inicia la gestin de las peticiones que tenga pendientes de prefetch, aprovechando que las o condiciones del sistema son ms favorables para la carga en memoria (ver gura 6.15). a La gestin que hemos implementado para las operaciones de prefetch canceladas por el SO o es muy sencilla. El orden de tratamiento es FIFO y, como ya hemos dicho, se inicia si las solicitudes de carga correspondientes a la ejecucin de la instruccin actual se completan o o

162

Cap tulo 6

JVM

SO

prediccin seleccionadas filtro

Estado pginas

async_page_read

peticin cancelada pendientes por cancelacin seleccin y solicitud de prefetch

Figura 6.14 Condiciones no favorables para el prefetch: operaciones canceladas

con xito. Para tratar cada peticin, se extrae del buer de peticiones pendientes y se e o comprueba el estado de la pgina involucrada y, si todav se encuentra en el rea de a a a swap, se solicita de nuevo su carga as ncrona. El tratamiento de las peticiones pendientes se suspende cuando ya no es posible completar con xito las solicitudes de carga, es decir, e cuando el SO cancela una de las operaciones, y se reanuda cuando el SO sea capaz de volver a aceptar solicitudes de carga as ncrona. Hay que decir que esta pol tica tan sencilla para la gestin de las operaciones ha demoso trado un buen rendimiento para la estrategia de prefetch en los experimentos que hemos ejecutado (ver seccin 6.6.2). o

Alternativa para el tratamiento de las operaciones de prefetch canceladas


Una alternativa ms simple para el tratamiento de las operaciones de prefetch canceladas a por el SO consiste en descartarlas. Hay que destacar que esta es la opcin adoptada por o la estrategia de prefetch secuencial que ofrece Linux, en la versin de kernel que hemos o usado en esta implementacin, ya que, cuando la carga de la mquina es alta, simplemente o a

Prefetch cooperativo entre la JVM y el SO

163

JVM

SO

prediccin seleccionadas filtro

Estado pginas

async_page_read

peticin en curso pendientes por cancelacin seleccin y solicitud de prefetch

Figura 6.15 Condiciones favorables para el prefetch: prefetch en curso

desactiva su estrategia de prefetch, para dedicarse slo a las cargas que realmente son o imprescindibles para que los procesos contin en. u Sin embargo, hemos evaluado el uso de esta opcin en el prefetch cooperativo y hemos o visto que provoca que baje su rendimiento (ver seccin 6.6.2). El motivo es que, cuando el o sistema de memoria se encuentra bajo una alta presin, las probabilidades de solicitar una o operacin de prefetch en un momento de saturacin del sistema son muy altas y, por lo o o tanto, son muchas las operaciones que, en primera instancia, se tienen que cancelar. Como esta alternativa no da la opcin de reintentar estas operaciones, todas las cancelaciones o se convierten en oportunidades perdidas para solapar los accesos a disco con el tiempo de clculo del proceso. a

6.6

EVALUACION DEL PREFETCH COOPERATIVO

En esta seccin presentamos los resultados de los experimentos que hemos realizado para o evaluar la estrategia de prefetch cooperativo. Estos experimentos se pueden separar en dos grandes grupos. El primer grupo de experimentos, que se describen en la seccin 6.6.2, son o los que nos han servido para validar las decisiones que hemos tomado durante la imple-

164

Cap tulo 6

mentacin de la estrategia. El segundo grupo de experimentos compara el rendimiento de o un conjunto de aplicaciones ejecutadas sobre el entorno modicado con nuestra propuesta de prefetch cooperativo y ejecutadas sobre el entorno original (ver seccin 6.6.3). o Hemos ejecutado todos estos experimentos sobre un PC con un procesador Pentium IV a 1,8 GHz y con 256Mb de memoria. El objetivo de las tcnicas de prefetch es mejorar el e rendimiento de los programas que hacen un uso intensivo de la memoria virtual. Por este motivo, para cada programa, hemos seleccionado la cantidad de memoria f sica que hace necesario que el programa utilice el mecanismo de memoria virtual durante su ejecucin, y o hemos arrancado la mquina limitando a esa cantidad la memoria disponible en el sistema. a

6.6.1

Metodolog para los experimentos a

Para evaluar el rendimiento del prefetch cooperativo hemos utilizado el mismo mecanismo de contadores utilizado en el cap tulo 3 y en el cap tulo 5, adaptndolo a las necesidades a de esta evaluacin. o En estos experimentos nos interesa desglosar el tiempo de ejecucin separando el tiempo o dedicado a resolver fallos de pgina del resto del tiempo de ejecucin. A su vez, clasicamos a o el tiempo de fallo de pgina en funcin del tipo de fallo de pgina involucrado: fallos de a o a pgina que no requieren un acceso a disco para ser completados (fallos soft), como, por a ejemplo, los que se deben al acceso a pginas que se encuentran en proceso de intercambio a con el rea de swap, y fallos de pgina que s necesitan del acceso a disco para poder ser a a resueltos (fallos hard). Tambin, hemos evaluado el tiempo de bloqueo que sufre el proceso e durante las operaciones de prefetch, para lo cual hemos introducido un nuevo contador en el kernel. Del resto de tiempo de ejecucin, la unica distincin a adida que nos interesa o o n es saber la cantidad de tiempo dedicada a ejecutar la tarea de seleccin de pginas. Este o a tiempo slo puede ser medido por la JVM, por lo que, utilizando los contadores hardware o de tiempo que ofrece nuestro procesador, hacemos que la JVM acumule en una variable el tiempo invertido en esa tarea. En cuanto a las peticiones de lectura del rea de swap, queremos distinguir entre las que a provienen de la llamada a sistema de prefetch y las que solicitan los fallos de pgina del a

Prefetch cooperativo entre la JVM y el SO

165

programa, separando tambin los fallos de pgina que realmente implican un acceso al e a rea de swap, y los que se pueden resolver sin ese acceso. a Por ultimo, hay que tener en cuenta la inuencia que puede tener en el rendimiento de los programas la estrategia de prefetch secuencial implementada por Linux ya que, en el mejor de los casos, sus decisiones son redundantes con respecto a las decisiones del prefetch cooperativo. En la versin de kernel que hemos utilizado para desarrollar y o evaluar el prefetch cooperativo (versin 2.4.18-14), si la cantidad de memoria f o sica libre es muy baja, Linux descarta la utilizacin de su estrategia de prefetch. Este comportamiento, o que no se daba en las versiones previas de Linux que hemos utilizado durante el desarrollo de este trabajo, hace previsible que Linux no aplique sus propias decisiones de prefetch durante la ejecucin de nuestros experimentos, ya que stos involucran una alta carga para o e el sistema de memoria. De todas maneras, hemos optado por desactivar expl citamente el prefetch original de Linux durante la ejecucin de los benchmarks sobre el prefetch o cooperativo.

6.6.2

Evaluacin de las decisiones de diseo o n

En esta seccin presentamos el grupo de experimentos que hemos utilizado para validar o las decisiones de dise o y de implementacin que hemos tomado en el desarrollo de esta n o estrategia. En estos experimentos era importante utilizar un benchmark que facilitara el anlisis a de los resultados, por lo que hemos seleccionado el kernel de multiplicacin de matrices. o El tama o de las matrices de entrada que hemos seleccionado hace necesario el uso de n la memoria virtual, y por lo tanto tiene sentido aplicar la estrategia de prefetch para mejorar su rendimiento (ver tabla 6.1). Adems, con estas matrices de entrada, es posible a mantener varios working sets en memoria, ya que, como se puede ver en la tabla 6.1, se necesita alrededor de 16Mb para almacenar una la de la matriz recorrida por las (matriz A) y varias columnas consecutivas de la matriz recorrida por columnas (matriz B). Por lo tanto, se puede simplicar el patrn de accesos asociado a las instrucciones tal o y como se describi en la seccin 5.1.3 del cap o o tulo 5. Es decir, una vez captado el patrn o de accesos, se toma una decisin de prefetch para el primer acceso a cada pgina de un o a

166

Cap tulo 6

working set y, como consecuencia, se solicita la carga anticipada de la pgina equivalente a del siguiente working set. En este tipo de simplicacin, pues, medimos la distancia de o prefetch en unidades de working set del programa y siempre vale una unidad.
Matriz Matriz A (ints) Matriz B (ints) Tamao n 1024x4096 (16Mb) 4096x16384 (256Mb) Pginas la a 4 (0,015Mb) 16 (0,062Mb) Pginas columna a 1024 (4Mb) 4096 (16Mb)

Tabla 6.1 Caracter sticas de las matrices de entrada para la multiplicacin (AxB) o

Los resultados que mostramos en esta seccin son los obtenidos tras el clculo de cinco o a las de la matriz resultado, ya que esto es suciente para analizar el comportamiento de las alternativas para la implementacin del prefetch cooperativo. o

Eciencia del bitmap


En este primer experimento medimos la necesidad de utilizar el bitmap que representa el estado de las pginas del heap. Para ello hemos querido estimar el coste que implicar a a hacer todas las solicitudes de carga, sin ltrar las que se reeren a pginas ya presentes a en memoria f sica. El coste de este tipo de solicitudes redundantes se limita prcticamente al coste de entrar a en el sistema, ya que el cdigo de la llamada a sistema lo primero que hace es comprobar o en la tabla de pginas del proceso si la pgina ya est presente en memoria y, de ser as a a a , retorna a usuario inmediatamente. Por lo tanto, medir el tiempo utilizado para ejecutar los traps involucrados es una buena estimacin de la sobrecarga que implica no ltrar las o peticiones redundantes. Para hacer esta medida, hemos substituido el uso de la llamada a sistema de prefetch por una llamada a sistema vac y hemos medido el tiempo asociado a, a las llamadas tanto si se consulta el bitmap para eliminar las peticiones redundantes como si no se hace.
Bitmap No usado Usado Num. peticiones pref. 369.604.819 421.952 Tiempo de trap 241,18 segs 0,29 segs Tiempo de fp hard 279,51 segs 267,63 segs

Tabla 6.2 Inuencia en el rendimiento del bitmap del estado de las pginas a

Prefetch cooperativo entre la JVM y el SO

167

En la tabla 6.2 mostramos el resultado de este experimento. Hemos contado para cada caso, el n mero de peticiones de prefetch que se ejecutan, el tiempo de trap implicado en u esas peticiones y el tiempo que el SO ha dedicado a resolver fallos de pgina del proceso. a Podemos observar que, si no se utiliza el bitmap para ltrar peticiones redundantes, el n mero de entradas en el sistema es casi 370 millones y el tiempo necesario para ejecutarlas u es alrededor de 241 segundos. Teniendo en cuenta que el tiempo dedicado a resolver fallos de pgina es de alrededor de 268 segundos, aunque la estrategia de prefetch sea capaz de a evitar todos los fallos de pgina, la sobrecarga involucrada en el mecanismo para cargar a anticipadamente las pginas hace imposible mejorar el rendimiento nal del programa. a Sin embargo, si se consulta el bitmap y se entra en el sistema slo para aquellas pginas o a que se encuentran en el rea de swap, entonces el n mero de traps se reduce a unos 422 a u mil con un tiempo asociado de tan solo 0,29 segundos. Es decir, la consulta del bitmap permite dividir por un factor mayor de 1000 la sobrecarga que a aden los traps al sistema sobre el mecanismo de prefetch. Por lo tanto, se incrementa n considerablemente el margen para los posibles benecios de la estrategia de prefetch.

Alternativas en el comportamiento de la solicitud de carga anticipada


Durante el dise o e implementacin de la estrategia de prefetch, hemos considerado tres n o posibles comportamientos de las solicitudes de carga anticipada. En esta seccin presentao mos los resultados de los experimentos que hemos realizado para validar la decisin nal o que hemos adoptado en nuestra estrategia de prefetch. Lo primero que hay que decir es que las tres opciones coinciden en dar a la JVM el papel de gu del prefetch, ya que es ella la que, en base al conocimiento que tiene sobre el a comportamiento del programa, selecciona las pginas que conviene cargar con antelacin a o para evitar fallos de pgina. a

168

Cap tulo 6

Partiendo de esta base, las dos primeras alternativas afectan a la participacin del sistema o en las decisiones de prefetch. La primera opcin es hacer que una llamada a sistema de o prefetch, siempre que respete la abilidad del sistema, concluya con la peticin de lectura o entregada al gestor de disco. Es decir, las peticiones de prefetch que hace la JVM son de ejecucin obligatoria y, por lo tanto, el SO se limita a efectuar la operacin, bloqueando o o en caso necesario al proceso que la solicita (ver seccin 6.5.2). La segunda opcin es la o o que hemos adoptado como parte de nuestra propuesta. Consiste en dar al SO la facultad de cancelar las solicitudes de prefetch cuando las condiciones de ejecucin hacen necesario o bloquear al proceso para poder completar la solicitud. Con esta alternativa cada peticin o de prefetch de la JVM es una pista para mejorar el rendimiento del programa, pero la decisin nal queda en manos del SO. o La alternativa de implementar la peticin de prefetch como una pista tiene a su vez dos o posibles comportamientos. La primera posibilidad es que el SO implemente la cancelacin o de forma transparente a la JVM. En este caso, la JVM no es consciente de qu solicitudes e se han cancelado y, por lo tanto, no tiene opcin de reaccionar adecuadamente (pista o sin reaccin). La segunda posibilidad consiste en que el SO informe a la JVM, mediante o el valor de retorno de la llamada a sistema, sobre aquellas operaciones que ha debido cancelar para no perjudicar el rendimiento del proceso. De esta manera, la JVM puede gestionar estas operaciones canceladas reintentando su solicitud cuando las condiciones de ejecucin sean ms favorables (pista con reaccin). Este ultimo es el comportamiento o a o que sigue nuestra propuesta de prefetch cooperativo. En la gura 6.16 comparamos las tres alternativas de comportamiento de una peticin de o prefetch: obligatoria, pista sin reaccin y pista con reaccin. La gura 6.16.a muestra el o o tiempo de ejecucin desglosado del benchmark: tiempo de fallo de pgina hard (tfp hard), o a tiempo de fallo de pgina soft (tfp soft), tiempo de bloqueo de la peticin de prefetch a o (bloqueo peticin), tiempo de seleccin de pginas de prefetch (seleccin) y resto de tiempo o o a o de clculo (clculo). Por otro lado, la gura 6.16.b muestra el n mero de fallos de pgina a a u a (fp hard y fp soft) y el n mero de pginas cargadas por prefetch (carga anticipada). u a Lo primero que podemos observar es que la opcin de solicitud obligatoria consigue evitar o prcticamente todos los fallos de pgina del programa y, como consecuencia, se elimina a a

Prefetch cooperativo entre la JVM y el SO

169

(a) Multiplicacin de matrices: tiempo de ejecucin


700 600

Tiempo (segs.)

tfp soft tfp hard bloqueo peticin seleccin clculo

500 400 300 200 100 0 obligatoria pista sin reaccin pista con reaccin

Comportamiento de las peticiones

(b) Multiplicacin de matrices: peticiones de pginas


3,5E+05

Nmero de pginas

3,0E+05 2,5E+05 2,0E+05 1,5E+05 1,0E+05 5,0E+04 0,0E+00


obligatoria pista sin reaccin pista con reaccin fp soft fp hard carga anticipada

Comportamiento de las peticiones

Figura 6.16 Posibles comportamientos de las peticiones de carga anticipada

el tiempo dedicado a resolver fallos de pgina. Sin embargo, el tiempo de bloqueo que a aparece durante la atencin a las peticiones de prefetch es signicante, lo cual impide un o total solapamiento entre los accesos a disco y el clculo del proceso y limita los benecios a que se pueden obtener del prefetch. Hemos analizado detalladamente las causas que provocan el tiempo de bloqueo, para determinar en qu situaciones era aconsejable cancelar la peticin de prefetch. Los motivos e o de bloqueo que hemos encontrado son dos: la saturacin de la cola de peticiones del o gestor de disco y la escasez de memoria f sica libre durante la reserva de la pgina para a

170

Cap tulo 6

soportar los datos cargados. De hecho, la mayor parte del tiempo de bloqueo es debido a la saturacin de la cola de disco. Por este motivo, decidimos evaluar el comportamiento o de la estrategia de prefetch al cancelar la operacin slo cuando la cola del gestor de disco o o se saturaba. Los resultados de esa evaluacin nos demostraron que esas cancelaciones o no eran sucientes para eliminar el tiempo de bloqueo ya que, entonces, aumentaba la presin sobre la tarea de reserva de memoria y, por lo tanto, aumentaba considerablemente o el tiempo de bloqueo implicado en esa reserva. Por lo tanto, para eliminar el tiempo de bloqueo asociado a las peticiones de prefetch es necesario cancelar las peticiones tanto en el caso de saturacin de disco como en el caso o de saturacin del sistema de reserva de memoria. o Respecto a la alternativa de cancelar las peticiones de forma transparente a la JVM (pista sin reaccin), hay que decir que es la alternativa que peor rendimiento ofrece a la estrategia o de prefetch (ver gura 6.16.a). El motivo es que la ejecucin del benchmark est ejerciendo o a mucha presin sobre el sistema de memoria, con lo cual es necesario cancelar muchas o peticiones de prefetch. Como consecuencia, ms del 25 % de las pginas cargadas con a a antelacin en la opcin de peticin obligatoria pasan a ser fallos de pgina en la ejecucin o o o a o sobre esta alternativa (ver gura 6.16.b). Hay que destacar que la estrategia de prefetch secuencial implementada por Linux tiene un comportamiento similar a esta opcin: si o el sistema se encuentra sobrecargado Linux decide descartar la ejecucin de la carga o anticipada sin considerar posibles reintentos. Por ultimo, la opcin de pista con reaccin es la alternativa que hemos seleccionado como o o parte de la estrategia de prefetch cooperativo ya que es la que ofrece un mejor rendimiento. Esta alternativa coincide con el caso de pista sin reaccin en que ambas consiguen que o las peticiones de prefetch se ejecuten sin ning n tiempo de bloqueo asociado, lo que u permite que las lecturas as ncronas de disco se solapen con el tiempo de clculo del a proceso (ver gura 6.16.a). La diferencia radica en la cantidad de cargas as ncronas que se completan con xito. La opcin de peticin pista con reaccin es capaz de aprovechar las e o o o bajadas momentneas en la carga del sistema para reintentar y completar las operaciones a previamente canceladas, lo cual permite que evite la mayor de fallos de pgina del a a proceso a diferencia de la opcin pista sin reaccin. Hay que decir que los reintentos de o o

Prefetch cooperativo entre la JVM y el SO

171

las operaciones canceladas llevan asociado un aumento en el tiempo dedicado a la tarea de seleccin de pginas, que es ignorable para las otras dos alternativas. Sin embargo, o a este incremento de tiempo de clculo no impide el buen rendimiento de la estrategia de a prefetch al adoptar esta alternativa. Adems, hay que destacar que, como hemos dicho a en la seccin 6.5.3, la implementacin de la gestin del buer de peticiones pendientes se o o o basa en una pol tica FIFO muy simple, por lo que cabe la opcin de que una estrategia o ms sosticada pueda optimizar este tratamiento. a

Alternativas en la actualizacin de la TP o
Como hemos explicado en la seccin 6.5.2, la carga as o ncrona de una pgina no se puede a dar por nalizada hasta que se actualiza la tabla de pginas del proceso, estableciendo la a asociacin entre la pgina lgica y la pgina f o a o a sica y, consiguiendo de esta manera, que los accesos del proceso a esas direcciones se puedan resolver sin provocar fallo de pgina. a Hemos evaluado las dos alternativas que se pueden utilizar para completar este tratamiento y mostramos los resultados de esta evaluacin en la gura 6.17. La primera es imitar el o tratamiento que hace Linux para las pginas cargadas mediante su estrategia de prefetch a secuencial. Este tratamiento consiste en esperar al primer acceso del proceso a una pgina a de prefetch para actualizar su entrada en la tabla de pginas (act. fp en la gura 6.17). a La segunda opcin, que es la que hemos adoptado en el prefetch cooperativo, consiste en o modicar la rutina de atencin al disco para que se encargue de actualizar la entrada de o la tabla de pginas en cuanto la lectura de la pgina concluya (act. int. disco en la gura). a a La gura 6.17.a muestra el tiempo de ejecucin desglosado del benchmark y la gura 6.17.b o muestra los fallos de pgina y el n mero de pginas cargadas con antelacin. Podemos ver, a u a o que para ambas opciones, el n mero de pginas cargadas de forma as u a ncrona es el mismo (carga anticipada en la gura 6.17.b). Sin embargo, el efecto de estas cargas anticipadas sobre el rendimiento del proceso depende de la opcin utilizada para actualizar la tabla de o pginas. Podemos observar que, con la opcin de actualizar la tabla de pginas durante a o a el primer acceso a cada pgina, las operaciones de prefetch no consiguen evitar que el a proceso se ejecute provocando un alto n mero de fallos de pgina de acceso a disco (fp u a hard en la gura 6.17.b). De tal manera que, como se ve en la gura 6.17.a, el tiempo

172

Cap tulo 6

(a) Multiplicacin de matrices: tiempo de ejecucin


1200 1000 tfp soft Tiempo (segs.) 800 600 400 200 0 act. fp act. int. disco tfp hard bloqueo peticin seleccin clculo

Actualizacin tabla de pginas

(b) Multiplicacin de matrices: peticiones de pginas


7,0E+05

Nmero de pginas

6,0E+05 5,0E+05 4,0E+05 3,0E+05 2,0E+05 1,0E+05 0,0E+00 act. fp act. int. disco
fp soft fp hard carga anticipada

Actualizacin tabla de pginas

Figura 6.17 Alternativas para la actualizacin de la tabla de pginas o a

dedicado a resolver fallos de pgina (tfp hard) es seis veces mayor que para la ejecucin a o utilizando la alternativa de actualizar la tabla de pginas al gestionar las interrupciones a de disco. La explicacin a este comportamiento la encontramos en la interaccin con el algoritmo o o de reemplazo de memoria que implementa Linux. Este algoritmo se ejecuta cuando es necesario liberar memoria f sica y selecciona, para enviar al rea de swap, las pginas que a a los procesos no estn usando activamente. En la implementacin que hace la versin de a o o

Prefetch cooperativo entre la JVM y el SO

173

Linux sobre la que hemos desarrollado el prefetch, se asume que las pginas que no se a encuentran ligadas a ninguna tabla de pginas son las candidatas ms adecuadas para a a ser expulsadas al rea de swap. Por lo tanto, si retrasamos el momento de asociar a la a tabla de pginas correspondiente las pginas cargadas por prefetch, estamos aumentando a a la probabilidad de que sean expulsadas de nuevo al rea de swap antes de que el proceso a las referencie. Este efecto, unido a la alta frecuencia con la que es necesario ejecutar el algoritmo de reemplazo cuando la presin sobre el sistema de memoria es alta, explica el o bajo rendimiento de la estrategia de prefetch cuando la actualizacin de la tabla de pginas o a se efect a durante el acceso del proceso. Sin embargo, si en el momento de nalizar la u lectura de disco actualizamos la tabla de pginas correspondiente, entonces esas pginas a a pasan a tener las mismas oportunidades de permanecer en memoria f sica que las pginas a cargadas bajo demanda, consiguiendo as que permanezcan en memoria hasta que el proceso las referencia.

6.6.3

Evaluacin de los benecios del prefetch cooperativo o

En esta seccin presentamos la evaluacin de la estrategia de prefetch cooperativo. Para o o ello, hemos ejecutado varios n cleos de clculo y aplicaciones sobre el entorno de ejecuu a cin que ofrece Linux por defecto y sobre le entorno modicado con nuestra estrategia. o Recordemos que hemos desactivado el prefetch de Linux para las ejecuciones de los benchmarks sobre el entorno con nuestra estrategia. Por otro lado, para evaluar la inuencia que tiene la estrategia de prefetch de Linux sobre el rendimiento del entorno original de ejecucin, hemos ejecutado los benchmarks tambin sobre el entorno original desactivando o e su estrategia de prefetch. Durante la evaluacin de la estrategia de prefetch hemos querido aislar la inuencia que o puede tener sobre su rendimiento la heur stica que utilizamos para automatizar el clculo a de la distancia de prefetch. Por este motivo, hemos hecho un primer grupo de experimentos utilizando como distancia de prefetch un valor determinado experimentalmente. En el segundo grupo de experimentos utilizamos la distancia obtenida de forma automtica en a tiempo de ejecucin, de manera que podemos evaluar la ecacia de la heur o stica que hemos implementado.

174

Cap tulo 6

Benchmarks
Adems del kernel de multiplicacin de matrices, que hemos utilizado para validar las a o decisiones de dise o, utilizamos algunos benchmarks de los suministrados como parte del n conjunto de programas de prueba JavaGrande [BSW+ 00] y como parte del conjunto de programas Java NAS [FSJY03]. En la seccin 6.6.2 hemos descrito las caracter o sticas del kernel de multiplicacin de matrio ces. Por otra parte, en la seccin 3.1.1 del cap o tulo 3 se puede encontrar una descripcin de o los benchmarks de JavaGrande que vamos a utilizar, de los que seleccionamos unicamente aquellos que se pueden ver afectados por nuestra estrategia de prefetch, es decir, los que utilizan arrays de grandes dimensiones. Respecto al conjunto de programas Java NAS hemos seleccionado el kernel RHS. Se trata de una rutina usada por los programas SP y BT, que forman parte de los programas suministrados como parte de los Java NAS. Esta rutina calcula el vector del lado derecho de un sistema de ecuaciones. Hemos seleccionado la versin clase B, que requiere 128Mb o para albergar todo el conjunto de datos. Todos estos datos estn organizados en una serie a de arrays que la rutina RHS utiliza con un patrn de accesos strided. Para ejecutar este o programa, arrancamos la mquina limitando su tama o de memoria f a n sica a 128Mb. La tabla 6.3 resume las principales caracter sticas de los experimentos que realizamos.
Programas Multiplicacion de matrices RHS Clase B Crypt SizeC Sparse SizeC FFT SizeA HeapSort SizeC Memoria Boot 128Mb 128Mb 64Mb 32Mb 32Mb 64Mb Memoria arrays grandes 336Mb 185Mb 143,05Mb 45,75Mb 32Mb 95,37Mb Tipos de acceso Strided (3 niveles) Strided (3 niveles) Secuencial Aleatorio y secuencial Strided dinmico (3 niveles) a Strided y aleatorio

Tabla 6.3 Resumen de las caracter sticas de los experimentos

Prefetch cooperativo entre la JVM y el SO

175

Resultados de los experimentos con distancia de prefetch manual


En esta seccin comparamos los resultados que hemos obtenido al ejecutar los bencho marks sobre el prefetch cooperativo (Prefetch cooperativo) y sobre el entorno original de ejecucin tanto con el comportamiento por defecto que ofrece Linux (Entorno original o (prefetch kernel)) como desactivando el prefetch de Linux (Entorno original (sin prefetch kernel)). En la ejecucin sobre el prefetch cooperativo, la distancia de prefetch que utilio zamos la hemos decidido de forma experimental y se aplica el mismo valor para todas las instrucciones. Los resultados de los experimentos que hemos realizado se muestran desde la gura 6.18 hasta la gura 6.23. En estas guras presentamos tanto el tiempo de ejecucin de los o programas como las peticiones de acceso al rea de swap. Hemos desglosado el tiempo de a ejecucin distinguiendo el tiempo dedicado a resolver fallos de pgina de acceso a disco o a (tfp hard), el tiempo dedicado a resolver fallos de pgina que no requieren de ese acceso a (tfp soft) y el resto de tiempo del programa (clculo) que incluye tambin el dedicado a e a la tarea de seleccin de pginas. Hay que destacar que hemos obviado el tiempo de o a bloqueo debido a las peticiones de prefetch, porque es nulo para la implementacin de o estas peticiones que hemos seleccionado. En cuanto a las peticiones de acceso al rea de a swap, distinguimos entre las debidas a peticiones de carga as ncrona (carga anticipada), las debidas a fallos de pgina que realmente requieren esa lectura (fp hard), y las debidas a a fallos de pgina que se pueden resolver sin ese acceso (fp soft). a El primer aspecto a destacar es que todos estos benchmarks sobrecargan el sistema de memoria virtual. Por este motivo, en cuanto Linux detecta esta sobrecarga, decide desactivar su estrategia de prefetch independientemente de la conguracin decidida por el o administrador de la mquina. Esto explica que el comportamiento de los benchmarks en a el entorno original, tanto con la conguracin por defecto como con el prefetch de Linux o desactivado, sea muy similar. En la gura 6.18 mostramos los resultados de la ejecucin de la multiplicacion de o matrices, ejecutada sobre 128Mb de memoria y con una distancia de un working set.

176

Cap tulo 6

(a) Multiplicacin de matrices: tiempo de ejecucin


1,2E+05

Tiempo (segs.)

9,6E+04 7,2E+04 4,8E+04 2,4E+04 0,0E+00 Entorno original (prefetch kernel) Entorno original (sin prefetch kernel) Prefetch cooperativo

tfp soft tfp hard clculo

Entorno de ejecucin

(b) Multiplicacin de matrices: peticiones de pginas

Nmero de pginas

8,0E+07 6,0E+07 4,0E+07 2,0E+07 0,0E+00 Entorno original Entorno original (sin prefetch (prefetch kernel) kernel) Prefetch cooperativo fp soft fp hard carga anticipada

Entorno de ejecucin

Figura 6.18 Resultados de la multiplicacion de matrices

La gura 6.18.a muestra el tiempo de ejecucin y la gura 6.18.b muestra las peticiones o de acceso al rea de swap. Podemos observar que las pginas cargadas con antelacin a a o con el prefetch cooperativo evitan la mayor de fallos de pgina de la aplicacin (ver a a o gura 6.18.b). Como consecuencia, en la gura 6.18.a se puede ver que el rendimiento del programa ejecutado sobre nuestro entorno mejora alrededor de un 22 % comparado con el obtenido sobre el entorno original de Linux. Hay que destacar que usando prefetch cooperativo, aunque el n mero de fallos de pgina hard se puede ignorar, el tiempo necesario u a para resolverlos a n representa alrededor de un 35 % del tiempo total de ejecucin del u o benchmark. Esto signica que el tiempo medio de fallo de pgina aumenta considerablea

Prefetch cooperativo entre la JVM y el SO

177

mente. Este incremento se debe a que la ejecucin con el prefetch cooperativo aumenta o el n mero de peticiones acumuladas en la cola del gestor de disco, con lo que tambin u e aumenta el tiempo de respuesta del gestor a esas peticiones y, por lo tanto, el tiempo que pasa desde que el proceso provoca el fallo de pgina hasta que el gestor es capaz a de completar la lectura de los datos solicitados. Por este motivo, para conseguir que la estrategia de prefetch sea ecaz es muy importante conseguir eliminar la mayor de los a fallos de pgina, ya que la penalizacin sobre el rendimiento de los que no se evitan es a o muy alta. En las guras 6.19.a y 6.19.b mostramos los resultados de la ejecucin de RHS. La cantio dad de memoria f sica utilizada es de 128Mb y, para el prefetch cooperativo se ha utilizado un valor de distancia de prefetch de 32 pginas. En la gura 6.19.b se observa que el prea fetch cooperativo es capaz de eliminar la mayor de los fallos de pgina de acceso a disco a a que el programa genera durante su ejecucin en el entorno original. Sin embargo, aparece o un incremento en la cantidad de fallos de pgina soft, debido a las pginas solicitadas a a con antelacin cuya carga no es posible completar antes de que el proceso las referencie. o A pesar de este incremento, hay que destacar que el tiempo dedicado a resolver fallos de pgina, considerando tanto los fallos de pgina hard como los soft, es menos de la mitad a a que el necesario para resolver los fallos de pgina en el entorno original de Linux (ver a gura 6.19.a). Esta importante reduccin en el tiempo de resolucin de fallo de pgina se o o a reeja tambin en una mejora del rendimiento global del programa alrededor del 40 % con e respecto al rendimiento obtenido en el entorno original de ejecucin (ver gura 6.19.a). o Los resultados de la ejecucin de Crypt se muestran en las guras 6.20.a y 6.20.b. Este o experimento se ha realizado utilizando 64Mb de memoria f sica y con una distancia de prefetch para el prefetch cooperativo es de 128 pginas. a En la gura 6.20.a podemos comparar los resultados de la ejecucin sobre el entorno orio ginal de ejecucin y sobre el entorno modicado con el prefetch cooperativo. Podemos o observar que la ejecucin con el prefetch cooperativo reduce en un 73,2 % el tiempo deo dicado a resolver fallos de pgina, lo cual involucra una mejora en el rendimiento global a de un 13,11 % con respecto a la ejecucin en el entorno original de Linux. Hay que tener o en cuenta que este programa, ejecutado sobre el entorno original, dedica slo un 18 % de o

178

Cap tulo 6

(a) RHS (NAS claseB): tiempo de ejecucin


300 Tiempo (segs.) 250 200 150 100 50 0 Entorno original Entorno original (prefetch kernel) (sin prefetch kernel) Prefetch cooperativo tfp soft tfp hard prediction

Entorno de ejecucin

(b) RHS (NAS claseB): peticiones de pginas


Nmero de pginas
1,8E+05 1,4E+05 9,0E+04 4,5E+04 0,0E+00 Entorno original Entorno original (sin prefetch (prefetch kernel) kernel) Prefetch cooperativo fp soft fp hard carga anticipada

Entorno de ejecucin

Figura 6.19 Resultados de RHS

su tiempo total de ejecucin a la resolucin de fallos de pgina. Por este motivo, aunque o o a nuestra estrategia de prefetch consigue una reduccin muy importante en el tiempo de o fallo de pgina, el impacto de esta reduccin sobre el tiempo total de ejecucin no es tan a o o signicativo. En la gura 6.20.b podemos comprobar que el prefetch cooperativo elimina ms del 97 % de los fallos de pgina provocados por el programa en el entorno original de a a ejecucin. Tambin podemos observar, que tal y como ocurr en el caso de la ejecucin o e a o de RHS, se incrementan el n mero de fallos de pgina soft, aunque esto no impide que u a la reduccin del tiempo de fallo de pgina sea importante. o a

Prefetch cooperativo entre la JVM y el SO

179

(a) Crypt (JavaGrande SizeC): tiempo de ejecucin


180

Tiempo (segs.)

150 120 90 60 30 0 Entorno original Entorno original (prefetch kernel) (sin prefetch kernel) Prefetch cooperativo

tfp soft tfp hard clculo

Entorno de ejecucin

(b) Crypt (JavaGrande SizeC): peticiones de pginas

Nmero de pginas

8,0E+04 6,0E+04 4,0E+04 2,0E+04 0,0E+00 Entorno original Entorno original (sin prefetch (prefetch kernel) kernel) Prefetch cooperativo fp soft fp hard carga anticipada

Entorno de ejecucin

Figura 6.20 Resultados de Crypt

En la gura 6.21 mostramos los resultados de la ejecucin del benchmark Sparse, ejecuo tado sobre 32Mb de memoria f sica y utilizando una distancia de prefetch de 64 pginas a en el prefetch cooperativo. En la gura 6.21.a podemos ver el tiempo de ejecucin del benchmark, y se observa que o el prefetch cooperativo consigue una mejora del 24,4 % sobre el tiempo de ejecucin obo tenido en el entorno original de ejecucin. Hay que decir que, a pesar de esta mejora del o rendimiento, el tiempo de fallo de pgina sigue siendo considerable. Este tiempo de fallo a de pgina se debe, en su mayor parte, a que el sistema no es capaz de cargar con la sua

180

Cap tulo 6

(a) Sparse (JavaGrande SizeC): tiempo de ejecucin


2000

Tiempo (segs.)

1500 1000 500 0 Entorno original Entorno original (prefetch kernel) (sin prefetch kernel) Prefetch cooperativo

tfp soft tfp hard clculo

Entorno de ejecucin

(b) Sparse (JavaGrande SizeC): peticiones de pginas


2,0E+06 1,5E+06 1,0E+06 5,0E+05 0,0E+00 Entorno original Entorno original (prefetch kernel) (sin prefetch kernel) Prefetch cooperativo fp soft fp hard carga anticipada

Nmero de pginas

Entorno de ejecucin

Figura 6.21 Resultados de Sparse

ciente antelacin las pginas solicitadas as o a ncronamente, con lo que slo se consigue un o solapamiento parcial entre tiempo de acceso a disco y tiempo de clculo. La explicacin a o a este comportamiento la encontramos en el bajo porcentaje de tiempo de clculo del a programa, que representa slo un 18,4 % del tiempo total de ejecucin, y que limita el o o grado de solapamiento alcanzable por el prefetch de memoria. Por otro lado, en la gura 6.21.b podemos ver que la mayor de accesos que involucran fallos de pgina en el entora a no original de ejecucin son solicitados anticipadamente por el prefetch cooperativo, de o manera que se eliminan el 97,7 % de los fallos de pgina hard. Los fallos de pgina hard a a que no se pueden evitar son los debidos a los accesos aleatorios que ejecuta este programa

Prefetch cooperativo entre la JVM y el SO

181

y que, por lo tanto, son impredecibles. Tenemos que remarcar que la estrategia de prefetch cooperativo es capaz de detectar este comportamiento y se desactiva para aquellas instrucciones impredecibles, evitando de esta manera la sobrecarga de ejecutar un cdigo o que no puede beneciar su rendimiento. En la gura 6.22 mostramos el resultado de ejecutar el benchmark FFT. La cantidad de memoria f sica sobre la que se ha ejecutado este experimento es 32Mb y la distancia usada por el prefetch cooperativo es 8 pginas. La gura 6.22.a muestra el tiempo de ejecucin. a o La primera cosa a destacar es que el tiempo de clculo de este benchmark representa slo a o un 0,35 % del tiempo total de ejecucin. Esto signica que esta aplicacin ofrece muy o o pocas posibilidades para solapar tiempo de carga de disco y tiempo de clculo, y, por lo a tanto, es dif mejorar su rendimiento usando la tcnica de prefetch. Por este motivo, el cil e prefetch cooperativo se comporta de forma muy parecida al comportamiento por defecto del entorno original. En este punto hay que destacar que el tiempo de clculo debido a a la tarea de seleccin no es signicativo, como se puede observar comparando el tiempo o de ejecucin en el entorno original y el tiempo de ejecucin sobre el entorno modicado o o con el prefetch cooperativo. Sin embargo, en la gura 6.22.b se puede comprobar que el prefetch cooperativo es capaz de evitar alrededor de un 55 % de los fallos de pgina que a provoca el programa en su ejecucin sobre el entorno original. Esta alta tasa de aciertos o en las predicciones, sin un aumento signicativo del tiempo de clculo, es especialmente a destacable porque este programa utiliza un patrn de accesos complejo que, aunque se o basa en el uso de strides, utiliza varios valores de stride que cambian a lo largo de la ejecucin. Por tanto, este resultado anima a pensar que otras aplicaciones con patrones o de acceso complejos pero con un relacin mejor balanceada entre tiempo de clculo y o a tiempo dedicado a accesos a disco, tambin pueden mejorar su rendimiento si se ejecutan e usando el prefetch cooperativo Por ultimo, en la gura 6.23 mostramos los resultados de ejecutar el benchmark Heap Sort. La cantidad de memoria f sica sobre la que se ha ejecutado este experimento es 64Mb. Recordemos que el comportamiento de este benchmark es prcticamente por coma pleto aleatorio, ya que el n mero de ejecuciones de las instrucciones con acceso strided u es muy bajo comparado con el n mero total de instrucciones ejecutadas. Por lo tanto, u

182

Cap tulo 6

(a) FFT (JavaGrande SizeA): tiempo de ejecucin


35000

Tiempo (segs.)

28000 21000 14000 7000 0 Entorno original Entorno original (sin prefetch (prefetch kernel) kernel) Prefetch cooperativo

tfp soft tfp hard clculo

Entorno de ejecucin

(b) FFT (JavaGrande SizeA): peticiones de pginas

Nmero de pginas

1,2E+07 9,0E+06 6,0E+06 3,0E+06 0,0E+00 Entorno original Entorno original (sin prefetch (prefetch kernel) kernel) Prefetch cooperativo fp soft fp hard carga anticipada

Entorno de ejecucin

Figura 6.22 Resultados de FFT

como nuestra estrategia de prefetch detecta esta situacin y se desactiva, el resultado de o la ejecucin es equivalente para ambos entornos de ejecucin (ver gura 6.23). o o

Efectos de la automatizacin de la distancia o


En la seccin anterior hemos presentado la evaluacin de la estrategia de prefetch, utilio o zando como distancia de prefetch para cada benchmark el mejor valor que hemos obtenido experimentalmente. En esta seccin mostramos qu inuencia tiene sobre el rendimiento o e

Prefetch cooperativo entre la JVM y el SO

183

(a) HeapSort (JavaGrande SizeC): tiempo de ejecucin


6000
>60 horas >60 horas >60 horas

Tiempo (segs.)

4000

tfp soft tfp hard clculo

2000

0 Entorno original Entorno original (sin prefetch (prefetch kernel) kernel) Prefetch cooperativo

Entorno de ejecucin

(b) HeapSort (JavaGrande SizeC): peticiones de pginas


Nmero de pginas
9,0E+06 fp soft fp hard carga anticipada

6,0E+06

3,0E+06

0,0E+00 Entorno original Entorno original (sin prefetch (prefetch kernel) kernel) Prefetch cooperativo

Entorno de ejecucin

Figura 6.23 Resultados de HeapSort

de los programas la incorporacin en la estrategia del clculo automtico de la distancia o a a de prefetch. Antes de iniciar el anlisis es conveniente aclarar que para la implementacin de la esa o trategia que utiliza la distancia de prefetch recibida como parmetro, este valor se aplica a por igual a todas las instrucciones para las que se utiliza prefetch, sin tener en cuenta las posibles particularidades de cada una de ellas. Por lo tanto, aunque el valor que hemos seleccionado para cada programa es el que ofrec mejores resultados no se garantiza a

184

Cap tulo 6

que este resultado no se pueda mejorar si se permite utilizar una distancia para cada instruccin, como ocurre en la estrategia con distancia automatizada. o En las guras 6.24, 6.25 y 6.26 comparamos el rendimiento de los programas ejecutados sobre el entorno original, tanto con la conguracin por defecto (Entorno original (preo fetch kernel)) como con el prefetch de Linux desactivado (Entorno original (sin prefetch kernel)), y sobre la estrategia de prefetch cooperativo, cuando la distancia de prefetch es un parmetro de la ejecucin (Prefetch cooperativo (dist. manual))y cuando se calcula la a o distancia adecuada para cada instruccin (Prefetch cooperativo (dist. aut.)). Para cada o uno de los benchmarks mostramos el tiempo de ejecucin distinguiendo entre el tiempo o dedicado a resolver fallos de pgina hard (tfp hard), fallos de pgina soft (tfp soft) y el a a resto del tiempo del programa (clculo). a Mostramos los resultados de aquellos benchmarks que se pueden ver afectados por esta automatizacin del clculo. Es decir, todos los programas excepto la multiplicacion de o a matrices, que como utiliza el patrn simplicado basado en working sets las predicciones o asociadas a sus instrucciones se reeren siempre al siguiente working set, HeapSort, que como utiliza un patrn de accesos aleatorio desactiva la estrategia de prefetch, y fft, o cuyo porcentaje de tiempo de clculo no es suciente para poder solapar la carga de sus a pginas. a En la gura 6.24 mostramos los resultados de la ejecucin de rhs. Podemos observar o que la automatizacin del clculo de la distancia aumenta el rendimiento de la estrategia o a de prefetch ya que es capaz de disminuir a n ms el tiempo dedicado a resolver fallos u a de pgina hard. Esto se debe a la exibilidad que da poder tener diferentes distancias a para cada instruccin, ya que es posible adaptar ese valor a las necesidades del prefetch o asociado a cada una. As el clculo experimental para las distancias globales nos hab , a a llevado a seleccionar como parmetro una distancia de 32 pginas. Mientras que el clculo a a a automatizado selecciona diferentes distancias para diferentes instrucciones en un rango que va desde 16 pginas hasta 256. Como consecuencia, la estrategia de prefetch coopea rativo con distancias calculadas automticamente mejora el rendimiento del benchmark a alrededor de un 43,03 % si se compara con su ejecucin en el entorno original. o

Prefetch cooperativo entre la JVM y el SO

185

RHS (NAS classB): tiempo de ejecucin


300

Tiempo (segs.)

250 200 150 100 50 0 Entorno original (prefetch kernel) Entorno original (sin prefetch kernel) Prefetch cooperativo (dist. manual) Prefetch cooperativo (dist. aut.) tfp soft tfp hard clculo

Entorno de ejecucin

Figura 6.24 Inuencia de la automatizacin de la distancia para rhs o

Las guras 6.25 y 6.26 muestran, respectivamente, los resultados para la ejecucin de o crypt y de sparse. Podemos comprobar que el efecto de incluir la automatizacin de la o distancia es similar para los dos benchmarks. En ambos casos, la estrategia de prefetch sigue mejorando el rendimiento del entorno original de Linux, tanto si se utiliza la conguracin por defecto como si se desactiva el prefetch de Linux. As la estrategia con o , distancia automtica mejora el rendimiento obtenido en el entorno original alrededor de a un 10,29 %, para el caso de Crypt y alrededor de un 20,12 % para el caso de Sparse. Sin embargo esta mejora es ligeramente inferior a la que obtenemos seleccionando la distancia experimentalmente. Si comparamos el resultado de las dos implementaciones de la estrategia de prefetch podemos ver que, para estos dos benchmarks, el uso de la distancia automtica y a nivel de instruccin es capaz de reducir el tiempo dedicado a resolver a o fallos de pgina hard. Sin embargo, aumenta el tiempo necesario para resolver fallos de a pgina soft, debidos a accesos a pginas en trnsito, ya que, las caracter a a a sticas de estos benchmarks, impiden que el sistema logre cargar a tiempo las pginas solicitadas. a Hay que remarcar que esta ligera disminucin del rendimiento al automatizar la distancia o no impide que la estrategia de prefetch cooperativo siga mejorando, de manera signicativa, el rendimiento ofrecido por el entorno original de Linux. Adems, esta mejora sigue a

186

Cap tulo 6

estando muy cerca del mximo benecio terico que una estrategia de prefetch puede a o ofrecer a unos programas con el comportamiento de crypt y sparse.
Crypt (JavaGrande SizeC): tiempo de ejecucin
200

Tiempo (segs.)

150
tfp soft

100 50 0 Entorno original (prefetch kernel) Entorno original (sin prefetch kernel) Prefetch cooperativo (dist. manual) Prefetch cooperativo (dist. aut.)

tfp hard clculo

Entorno de ejecucin

Figura 6.25 Inuencia de la automatizacin de la distancia para crypt o

Sparse (JavaGrande SizeC): tiempo de ejecucin


2000

Tiempo (segs.)

1500 1000 500 0 Entorno original (prefetch kernel) Entorno original (sin prefetch kernel) Prefetch Prefetch cooperativo cooperativo (dist. manual) (dist. aut.)

tfp soft tfp hard clculo

Entorno de ejecucin

Figura 6.26 Inuencia de la automatizacin de la distancia para sparse o

Por lo tanto, estos experimentos demuestran que es posible que la JVM calcule, en tiempo de ejecucin, la distancia de prefetch adecuada para las peticiones de cada instruccin, o o adaptando este valor a las condiciones de ejecucin. Hay que destacar que, aunque en o

Prefetch cooperativo entre la JVM y el SO

187

algunos casos el rendimiento no alcance el obtenido por el valor calculado de forma experimental, la disminucin del rendimiento es muy baja y est ampliamente compensada o a por los benecios que supone para el usuario el clculo automtico de ese valor. a a

6.6.4

Conclusiones de la evaluacin o

En esta seccin hemos presentado los resultados de la evaluacin del prefetch cooperao o tivo. En primer lugar, describimos los experimentos en los que hemos apoyado nuestras decisiones de dise o e implementacin. En segundo lugar, comparamos la ejecucin de n o o algunas aplicaciones sobre el entorno original de ejecucin y sobre el entorno modicado o con nuestra estrategia de prefetch cooperativo. El prefetch cooperativo ha demostrado ser una estrategia ecaz, capaz de mejorar el rendimiento que obtiene la ejecucin de los benchmarks sobre el entorno original de ejecucin, o o cuando las caracter sticas de los programas los hacen susceptibles de ser mejorados a travs del prefetch. Esta mejora se consigue por varios motivos: e

La JVM es capaz de captar los patrones de acceso de las instrucciones que tienen un comportamiento regular y usarlo para aplicar una prediccin espec o ca para cada una de ellas. De hecho, es capaz de captar patrones complejos, como lo demuestra la alta tasa de aciertos que se obtiene en la ejecucin del programa FFT. Con esta prediccin o o precisa se puede implementar un prefetch ms ecaz que el resultante de la prediccin a o simple que aplica el kernel de Linux en el entorno original, que slo puede beneciar o a las aplicaciones que acceden de forma secuencial. La JVM tambin es capaz de detectar qu instrucciones no tienen un comportamiento e e predecible, y desactivar el prefetch unicamente para esas instrucciones. De esta manera se elimina la sobrecarga que se tendr al cargar en memoria pginas seleccionadas a a de forma equivocada, pero se permite que el resto de instrucciones del programa con patrn predecible se benecien del uso del prefetch. Se puede comprobar los benecios o de este comportamiento en el rendimiento que obtiene el programa Sparse. El prefetch cooperativo es capaz de sacar ms rendimiento del sistema en situacioa nes de alta presin. En estas situaciones la estrategia de prefetch del entorno original o

188

Cap tulo 6

simplemente descarta las peticiones de prefetch. En el caso del prefetch cooperativo tambin se cancelan para no perjudicar el rendimiento del programa, pero se aprovee chan los momentos en los que esta carga baja para reintentar de nuevo las solicitudes de prefetch, consiguiendo completar con xito un alto porcentaje de ellas. Por este e motivo, incluso para aquellos programas que siguen el patrn de accesos secuencial o como Crypt, el prefetch cooperativo supera el rendimiento del prefetch secuencial que se intenta aplicar en el entorno original de Linux. Adems, el incremento de tiempo de clculo debido a la ejecucin del prefetch cooa a o perativo es asumible por las aplicaciones, dado el alto porcentaje de mejora que se obtiene con la carga anticipada de las pginas accedidas. a

Hay que destacar que el porcentaje de la mejora obtenida para cada programa depende de la relacin que haya entre tiempo de clculo y tiempo dedicado a resolver fallos de o a pgina. a Si el tiempo de clculo del proceso es muy bajo comparado con el tiempo de fallo de pgina, a a entonces se reducen las posibilidades de poder solapar el tiempo de carga anticipada con el tiempo de clculo del programa. Por ejemplo, en el caso del benchmark Sparse, aunque el a prefetch cooperativo elimina casi el 97 % de sus fallos de pgina hard, la mejora obtenida a en el rendimiento no pasa del 24,4 %, ya que el programa no dispone de ms tiempo de a clculo para solapar las cargas anticipadas. El caso extremo de esta situacin lo tenemos a o en la ejecucin del programa FFT, que slo dedica un 0,35 % de su tiempo a clculo y o o a por lo tanto no da opcin a solapar el tiempo de acceso a disco. A pesar de ello, hay que o decir que con este comportamiento del programa tan poco favorable para usar prefetch, la ejecucin del programa sobre el entorno con prefetch cooperativo tiene un rendimiento o equivalente al que se obtiene sobre el entorno original de ejecucin. o Por otro lado, si el porcentaje de tiempo de fallo de pgina es mucho menor que el a porcentaje de tiempo de clculo, entonces, aunque la estrategia de prefetch consiga reducir a gran parte del fallo de pgina la repercusin sobre el rendimiento total no tendr un a o a impacto equivalente. Es lo que sucede en el caso de la aplicacin Crypt que dedica slo o o un 18 % de su tiempo a resolver fallos de pgina, por lo que la reduccin del 73 % que la a o

Prefetch cooperativo entre la JVM y el SO

189

estrategia de prefetch consigue sobre su tiempo de fallo de pgina se corresponde con un a 13,11 % de mejora sobre el rendimiento global del programa. De esta manera, en funcin de las caracter o sticas del programa, el uso de la estrategia de prefetch cooperativo consigue mejorar el rendimiento hasta un 40 %, para el caso de RHS, pasando por un 24,4 % para Sparse, un 22 % para la Multiplicacion de matrices y un 13,11 % para Crypt, y consigue no empeorarlo para aquellos programas cuyo rendimiento no es mejorable utilizando una tcnica de prefetch de pginas como ocurre con FFT o e a HeapSort. En cuanto a la automatizacin del clculo de la distancia, hemos demostrado que es o a posible que la JVM realice este clculo de forma automtica, ajustndolo de acuerdo a a a a los cambios en las condiciones de ejecucin, con un coste asociado totalmente ignorable, o si se compara con las ventajas que tiene para el usuario la automatizacin del clculo de o a ese parmetro. a

6.7

COOPERACION ENTRE JVM Y EL SO: LA BASE PARA UNA ESTRATEGIA DE PREFETCH ESTABLE Y EFICAZ

En este cap tulo hemos presentado el dise o y la implementacin de la estrategia de n o prefetch cooperativo que hemos a adido al entorno de ejecucin de Java. n o Esta estrategia se basa en utilizar tanto el conocimiento de la JVM sobre el comportamiento del programa como el conocimiento del SO sobre las condiciones de ejecucin del o sistema, para tomar las decisiones de prefetch ms adecuadas para mejorar el rendimiento a del programa. La JVM selecciona las pginas que se deben cargar con antelacin, usando a o la informacin que ella tiene sobre el programa y la que exporta el SO sobre el estado de o la mquina, y solicita al SO la carga as a ncrona esas pginas. El SO por su parte, efect a a u las operaciones de carga, slo si las condiciones de ejecucin son favorables. o o

190

Cap tulo 6

De esta manera, se consigue una tcnica de prefetch que iguala las ventajas que ofrec la e a estrategia transparente al SO (que describimos en el cap tulo 5). Pero, adems, consigue a superar sus limitaciones involucrando al SO en la toma de decisiones, ya que constituye un mecanismo ms estable y es capaz de explotar mejor los recursos del sistema en situaciones a de alta presin. o Es decir, conseguimos una estrategia que cumple todos los requerimientos necesarios para que el prefetch sea ecaz:

Predice de forma precisa las prximas referencias a memoria de las instrucciones. o Respeta la portabilidad de los programas Java. Es transparente al programador y al usuario. Respeta la abilidad del sistema.

Pero adems, con la participacin del SO en las decisiones de prefetch: a o

No es necesario utilizar heur sticas para aproximar el estado de la mquina, ya que el a SO exporta al nivel de usuario la informacin sobre ese estado que permite optimizar o la seleccin de pginas de prefetch. o a Se puede utilizar un interfaz dedicado para la solicitud de carga por prefetch, de manera que: El SO puede gestionar estas solicitudes de forma diferente al resto de accesos a disco. Esto le permite, por ejemplo, descartar las operaciones de prefetch si el sistema de memoria est sobrecargado y, por lo tanto, completar esas operaciones a puede empeorar el rendimiento del programa. El SO puede controlar la interaccin de las operaciones de carga anticipada con o el resto de tareas de gestin de memoria implementadas por el SO. o La JVM puede agrupar varias solicitudes de prefetch, dando opcin al SO a o optimizar los accesos a disco involucrados.

Prefetch cooperativo entre la JVM y el SO

191

la JVM puede reintentar las operaciones de prefetch canceladas, al detectar que las condiciones de ejecucin son ms favorables si todav es posible mejorar el o a a rendimiento de la instruccin mediante su carga anticipada. o Se simplica el cdigo de prefetch ejecutado en el nivel de usuario, lo cual reduce o el impacto que las decisiones de gestin del SO puede tener sobre el rendimiento de o ese cdigo. Recordemos que la estrategia de prefetch transparente al SO requiere un o nuevo ujo de ejecucin que se encarga de solicitar la carga anticipada. Por lo tanto, el o rendimiento de la estrategia depende de las decisiones de gestin que el SO tome sobre o la ejecucin de ese ujo, que, adems pueden depender de detalles de implementacin o a o de la versin de kernel instalada en la mquina. o a

Por lo tanto, la cooperacin entre la JVM y el SO permite implementar un prefetch o ecaz, mediante un mecanismo estable, capaz de adaptarse tanto a las caracter sticas del programa como a las condiciones de ejecucin para mejorar de una forma considerable el o rendimiento de los programas.

7
TRABAJO RELACIONADO

En este cap tulo presentamos el trabajo relacionado con los aspectos desarrollados en nuestro trabajo. Para ello distinguimos tres grandes grupos. El primer grupo es el relacionado con la evaluacin del uso de la memoria que hacen los programas Java, primer paso o necesario para hacer las propuestas de mejora de su gestin. El segundo grupo se reere o a los trabajos que intentan mejorar el rendimiento de la gestin de memoria de la platao forma de ejecucin de Java. Por ultimo, el tercer grupo engloba las estrategias orientadas o a ofrecer a los programas una gestin de recursos espec o ca para su comportamiento.

7.1

EVALUACION DEL USO DE LA MEMORIA

Existen muchos trabajos que estudian cada una de las tareas de gestin de memoria por o separado: memoria virtual, reserva de memoria lgica y liberacin de memoria lgica. Sin o o o embargo, la mayor parte de estos trabajos se han hecho para otros entornos de ejecucin o y no para Java. Hay que tener en cuenta que el rendimiento de la gestin de memoria o depende en gran medida de los patrones de acceso de los programas, y estos patrones estn muy relacionados con las caracter a sticas del lenguaje. Por este motivo, era necesario evaluar el rendimiento de estas tareas en el entorno de ejecucin de Java. o A continuacin describimos algunos de los trabajos que han analizado el comportamiento o de los programas Java y las diferencias que existen entre estos trabajos y la evaluacin o que hemos presentado en este trabajo.

193

194

Cap tulo 7

Kim y Hsu han estudiado la interaccin que hay entre las memoria cache y los programas o Java, cuando se ejecutan utilizando compilacin en tiempo de ejecucin (Just In Time o o Compiler) [KH00]. Adems en este trabajo estudian la inuencia que puede tener el taa ma o inicial del heap sobre el rendimiento de la memoria cache, y mencionan que este n tama o puede inuir tambin sobre el rendimiento de la memoria virtual. n e Li et. al. tambin analizan la ejecucin sobre compiladores al vuelo [LJNS01]. Su trabajo e o se centra en entender la actividad del SO durante la ejecucin de programas Java. En esta o actividad se incluye la gestin de la memoria virtual y, por lo tanto, tambin cuantican o e el tiempo invertido en esta gestin. Sin embargo, no distinguen entre el tiempo debido al o cdigo del programa y el tiempo debido al cdigo de gestin de la JVM. o o o El estudio de Dieckmann y Hlzle [DH99] estaba orientado a ayudar a los implementadores o de garbage collectors, y mostraba el tipo de objetos que los programas Java reservan as como la distribucin en el tiempo de esas reservas. o La evaluacin que presentamos en este trabajo consiste en un anlisis completo del rendio a miento de la memoria virtual, inexistente hasta el momento. En este anlisis aislamos la a zona del espacio de direcciones ms afectada por el uso de la memoria virtual y separamos a la sobrecarga debida al cdigo del programa de la debida al cdigo de gestin de la JVM. o o o Adems, los estudios previos sobre el comportamiento de los programas Java se han hecho a sobre los programas del conjunto SPECjvm98 [SPE98]. Este conjunto de programas de pruebas, aunque realizan numerosos accesos a memoria y, por lo tanto, hacen un uso intensivo de memoria, tienen un working set peque o, que requiere muy poca memoria n f sica. Dieckmann y Hlzle mostraron que estos programas se pueden ejecutar sobre un o heap de tama o menor que 8Mb. Esto signica que durante su ejecucin no necesitan la n o intervencin de la gestin de memoria virtual y que el porcentaje de tiempo dedicado a o o resolver fallos de pgina es ignorable comparado con el tiempo de clculo de los programas. a a Sin embargo, los programas de prueba que hemos utilizado en la evaluacin que preo sentamos son parte del conjunto de programas de prueba suministrado por el grupo de trabajo JavaGrande (ver seccin 3.1.1 del cap o tulo 3). Estos programas tienen working

Trabajo Relacionado

195

sets mayores que requieren de una mayor cantidad de memoria f sica y, por lo tanto, se ven afectados por la ejecucin de la gestin de memoria virtual. o o

7.2

GESTION DE MEMORIA EN JAVA

A medida que la popularidad de Java ha ido creciendo y se han diversicado los programas que utilizan su plataforma de ejecucin, ha aumentado la preocupacin por el rendimiento o o ofrecido por su gestin de memoria. Por este motivo, han aparecido numerosos estudios o dedicados a mejorar este rendimiento. As podemos encontrar propuestas para que la gestin del espacio lgico que implementa , o o la JVM respete la localidad de referencia de los programas. Por ejemplo, hay propuestas de algoritmos de garbage collection que al gestionar los objetos supervivientes no alteran la localidad de los datos [Boe00, SGBS02]; tambin hay propuestas que durante la asignacin e o de memoria a los objetos creados intentan tanto favorecer la localidad de referencia como disminuir el tiempo dedicado a cada ejecucin del garbage collector [SGBS02, SGF+ 02, o SZ98]. Fuera del mbito de la gestin del espacio direcciones, tambin encontramos propuestas a o e para mejorar el rendimiento de los accesos a objetos pequeos. Por ejemplo, Cahoon n y McKinley [CM01, CM02] proponen a adir prefetch de cache al entorno de ejecucin n o de Java. Este trabajo se centra en mejorar los accesos a peque os arrays y a objetos n enlazados como parte de una lista. Para ello proponen modicar el compilador de Java para insertar en el cdigo generado las operaciones de prefetch de cache adecuadas. Por lo o tanto, el anlisis que proponen es esttico, realizado en tiempo de compilacin, y no pueden a a o utilizar la informacin sobre el comportamiento dinmico de los programas. Hay que decir o a que tambin proponen simplicar las tcnicas de anlisis que se utilizan en compilacin e e a o tradicional, para incorporarlas como parte del compilador al vuelo que puede utilizar Java en tiempo de ejecucin. De esta manera, el anlisis para insertar las operaciones o a de prefetch podr usar tambin la informacin sobre el comportamiento dinmico de los a e o a programas. Sin embargo, dejan para una futura evaluacin la viabilidad de esta propuesta. o

196

Cap tulo 7

Hay que destacar que ninguno de estos trabajos han considerado las necesidades de los programas que trabajan sobre objetos de grandes dimensiones en uso durante toda la ejecucin, para los que no inuye la ejecucin de las tareas de gestin del espacio lgico. o o o o Al contrario, todos los trabajos previos se centran en mejorar el rendimiento de programas que durante su ejecucin realizan numerosas creaciones de objetos peque os con un tiempo o n de vida corto. Adems, en ning n caso aprovechan el potencial que ofrece el conocimiento que tiene la a u JVM sobre el comportamiento dinmico de los programas para adaptar las decisiones de a gestin a sus necesidades. o

7.3

GESTION ESPEC IFICA DE RECURSOS

Durante los ultimos a os han aparecido muchas propuestas que intentan conseguir una n gestin de recursos espec o ca para los programas. En esta gestin podemos distinguir o dos tareas principales: la toma de decisiones y la realizacin de esas decisiones. Teniendo o en cuenta estas dos tareas, podemos clasicar las estrategias propuestas en tres grupos diferentes. En el primer grupo de propuestas, el sistema operativo se encarga tanto de las toma de decisiones como de su realizacin. En estos trabajos los sistemas operativos utilizan la o informacin que tienen sobre el comportamiento de los programas, para intentar hacer o predicciones sobre el comportamiento futuro, y, en funcin de esas predicciones gestionar o los recursos. Debido a la poca informacin que tienen sobre el comportamiento de los o programas, las predicciones que pueden hacer son, en general, poco precisas. Por ejemplo, Vitter y Krishnan han trabajado sobre algoritmos para pure prefetching [VK96, KV94], un modelo terico de carga anticipada y as o ncrona, que ignora la ejecucin del algoritmo o de reemplazo y que asume que no hay latencia de prefetch; y Vilayannur et al. [VSK05] han trabajado para predecir cul es el momento adecuado para reemplazar una pgina a a determinada, para favorecer el rendimiento de las decisiones de reemplazo.

Trabajo Relacionado

197

Todas estas estrategias se basan en determinar el patrn de accesos de los programas o usando como datos de entrada la unica informacin que tiene el sistema operativo sobre los o accesos de los programas, esto es, los fallos de pgina. Por lo tanto, esta poca informacin a o limita la precisin de los algoritmos de prediccin. o o Fraser y Chang [FC03] proponen utilizar ejecucin especulativa para anticipar los accesos o a disco realizados por las aplicaciones. Esta estrategia implica una profunda y complicada modicacin del sistema operativo y slo puede ser efectiva en entornos en los que la o o CPU est ociosa durante un tiempo suciente. La propuesta se basa en tener un ujo de a ejecucin especulativo que ejecuta por adelantado el cdigo de la aplicacin, aprovechando o o o los instantes en los que la CPU pasar a estar ociosa. El sistema operativo tiene que a garantizar que el ujo especulativo no modica los datos utilizados por el ujo de ejecucin o real, lo que implica el uso de la tcnica de copy-on-write, aumentando la cantidad de e memoria necesaria para la ejecucin del programa. Este incremento puede penalizar el o rendimiento de las aplicaciones que tengan un alto consumo de memoria, aunque las decisiones de prefetch sean precisas. Por este motivo, como parte de la estrategia, han implementado un mdulo que eval a los benecios obtenidos de la ejecucin especulativa, o u o para poder desactivarla si estos benecios son bajos. En el otro extremo, tenemos el grupo de propuestas que permiten que el nivel de usuario suministre el cdigo de gestin que contendr la toma de decisiones y su realizacin. o o a o Esta alternativa ha sido estudiada profundamente a lo largo de los a os [SS96]. As n , encontramos propuestas que van desde los microkernels iniciales [AR89, Jr,87], los sistemas operativos extensibles (como Vino [SESS96] o Spin [BSP+ 95]) y los exokernels [EKJ95]. Este grupo de propuestas se enfrentan al compromiso entre dos caracter sticas necesarias y muchas veces opuestas: abilidad y eciencia. Esto es as porque tienen que garantizar que el cdigo que suministra el usuario, y que ejecuta las decisiones de gestin, no arriesga o o la integridad del sistema. Adems tienen otra gran desventaja que es la necesidad de que a el programador aporte el cdigo de gestin que conviene utilizar para su programa. Esto o o implica que el programador debe, en el mejor de los casos, analizar el tipo de gestin que o es conveniente para optimizar el rendimiento del programa lo cual no siempre es una tarea sencilla asumible por cualquier programador, y, en el peor de los casos, debe implementar tambin el cdigo de esa gestin. e o o

198

Cap tulo 7

El tercer grupo de propuestas, se basan en la cooperacin entre el nivel de usuario y el o nivel de sistema para gestionar los recursos. En estas propuestas el nivel usuario se puede encargar de la toma de decisiones mientras que el sistema operativo es el encargado de realizarlas. La opcin de pedirle a un usuario que modique el cdigo del programa para o o insertar las operaciones de gestin no es siempre una alternativa viable. Por este motivo o se ha trabajado en la insercin automtica de estas peticiones. o a Hay muchos trabajos sobre compiladores para que este software, durante la generacin del o ejecutable, se encargue de analizar el cdigo de los programas y de insertar las operaciones o de gestin [BMK96, BM00]. Sin embargo, esta opcin tiene varias limitaciones. La primera o o limitacin es que la necesidad de que el usuario posea el cdigo fuente de los programas, o o lo cual no siempre es posible. Otra limitacin importante es que los compiladores slo o o disponen de la informacin esttica. Por lo tanto, no pueden tener en cuenta todas aquellas o a caracter sticas de los programas que dependen de condiciones de ejecucin. Adems, la o a ecacia de algunas decisiones de gestin depende no slo del programa, sino tambin o o e de las caracter sticas de la mquina y de sus condiciones en el momento de ejecutar a el programa. As para poder tener en cuenta el estado de la mquina ser necesario , a a recompilar el programa cada vez que se quiera ejecutar. Algunos trabajos han intentado complementar el trabajo del compilador para que se pueda considerar al menos el estado de la mquina en tiempo de ejecucin [CG99]. Estos traa o bajos a aden al entorno de ejecucin una capa de software que, en tiempo de ejecucin, n o o ltran aqullas operaciones insertadas por el compilador pero no adecuadas a las condie ciones actuales de la mquina. Sin embargo esta capa no tiene acceso a las caracter a sticas dinmicas de los programas. En cualquier caso, para que el usuario pueda ejecutar el proa grama usando esta estrategia, es necesario poseer el cdigo fuente del programa lo que, o en general, no se puede suponer que suceda. En este grupo de trabajos tambin se puede incluir el propuesto por Guitart et. al. e [GMTA03]. Este trabajo se centra en mejorar el rendimiento de aplicaciones Java paralelas ejecutadas sobre multiprocesadores de memoria compartida. Para ello propone permitir la cooperacin entre el nivel de usuario y el nivel de sistema para decidir el grado o de paralelismo que debe explotar el programa para obtener un buen rendimiento. Sin em-

Trabajo Relacionado

199

bargo, es responsabilidad del programador insertar en el cdigo las operaciones adecuadas o para informar al sistema de sus necesidades. Nuestra propuesta tambin se basa en la cooperacin entre el nivel usuario y el sistema e o operativo, sin embargo supera todas las limitaciones de la opcin de los compiladores y es o totalmente automtica y transparente al programador y al usuario. Adems, ni tan solo a a es necesario disponer del cdigo fuente de los programas. En nuestra propuesta la JVM es o la encargada de guiar las decisiones de gestin utilizando la informacin que tiene sobre o o el comportamiento dinmico de los programas, lo que permite adaptar automticamente a a las decisiones de gestin a las necesidades del programa. El SO es el encargado de llevar a o cabo estas decisiones slo si las condiciones de ejecucin son favorables, lo que garantiza o o la abilidad del sistema y facilita tener en cuenta el estado del sistema a la hora de tomar las decisiones de gestin. o

8
CONCLUSIONES Y TRABAJO FUTURO

8.1

RESUMEN DEL TRABAJO

El objetivo principal de este trabajo ha sido demostrar que es posible mejorar el rendimiento de los entornos con ejecucin basada en mquinas virtuales como, por ejemplo, el o a entorno de ejecucin de Java o de C#, explotando las caracter o sticas propias del entorno para ofrecer una gestin de recursos ms adecuada al comportamiento de los programas. o a Una de las caracter sticas ms relevantes de este tipo de entornos de ejecucin es la portaa o bilidad de los programas. Sin embargo, el precio de esta portabilidad es una disminucin o del rendimiento con respecto al que se puede obtener en un entorno tradicional basado en la compilacin. Esto es as ya que los programas se ejecutan sobre una mquina virtual o a que, en tiempo de ejecucin, convierte el cdigo independiente de la plataforma f o o sica en el correspondiente a la mquina real sobre la que se intenta ejecutar el programa. En a este trabajo hemos propuesto aprovechar, precisamente, la ejecucin basada en el uso de o una mquina virtual para ofrecer a los programas una gestin de recursos espec a o ca para su comportamiento, mejorando de esta manera el rendimiento de los programas. Para demostrar los posibles benecios de esta estrategia, nos hemos centrado en la gestin del o recurso memoria y en el entorno de ejecucin de Java. o De esta manera, hemos analizado el uso de la memoria que hacen los programas Java cuyo rendimiento viene limitado por la gestin de memoria. Los objetivos de este anlisis, o a novedoso en el mbito de ejecucin de Java, han sido determinar las posibles v para a o as mejorar el rendimiento de la gestin de memoria del entorno de Java [BCGN03]. Para o 201

202

Cap tulo 8

ello hemos comprobado la inuencia que tiene el uso de la memoria virtual, teniendo en cuenta tanto la zona del espacio de direcciones ms afectada como la interaccin con las a o tareas de gestin del espacio de direcciones que implementa la JVM. o Las conclusiones de esta evaluacin del uso de la memoria, nos han llevado a determinar o que una estrategia de prefetch de pginas ecaz puede mejorar el rendimiento de estos a programas. Por este motivo, hemos analizado los requerimientos de las diferentes tareas de prefetch para poder asignar cada tarea al componente del entorno de ejecucin ms o a adecuado para realizarla. Las conclusiones de este anlisis nos han llevado al siguiente a reparto de tareas: la seleccin de pginas de prefetch debe ser guiada, en tiempo de o a ejecucin, por la JVM, y la carga en memoria debe ser efectuada por el SO. De esta o manera es posible dotar a la estrategia de prefetch de:

Un algoritmo de prediccin preciso implementado a nivel de instruccin, que tenga o o en cuenta la informacin que posee la JVM en tiempo de ejecucin, sobre todos los o o accesos que realiza la instruccin y sobre las caracter o sticas espec cas de la instruccin y del objeto que accede. Esta cantidad de informacin sobre el comportamiento o o dinmico de los programas supera con creces a la que tienen disponible tanto el SO a como el compilador y, por lo tanto, la precisin de la prediccin implementada por la o o JVM es mucho mayor que la puede ofrecer cualquier otro componente de los entornos tradicionales basados en compilacin. o Una seleccin de pginas capaz de adaptarse a las condiciones de ejecucin presentes o a o en cada momento, necesario, por ejemplo, para determinar la distancia de prefetch adecuada o para ltrar peticiones de prefetch redundantes. Esta capacidad de adaptacin no existe si se implementa la seleccin de pginas con un anlisis esttico en o o a a a tiempo de compilacin. o Una carga en memoria que respete la abilidad del sistema, ya que garantiza que el SO, unico componente del entorno able, realiza los accesos al hardware involucrados en la operacin de carga. o Un mecanismo totalmente transparente al programador y al usuario, que respeta el paradigma de portabilidad de Java y que ni tan slo requiere del usuario el cdigo o o

Conclusiones y trabajo futuro

203

fuente del programa, a diferencia de las estrategias basada en modicar el cdigo o generado por el compilador.

A partir de este primer anlisis hemos contemplado dos posibles alternativas para la a estrategia de prefetch, que hemos implementado y evaluado. Una primera opcin consiste en dotar al entorno de ejecucin de Java de un mecanismo o o de prefetch totalmente transparente al SO [BGCN06b, BGCN06c]. Esta opcin se basa en o utilizar heur sticas para aproximar las condiciones de ejecucin, necesarias para adaptar o las decisiones de prefetch al estado en el que se encuentra en cada momento el sistema, y en solicitar la carga anticipada de las pginas mediante un mecanismo ya existente en a el SO para otros propsitos (la excepcin del fallo de pgina). La ventaja de esta opcin o o a o es que favorece la portabilidad de la estrategia de prefetch ya que, al ser transparente al SO, no requiere modicar el sistema de las mquinas donde se quiera incorporar. La a evaluacin de esta alternativa ha ofrecido una mejora, con respecto al entorno original o de ejecucin, de hasta el 43 % para los benchmarks utilizados. Sin embargo, un anlisis o a detallado nos ha llevado a descartarla por varios motivos. El principal motivo es que el grado de portabilidad de la estrategia no es tan alto como el que se esperaba ya que, aunque este mtodo no requiere la modicacin del SO, s que es necesario analizar cuie o dadosamente la interaccin entre el cdigo de prefetch que hemos introducido y el resto o o de decisiones de gestin que sigue tomando el SO, ajeno a este nuevo nivel de gestin o o introducido. Adems, el uso de heur a sticas no ofrece las mismas garant de xito como as e poder consultar la informacin real, que se puede obtener con una mayor involucracin o o del SO en las decisiones de prefetch. La segunda opcin, que es la que hemos adoptado como propuesta nal para la estrategia o de prefetch, consiste en implementar una estrategia cooperativa en la que tanto la JVM como el SO participen en las decisiones de prefetch [BGCN06a]. En esta opcin, se subso tituye el uso de heur sticas por la consulta de la informacin real sobre el estado de la o mquina, lo cual dota al sistema de una mayor abilidad. Adems, la mayor participacin a a o del SO tambin permite obtener un mecanismo ms estable, ya que el SO es capaz de e a controlar la interaccin de las decisiones de prefetch con el resto de decisiones que toma o en la gestin de los recursos de la mquina. o a

204

Cap tulo 8

Para implementar esta estrategia, ha sido necesario modicar el SO con el interfaz necesario para implementar la cooperacin entre la JVM y el SO que, bsicamente, consiste en o a una zona de memoria compartida en la que el SO exporta al nivel de usuario la informacin sobre el estado de la memoria, y una nueva llamada a sistema que permite solicitar o la carga as ncrona de una pgina que se encuentra en el rea de swap. a a As pues, el papel de ambos componentes en la estrategia nal de prefetch es el siguiente:

La JVM utiliza su informacin sobre el comportamiento dinmico del programa para o a implementar la prediccin a nivel de instruccin. Adems utiliza la informacin que o o a o exporta el SO sobre el estado de la memoria para determinar la distancia de prefetch, ltrar las peticiones redundantes de prefetch, y determinar si las condiciones del sistema son favorables para solicitar nuevas cargas anticipadas, e incluso reintentar peticiones que fueron solicitadas en momentos poco adecuados, o si es ms apropiado a posponer la solicitud hasta que la carga del sistema sea menor. El SO efect a los accesos a disco y a memoria f u sica necesarios para realizar las cargas solicitadas por la JVM, cancela aquellas solicitudes que pueden perjudicar el rendimiento del programa dada la carga del sistema y exporta al nivel de usuario la informacin sobre el estado de la memoria para que la JVM la utilice durante la o seleccin y solicitud de pginas de prefetch. o a

La evaluacin de esta estrategia nos ha permitido comprobar que las mejoras en el reno dimiento de los programas, con respecto a la ejecucin en el entorno original, alcanzan o hasta un 40 %. Hay que decir que hay programas cuyas caracter sticas limitan el posible porcentaje de mejora del rendimiento que pueden obtener mediante una tcnica de pree fetch. Por ejemplo, si el programa no tiene un comportamiento predecible o si no tiene suciente tiempo de clculo para poder solapar la carga con el consumo de CPU. Sin ema bargo, en el peor de los casos, para los programas que no pueden ser mejorados mediante una estrategia de prefetch, la ejecucin sobre el entorno modicado con nuestra estrategia o ofrece un rendimiento similar a la ejecucin sobre el entorno original. o

Conclusiones y trabajo futuro

205

Por lo tanto, la estrategia de prefetch cooperativo que hemos desarrollado en este trabajo constituye un ejemplo que cmo mejorar el rendimiento de los programas Java, mediano te una pol tica de gestin totalmente adaptada al comportamiento de cada programa, o capaz de utilizar tanto el conocimiento que tiene la JVM sobre los programas, como el conocimiento que tiene el SO sobre las condiciones de ejecucin. o

8.2

CONTRIBUCIONES DE ESTE TRABAJO

As pues, las principales contribuciones de esta tesis son:

Hemos demostrado que es posible mejorar el rendimiento de los programas con ejecucin basada en la interpretacin, sin renunciar a las caracter o o sticas que hacen de estos entornos una opcin atractiva para la ejecucin de o o programas. Hemos demostrado que los entornos de ejecucin basados en mquinas o a virtuales constituyen el escenario ideal para implementar una gestin de o recursos adaptada al comportamiento de los programas, que supera las limitaciones presentes en los entornos tradicionales basados en compilacin. o As en estos entornos es posible ofrecer a los programas pol , ticas de gestin o de recursos espec cas, que se adapten a su comportamiento dinmico y a respeten la abilidad del sistema, de una forma totalmente transparente al programador y al usuario.

Para llegar hasta estas aportaciones, hemos acotado nuestro caso de estudio a la gestin de o memoria en el entorno de ejecucin de Java, y hemos aportado las siguientes contribuciones o aplicadas:

Hemos evaluado de forma detallada el comportamiento de los programas Java cuya ejecucin necesita el mecanismo de memoria virtual, que nos ha llevado a determinar o que una pol tica de prefetch ecaz puede mejorar su rendimiento, ya que:

206

Cap tulo 8

El uso de la memoria virtual inuye de forma signicativa sobre los programas Java cuando la memoria f sica disponible no es suciente para soportar el conjunto de datos del programa La zona del espacio de direcciones que se ve ms afectada es la zona donde se a almacenan los objetos, de manera que es posible obviar la inuencia que tiene el uso de la memoria virtual sobre los accesos al resto de zonas del espacio de direcciones. Existen programas que apenas requieren la participacin de las tareas de gestin o o del espacio de direcciones que implementa la JVM, por lo que mejorar la interaccin entre la ejecucin de estas tareas y la gestin de memoria implementada por o o o el SO no es un camino factible para mejorar su rendimiento. El tipo de objetos que provocan la necesidad del uso de la memoria virtual son arrays de grandes dimensiones, que ocupan la mayor parte del espacio de direcciones del programa. Adems, estos objetos son accedidos siguiendo un patrn a o predecible, por lo que es posible anticipar cules sern los prximos accesos del a a o programa e implementar su carga anticipada. El rendimiento del sistema de memoria est muy lejos del rendimiento ofrecido a por una gestin ptima de memoria, por lo que el margen de mejora es muy o o amplio. Hemos analizado la manera ms adecuada para repartir las tareas de prefetch entre los a diferentes componentes del entorno de ejecucin para obtener una pol o tica eciente, adaptada a las caracter sticas de cada programa, able, que respete la portabilidad de los programas Java y que sea transparente al usuario y al programador. Hemos demostrado que es posible obtener una pol tica de prefetch ecaz, totalmente dirigida por la JVM y sin involucrar al SO en la decisiones de gestin asociadas. Sin o embargo, es necesario utilizar heur sticas para aproximar las condiciones de ejecucin o del sistema. Adems, el mecanismo resultante es muy sensible a la implementacin a o del resto de tareas de gestin del SO. Esto hace necesario un anlisis detallado de o a la interaccin del mecanismo de prefetch con la versin del SO instalada en cada o o plataforma donde se quiera implantar comprometiendo, de esta manera, la potencial portabilidad que puede tener una estrategia implementada por completo en el nivel de usuario.

Conclusiones y trabajo futuro

207

Hemos dise ado, implementado y evaluado una estrategia de prefetch basada en la n cooperacin entre la JVM y el SO. Esta pol o tica de gestin adapta sus decisiones o al comportamiento de cada programa y a las condiciones de ejecucin del sistema, o y supera las limitaciones de las estrategias de prefetch propuestas en los entornos tradicionales basados en compilacin. o

8.3

TRABAJO FUTURO

Como trabajo futuro nos planteamos los siguientes puntos:

Renamiento de la estrategia de prefetch cooperativo, explorando los siguientes aspectos: Cantidad de pginas solicitadas para cada prediccin: en este trabajo hemos jado a o el n mero mximo de peticiones en base a las posibles optimizaciones que puede u a hacer Linux en el acceso al rea de swap. Como trabajo futuro nos planteamos a analizar en profundidad la inuencia que este parmetro puede tener sobre la a estrategia de prefetch. Gestin de las operaciones canceladas: en la implementacin presentada en este o o trabajo, la gestin de las solicitudes de prefetch canceladas se hace mediante una o pol tica FIFO muy sencilla, que ha dado buen resultado para los programas que hemos evaluado. En versiones futuras de nuestra estrategia, queremos investigar la inuencia que puede tener sobre el rendimiento una pol tica ms elaborada. a Automatizacin del clculo de la distancia: en este trabajo hemos demostrado que o a la JVM es capaz de adaptar el valor de la distancia de prefetch a las condiciones de ejecucin del sistema. Esta adaptacin la hemos implementado mediante una o o heur stica muy sencilla que incrementa el valor de la distancia si el actual no es suciente para completar la carga anticipada. Como parte de nuestro trabajo futuro pretendemos evaluar posibles renamientos sobre esta heur stica como, por ejemplo, permitir que el valor de la distancia tambin pueda disminuir si la e presin sobre el sistema de memoria disminuye durante la ejecucin. o o

208

Cap tulo 8

Desactivacin del prefetch: en este trabajo hemos implementado la desactivacin o o del prefetch cuando el comportamiento de las instrucciones no es predecible. Tambin hemos implementado la cancelacin de las operaciones de prefetch cuando e o las condiciones de ejecucin desaconsejan llevarlas acabo. Sin embargo, queda o pendiente desactivar la estrategia para los programas que no utilizan el mecanismo de memoria virtual y, que por lo tanto, ver ralentizada su ejecucin por an o la estrategia de prediccin y solicitud de pginas ya presentes en memoria f o a sica. La implementacin de esta funcionalidad es muy sencilla, teniendo en cuenta que o el SO puede informar a la JVM sobre el estado del sistema, usando la zona de memoria que comparten. Nuevas funciones de prediccin: en este trabajo nos hemos centrado en mejorar los o accesos a objetos de tipo array de grandes dimensiones, ya que este tipo de objetos era el que provocaba el uso de la memoria virtual en los benchmarks con los que hemos trabajado. Como parte de nuestro trabajo futuro queremos incorporar nuevos algoritmos de prediccin, capaces de gestionar el acceso a objetos de otro o tipo. Evaluacin de la estrategia de prefetch cooperativo en aplicaciones pertenecientes a o otros mbitos, ya que todos los benchmarks utilizados en este trabajo son de clculo a a cient co. Evaluacin de la inuencia que puede tener el uso de compiladores en tiempo de ejeo cucin sobre el rendimiento del prefetch. Hay que decir que la estrategia propuesta o es totalmente aplicable si se utiliza un compilador al vuelo, ya que es suciente con modicar el compilador, para que incorpore en el cdigo mquina que genera las inso a trucciones encargadas de seleccionar y solicitar las pginas de prefetch. Sin embargo, a es necesario evaluar los posibles efectos laterales que esta compilacin al vuelo pueda o tener sobre el rendimiento de la estrategia de prefetch. Implementar la cooperacin entre la JVM y el SO para ofrecer tambin una gestin o e o espec ca para el uso de otros recursos como, por ejemplo, el procesador.

REFERENCIAS

[AES97]

Anurag Acharya, Guy Edjlali, y Joel Saltz. The utility of exploiting idle workstations for parallel computation. En Proceedings of the 1997 ACM SIGMETRICS International Conference on Measurements and Modeling of Computer Systems, pginas 225236, Seattle, WA, Junio 1997. a

[AGH00]

Ken Arnold, James Gosling, y David Holmes. Java Programming Language, The 3rd Edition. Addison Wesley Professional, 2000.

[AR89]

Vadim Abroossimov y Marc Rozier. Generic virtual memory management for operating system kernels. ACM, SIGOPS Operating Systems Review, 23(5):123136, Diciembre 1989.

[AW02]

Tom Archer y Andrew Whitechapel. Inside C#, 2nd edition. Microsoft Press, 2002.

[BCGN03] Yolanda Becerra, Toni Cortes, Jordi Garcia, y Nacho Navarro. Evaluating the importance of virtual memory for java. En Proceedings of the IEEE 2003 International Symposium on Performance Evaluation of Systems and Applications, Austin, TX, Marzo 2003. [BFH03] Fran Berman, Georey Fox, y Tony Hey. The Grid: past, present, future, cap tulo 1, pginas 950. Wiley and Sons, Ldt, Marzo 2003. a

[BGCN06a] Yolanda Becerra, Jordi Garcia, Toni Cortes, y Nacho Navarro. Cooperative page prefetching: an example of os and vm cooperation. Pendiente de revisin, 2006. o [BGCN06b] Yolanda Becerra, Jordi Garcia, Toni Cortes, y Nacho Navarro. Java virtual machine: the key for accurated memory prefetching. En Proceedings of the 2006 International Conference on Programming Languages and Compilers (pendiente de publicacin), Las Vegas, NE, Junio 2006. o 209

210

[BGCN06c] Yolanda Becerra, Jordi Garcia, Toni Cortes, y Nacho Navarro. Memory prefetching managed by the java virtual machine. Technical Report UPC-DACRR-2006-2, Computer Architecture Dept., UPC, Barcelona, Espa a, 2006. n [BM00] Angela Demke Brown y Todd C. Mowry. Taming the memory hogs: Using compiler-inserted releases to manage physical memory intelligently. En Proceedings of the Fourth Symposium on Operating Systems Design and Implementation, pginas 3144, San Diego, CA, Octubre 2000. a [BMK96] Angela Demke Brown, Todd C. Mowry, y Orran Krieger. Automatic compilerinserted I/O prefetching for out-of-core applications. En Proceedings of the Second Symposium on Operating Systems Design and Implementation, pgia nas 317, Seattle, WA, Octubre 1996. [Boe00] Hans-J. Boehm. Reducing garbage collector cache misses. Technical Report HPL-2000-99, Hewlett-Packard Laboratories, Palo Alto, CA, Julio 2000. [BSP+ 95] Brian N. Bershad, Stefan Savage, Przemyslaw Pardyak, Emin G n Sirer, u Marc E. Fiuczynski, David Becker, Craig Chambers, y Susan Eggers. Extensibility, safety and performance in the spin operating system. En Proceedings of 15th Symposium on Operating Systems Principles, pginas 267283, Sainta Mal, France, Diciembre 1995. o [BSW+ 00] J.M. Bull, L.A. Smith, M.D. Westhead, D.S. Henty, y R.A. Davey. A benchmark suite for high performance java. Concurrency, Practice and Experience, (12):2156, 2000. [CG99] Fay Chang y Garth A. Gibson. Automatic I/O hint generation through speculative execution. En Proceedings of the Third Symposium on Operating Systems Design and Implementation, pginas 114, New Orleans, LA, Febrero a 1999. [CHL+ 00] Ralph Christ, Steven L. Halter, Kenton Lynne, Stephanie Meizer, Steven J. Munroe, y Mark Pasch. Sanfrancisco performance: A case study in performance of large-scale Java applications. IBM Systems Journal, 39(1):420, Febrero 2000.

Referencias

211

[CKV93]

Kenneth M. Curewitz, P. Krishnan, y Jerey S. Vitter. Practical prefetching via data compression. En Proceedings 1993 ACM-SIGMOD Conference on Management of Data, pginas 257266, Washington, D.C., Mayo 1993. a

[CM92]

Henry Clark y Bruce McMillin. DAWGS - a distributed compute server utilizing idel workstations. Journal of Parallel and Distributed Computing, 14(2):175186, Febrero 1992.

[CM01]

Brendon Cahoon y Kathryn S. McKinley. Data ow analysis for software prefetching linked data structures in java. En Proceedings of the International Conference on Parallel Architectures and Compilation Techniques, pginas a 280291, Barcelona, Espa a, Septiembre 2001. n

[CM02]

Brendon Cahoon y Kathryn S. McKinley. Simple and eective array prefetching in java. En Proceedings of the ACM Java Grande Conference, pginas a 8695, Seattle, WA, Noviembre 2002.

[DH99]

Sylvia Dieckmann y Urs Hlzle. A study of the allocation behavior of the o SPECjvm98 java benchmarks. En Proceedings of the 1999 European Conference on Object-Oriented Programming, Lisboa, Portugal, Junio 1999. Ecma International. Common Language Infrastructure (CLI), common generics. Technical Report TR/89, Ecma International, Junio 2005.

[Ecm05]

[EKJ95]

Dawson R. Engler, M. Frans Kaashoek, y James OToole Jr. Exokernel: An operating system architecture for application-level resource management. En Proceedings of 15th Symposium on Operating Systems Principles, pginas a 251266, Saint-Mal, France, Diciembre 1995. o

[FC03]

Keir Fraser y Fay Chang. Operating system I/O speculation: How two invocations are faster than one. En Proceedings of the 2003 Usenix Annual Technical Conference, pginas 325328, San Antonio, TX, Junio 2003. a

[FGT02]

Georey Fox, Dennnis Gannon, y Mary Thomas. Editorial: A summary of grid computing environments. Concurrency and computation: practice and experience, 14(13-15):10351044, Noviembre-Diciembre 2002. Michael Frumkin, Matthew Schultz, Haoquiang Jin, y Jerry Yan. Performance and scalability of the NAS parallel benchmarks in Java. En Proceedings

[FSJY03]

212

of the International Parallel and Distributed Processing Symposium, pginas a 139145, Niza, Francia, Abril 2003. [GA94] James Grioen y Randy Appleton. Reducing le system latency using a predictive approach. En Proceedings of the 1994 Summer USENIX Conference, pginas 197207, Boston, MA, Junio 1994. a [GG97] Jos Gonzlez y Antonio Gonzlez. Speculative execution via address pree a a diction and data prefetching. En Proceedings of the ACM 1997 International Conference on Supercomputing, pginas 196203, Viena, Austria, Julio 1997. a [GM96] James Gosling y Henry McGilton. The Java language environment. A white paper. Technical report, Sun Microsystems, Inc., Mayo 1996.

[GMTA03] Jordi Guitart, Xavier Martorell, Jordi Torres, y Eduard Ayguad. Applie cation/kernel cooperation towards the ecient execution of shared-memory parallel java codes. En Proceedings of the 17th IEEE International Parallel and Distributed Processing Symposium, Niza, Francia, Abril 2003. [JGF01] [JL96a] Java Grande Forum. http://www.javagrande.org, 2001. Richard Jones y Rafael Lins. Garbage Collection: Algorithms for Automatic Dynamic Memory Management. Wiley and Sons Ldt., Septiembre 1996. [JL96b] Richard Jones y Rafael Lins. Mark-Sweep Garbage Collection, cap tulo 4, pginas 7596. Wiley and Sons Ldt., Septiembre 1996. a [Jr.87] Avadis Tevanian Jr. Arquitecture-independent virtual memory management for parallel and distributed environments: The mach approach. Technical Report CMU-CS-88-106, PhD. Thesis, Computer Science Dept., Carnegie Mellon University, Pittsburg, PA, Diciembre 1987. [KaMR02] Paul H.J. Kelly y Susanna Pelagatti annd Mark Rossiter. Instant-access cycle-stealing for parallel applications requiring interactive response. En Proceedings of the 8th International Euro-Par Conference, pginas 863872, a Paderborn, Germany, Agosto 2002. [KFH+ 06] Gopi Kandaswamy, Liang Fang, Yi Huang, Satoshi Shirasuna, Suresh Marru, y Dennis Gannon. Building web services for scientic grid applications. IBM journal of research and development, 50(2-3):249260, Marzo-Mayo 2006.

Referencias

213

[KH00]

Jin-Soo Kim y Yarsun Hsu. Memory system behavior of Java programs: Methodology and analysis. En Proceedings of the ACM International Conference on Measurement and Modeling of Computer Systems, pginas 264274, Santa a Clara, CA, Julio 2000.

[Kra96]

Douglas Kramer. The Java platform. A white paper. Technical report, Sun Microsystems, Inc., Mayo 1996.

[KV94]

P. Krishnan y Jerey S. Vitter. Optimal prediction for prefetching in the worst case. En Proceedings fth Annual SIAM/ACM Symposium on Discrete Algorithms, pginas 392401, Arlington, Virginia, Enero 1994. a

[LJNS01]

Tao Li, Lizy K. John, Vijaykrishnan Narayanan, y Anand Sivasubramaniam. Characterizing Operating System Activity in SPECjvm98 Benchmarks, cap tulo 3, pginas 5382. Kluwer Academic Publishers, 2001. a

[LY99]

Tim Lindholm y Frank Yellin. The Java Virtual Machine Specication, second edition. Addison Wesley, Abril 1999.

[MMG+ 00] Jos E. Moreira, Samuel P. Midki, Manish Gupta, Pedro V. Artigas, Marc e Snir, y Richard D. Lawrence. Java programming for high-performance numerical computing. IBM Systems Journal, 39(1):2156, Febrero 2000. [MMGL99] Jos E. Moreira, Samuel P. Midki, Manish Gupta, y Richard D. Lawrence. e High performance computing with the array package for Java: A case study using data mining. En Proceedings of the Supercomputing 99 Conference, Portland, OR, Noviembre 1999. [PZ91] Mark Palmer y Stanley B. Zdonik. Fido: A cache that learns to fetch. En Proceedings of the 17th International Conference on Very Large Data Base, pginas 255264, Barcelona, Espa a, Septiembre 1991. a n [Ric00] Jerey Richter. Microsoft .NET framework delivers the platform for an integrated, service-oriented web. MSDN Magazine, 15(9), Septiembre 2000. [SESS96] Margo I. Seltzer, Yasuhiro Endo, Christopher Small, y Keith A. Smith. Dealing with disaster: Surviving misbehaved kernel extensions. En Proceedings of the 1996 Symposium on Operating System Design and Implementation, pginas 213227, Seatle, WA, Octubre 1996. a

214

[SGBS02]

Yem Shuf, Manish Gupta, Rajesh Bordawekar, y Jaswinder Pal Singh. Exploiting prolic types for memory management and optimizations. En Proceedings of the ACM Symposium on Principles of Programming Languages 2002, pginas 194205, Portland, OR, Enero 2002. a

[SGF+ 02]

Yem Shuf, Manish Gupta, Hubertus Franke, Andrew Apple, y Jaswinder Pal Singh. Creating and preserving locality of java applications at allocation and garbage collection times. En Proceedings of the ACM Conference on ObjectOriented Programming, Systems, Languages, and Applications, 2002, pginas a 1325, Seattle, WA, Noviembre 2002.

[SMM99]

Darko Stefanovi, Kathryn S. McKinley, y J. Eliot B. Moss. Age-based c garbage collection. En Proceedings of ACM 1999 SIGPLAN Conference on Object-Oriented Programming Systems, Languages and Applications, pginas a 370381, Denver, CO, Noviembre 1999.

[SPE98] [SS96]

SPEC JVM98. http://www.spec.org/osg/jvm98, 1998. Christopher Small y Margo I. Seltzer. A comparison of OS extension technologies. En Proceedings of the 1996 Usenix Conference, pginas 4154, San a Diego, CA, Enero 1996.

[Sun01]

Sun Microsystems, Inc. The Java HotSpot Virtual Machine. Technical white paper, Abril 2001. Matthew L. Seidl y Benjamin .G. Zorn. Segregating heap objects by reference behavior and lifetime. En Proceedings of the 8th ACM International Conference on Architectural Support for Programming Languages and Operating Systems, pginas 1223, San Jose, CA, Octubre 1998. a

[SZ98]

[VK96]

Jerey S. Vitter y P. Krishnan. Optimal prefetching via data compression. Journal of the ACM, 43(5):771793, Septiembre 1996.

[VSK05]

Murali Vilayannur, Anand Sivasubramaniam, y Mahmut Kandemir. Proactive page replacement for scientic applications: A characterization. En Proceedings of the 2005 IEEE International Symposium on Performance Analysis of Systems and Software, pginas 248257, Austin, TX, Marzo 2005. a

Referencias

215

[WLM92]

Paul R. Wilson, Michael S. Lam, y Thomas G. Moher. Caching considerations for generational garbage collection. En Proceedings of the ACM Conference on Lisp and Functional Programming, pginas 3242, San Francisco, CA, a Junio 1992.

Potrebbero piacerti anche