Utilizo un ejemplo de la teoría de elementos finitos, pero cualquiera que mantenga una gran estructura de datos y la extienda sucesivamente encontrará algo similar.
Suponga que tengo una malla no estructurada de puntos y triángulos, donde los puntos están dados por coordenadas (digamos e ) y los triángulos consisten en tres índices de puntos (digamos , y ).
Como es común en FEM, la malla será sucesivamente refinada. Si recurrimos al refinamiento regular global, el número de triángulos crecerá en un factor con cada iteración del refinamiento. Dependiendo de cómo se haga esto, el diseño de la memoria se desarrollará de manera diferente.
Digamos que la malla oculta las celdas de memoria 1 a 300, cualquier cosa más allá de eso está libre.
Ejemplo 1:
Asignamos el espacio para la nueva malla, celdas 301 a 1501, la llenamos con los datos de la malla refinada y olvidamos la anterior. La siguiente malla refinada se colocará en las celdas 1501 a 6300, la siguiente en 6301 a 21500, y así sucesivamente. La ubicación de la malla actual se moverá en la memoria "hacia la derecha", mientras que no se utilizará un parche enorme. Podemos quedarnos sin memoria prematuramente.
Se podría observar en el ejemplo anterior, que esto solo nos dificultará un paso más, porque incluso sin esa fragmentación nos quedaríamos sin memoria total un refinamiento más tarde. A medida que también se tiene en cuenta la matriz de vértices, el problema puede ser más grave.
¿Cómo se puede evitar esto?
Ejemplo 2
Vuelva a asignar la matriz de triángulos a las celdas 1..1200. Cree la nueva malla en las celdas 1201 a 2400. Copie el contenido de esa copia de trabajo en las celdas 1..1200 y olvide la copia de trabajo. Repite de manera similar.
Ok, todavía nos quedamos sin memoria prematuramente, porque necesitamos una copia que funcione. Qué tal esto:
Ejemplo 3
Vuelva a asignar la matriz de triángulos a las celdas 1..1500. Copie la malla antigua a 1201 .. 1500. Cree una nueva malla en las celdas 1..1200. Luego olvida la copia de la malla vieja.
El caso aquí es artificial, porque uno no usaría el refinamiento de malla global en estas escalas. Si el crecimiento es mucho menor, la realineación de la memoria es posible para evitar la fragmentación. Sin embargo,
Preguntas:
¿La fragmentación de la memoria se vuelve crítica en la informática científica práctica / informática de alto rendimiento?
Si es así, ¿cómo lo evitas? Tal vez mi modelo de máquina está incluso equivocado, y el sistema operativo, por magia pesada, realinea la memoria tácitamente o gestiona bloques fragmentados en el montón.
Más específicamente, ¿cómo afecta a la gestión de la red?
fuente
En deal.II, refinamos la malla tirando las celdas viejas y reemplazándolas por otras nuevas. Pero también se colocan otros nuevos en los agujeros de memoria que dejan las celdas eliminadas. Todos los bucles sobre todas las celdas se realizan en el orden en que se encuentran las celdas en la memoria para mantener altos los éxitos de caché.
La pregunta más importante es cómo almacena los datos que definen las celdas. Por supuesto, puede hacer struct Simplex {Vértices vértices [4]; int material_id; int subdomain_id; bool usado; void * user_data; };
clase Triangulación {Simplex * celdas; }; pero esto no es eficiente en caché porque la mayoría de los bucles en todas las celdas solo tocarán un subconjunto de los datos que almacena en su estructura de datos Simplex y, por lo tanto, solo se usará una fracción de los datos que aterrizan en la caché. Una mejor estrategia es hacer algo como esto: clase Triangulación {Vértices * vértices; int * material_ids; int * subdomain_ids; bool * used_flags; void * * user_data; }; Debido a que en los bucles sobre todas las celdas, es probable que las iteraciones posteriores accedan al mismo subconjunto de datos que define las celdas, los cachés de lectura anticipada solo precargarán los datos que realmente va a usar y, en consecuencia, conducirán a altas tasas de aciertos de caché.
fuente
1) No. La memoria del solucionador supera con creces la memoria de la malla. Incluso si ejecuta el solucionador explícito más ligero, la malla es como máximo el 25% de la memoria de la simulación, y es mucho más probable que sea <10%.
2) Desglose su asignación y use la agrupación de memoria. No necesita asignar un fragmento contiguo para toda la malla, ya que generalmente solo necesita iterar sobre piezas locales. La introducción de un nivel de indirección no afecta el rendimiento de manera significativa.
fuente
Si se está quedando sin memoria, simplemente ejecute en más nodos para tener más memoria. Está desperdiciando un recurso muy valioso (el cerebro humano) para resolver un problema que tiene una solución muy fácil.
fuente