![]() |
||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||
![]() |
RefNUMA – библиотека для организации виртуальной общей памяти в программах, использующих MPI.А. О. Лацис
Пример 4. Контроль расхода физической памяти и диагностика ее исчерпания.Разбирая предыдущий пример, мы отмечали, что в качестве второго аргумента coarray_create() указывается объем заранее резервируемой в каждом процессе системной памяти, используемой по мере необходимости библиотекой RefNUMA для реализации данного массива общей памяти. Необходимость оценивать вручную и явно задавать это значение – пожалуй, главное неудобство RefNUMA. Тем более важно не просто понимать, на что и когда эта память расходуется, но и уметь, как минимум, две вещи:
Системная память расходуется исключительно для реализации доступа процессов к чужим секциям. Если такой доступ имел место, то системная память расходуется и в процессе, который осуществлял доступ, и в процессе, для которого эта секция – своя. Если ни один процесс не осуществлял доступа к чужим секциям, системная память не расходуется вообще. Расход системной памяти можно грубо оценить как удвоенный объем страниц чужой памяти, к которым осуществлялся доступ из одного процесса. При этом важно принимать во внимание «краевые эффекты»: поскольку системная память выделяется страницами, для «игрушечных», отладочных вариантов вновь создаваемых программ ее требуемый размер может многократно превышать размер секции, поскольку сама секция многократно меньше страницы. Размер страницы – 512 элементов типа double. Более или менее точная оценка необходимого объема системной памяти, таким образом, сложна и вряд ли целесообразна на практике. Важнее уметь спрашивать у системы, сколько ее реально потребовалось. Это делается обращением к функции coarray_report(), первым (входным) аргументом которой является указатель на секционированный массив, а вторым и третьим (выходными) – адреса переменных, которым присваиваются, соответственно, объем запрошенной и израсходованной при реализации данного массива системной памяти. Оба возвращаемых аргумента имеют тип long, а не int!!! Однако, для успешной отладки этого мало. Опыт показывает, что довольно часто в еще не отлаженной программе присутствуют массовые ошибочные обращения к чужим секциям некоторого массива общей памяти. При этом объем системной памяти, необходимый для формально успешного завершения программы, оказывается очень большим, и значительно превышает оценки, сделанные программистом. Программа из-за этого постоянно завершается аварийно. В этом случае очень важно бывает быстро и надежно понять, с каким именно массивом общей памяти связана проблема. Чтобы сделать диагностические сообщения об исчерпании системной памяти более информативными, можно сразу после создания секционированного массива присвоить ему текстовое имя, которое будет фигурировать в этих диагностических сообщениях. Это делается обращением к функции coarray_set_name(). По умолчанию все секционированные массивы имеют текстовое имя из одного пробела, и по тексту диагностического сообщения невозможно понять, в каком именно секционированном массиве исчерпалась системная память. Присвоенное секционированному массиву имя можно опросить обращением к функции coarray_get_name(). Ниже представлен исходный текст программы предыдущего примера, в которую добавлены описанные только что средства дополнительной диагностики. #include <stdio.h> #include <stdlib.h> #include <mpi.h> #include <coarray.h> #include <shared.h> #define LSECT 10 COARRAY_MEM_ALLOC( 2000000000l ); int main( int argc, char *argv[] ) { int i, j, k, my_node, n_nodes; double **coarray; long requested, used; FILE *fp; /***/ COARRAY_Init( &argc, &argv ); my_node = coarray_my_node(); n_nodes = coarray_n_nodes(); coarray = (double**)coarray_create( LSECT*sizeof(**coarray), LSECT*1000*sizeof(**coarray) ); if ( !coarray ) { fprintf( stderr, "No memory\n" ); exit( -1 ); } coarray_set_name( (void**)coarray, "This is my coarray" ); if ( my_node == 0 ) { fp = fopen( "output.dat", "w" ); fclose( fp ); } NODE_BY_NODE_BEGIN( i, 0, n_nodes ) fp = fopen( "output.dat", "a" ); if ( i == 0 ) fprintf( fp, "BEFORE ASSIGNMENT\n" ); fprintf( fp, "Hello, I am %d of %d\n", my_node, n_nodes ); fprintf( fp, "My view of the coarray is:\n" ); for ( j = 0; j < n_nodes; j++ ) { for ( k = 0; k < LSECT; k++ ) { fprintf( fp, " %f\n", coarray[j][k] ); } } fclose( fp ); NODE_BY_NODE_END coarray_barrier(); for ( i = 0; i < LSECT; i++ ) coarray[my_node][i] = LSECT*my_node+i; coarray_barrier(); NODE_BY_NODE_BEGIN( i, 0, n_nodes ) fp = fopen( "output.dat", "a" ); if ( i == 0 ) fprintf( fp, "AFTER ASSIGNMENT\n" ); fprintf( fp, "Hello, I am %d of %d\n", my_node, n_nodes ); fprintf( fp, "My view of the coarray is:\n" ); for ( j = 0; j < n_nodes; j++ ) { for ( k = 0; k < LSECT; k++ ) { fprintf( fp, " %f\n", coarray[j][k] ); } } coarray_report( (void**)coarray, &requested, &used ); fprintf( fp, "Coarray %s requested %ld bytes, actually used %ld bytes\n", coarray_get_name( (void**)coarray ), requested, used ); fclose( fp ); NODE_BY_NODE_END COARRAY_Finalize(); return 0; }◄ Пример 3 Пример 5 ► |
![]() |
||||||||||||||||||||||||||||||||
Тел. +7(499)220-79-72; E-mail: inform@kiam.ru |