Асинхронный MPI с разделяемой памятью SysV

У нас есть большая кодовая база Fortran/MPI, которая использует сегменты разделяемой памяти system-V на узле. Мы работаем на толстых узлах с 32 процессорами, но только с 2 или 4 сетевыми картами и относительно небольшим объемом памяти на процессор; поэтому идея в том, что мы настраиваем сегмент разделяемой памяти, на котором каждый ЦП выполняет свои вычисления (в своем блоке массива SMP). Затем MPI используется для управления связью между узлами, но только на ведущем устройстве в группе SMP. Процедура имеет двойную буферизацию и отлично сработала для нас.

Проблема возникла, когда мы решили переключиться на асинхронную связь, чтобы немного скрыть задержку.Поскольку только пара ЦП на узле взаимодействует через MPI, но все ЦП видят полученный массив (через общую память), ЦП не знает, когда взаимодействующий ЦП закончил работу, если только мы не установим какой-либо барьер, и тогда зачем делать асинхронные коммуникации?

Идеальным гипотетическим решением было бы поместить теги запроса в сегмент SMP и запустить mpi_request_get_status на процессоре, который должен знать. Конечно, тег запроса регистрируется только на взаимодействующем ЦП, поэтому он не работает! Еще одна предложенная возможность заключалась в том, чтобы разветвить поток в коммуникативном потоке и использовать его для запуска mpi_request_get_status в цикле с аргументом флага в сегменте общей памяти, чтобы все остальные изображения могли видеть. К сожалению, это тоже не вариант, поскольку мы вынуждены не использовать библиотеки потоков.

Единственный жизнеспособный вариант, который мы придумали, кажется, работает, но выглядит как грязный хак. Мы помещаем невозможное значение в верхний адрес буфера приема, таким образом, после завершения mpi_irecv значение изменилось, и, следовательно, каждый ЦП знает, когда он может безопасно использовать буфер. Это нормально? Кажется, что это будет работать надежно только в том случае, если реализация MPI может гарантировать последовательную передачу данных. Звучит почти убедительно, поскольку мы написали это на Фортране, и поэтому наши массивы непрерывны; Я бы предположил, что доступ будет также.

Есть мысли?

Спасибо, Джоли

Вот шаблон псевдокода того, чем я занимаюсь.Дома у меня нет кода для справки, так что, надеюсь, я не забыл ничего важного, но я обязательно позабочусь, когда вернусь в офис...

pseudo(array_arg1(:,:), array_arg2(:,:)...)

  integer,      parameter : num_buffers=2
  Complex64bit, smp       : buffer(:,:,num_buffers)
  integer                 : prev_node, next_node
  integer                 : send_tag(num_buffers), recv_tag(num_buffers)
  integer                 : current, next
  integer                 : num_nodes

  boolean                 : do_comms
  boolean,      smp       : safe(num_buffers)
  boolean,      smp       : calc_complete(num_cores_on_node,num_buffers)

  allocate_arrays(...)

  work_out_neighbours(prev_node,next_node)

  am_i_a_slave(do_comms)

  setup_ipc(buffer,...)

  setup_ipc(safe,...)

  setup_ipc(calc_complete,...)

  current = 1
  next = mod(current,num_buffers)+1

  safe=true

  calc_complete=false

  work_out_num_nodes_in_ring(num_nodes)

  do i=1,num_nodes

    if(do_comms)
      check_all_tags_and_set_safe_flags(send_tag, recv_tag, safe) # just in case anything else has finished.
      check_tags_and_wait_if_need_be(current, send_tag, recv_tag)
      safe(current)=true
    else
      wait_until_true(safe(current))
    end if

    calc_complete(my_rank,current)=false
    calc_complete(my_rank,current)=calculate_stuff(array_arg1,array_arg2..., buffer(current), bounds_on_process)
    if(not calc_complete(my_rank,current)) error("fail!")

    if(do_comms)
      check_all_tags_and_set_safe(send_tag, recv_tag, safe)

      check_tags_and_wait_if_need_be(next, send_tag, recv_tag)
      recv(prev_node, buffer(next), recv_tag(next))
      safe(next)=false

      wait_until_true(all(calc_complete(:,current)))
      check_tags_and_wait_if_need_be(current, send_tag, recv_tag)
      send(next_node, buffer(current), send_tag(current))
      safe(current)=false
    end if

    work_out_new_bounds()

    current=next
    next=mod(next,num_buffers)+1

  end do
end pseudo

Так что в идеале мне бы хотелось запустить «check_all_tags_and_set_safe_flags» в цикле в другом потоке в процессе связи, или даже лучше: покончить с «безопасными флагами» и сделать дескриптор отправки/получения доступными на подчиненных устройствах, тогда я мог бы запустить: «check_tags_and_wait_if_need_be( current, send_tag, recv_tag)" (mpi_wait) перед расчетом на ведомых вместо "wait_until_true(safe(current))".

5
задан holyjoly 19 May 2012 в 01:05
поделиться