MPI - Scatter, Gather

Kategori: Parallel Programming , 23 Ekim 2019 , JanFranco


Broadcast işlemini görmüştük. Scatter da bu işleme çok benziyor ancak belli bir farkları mevcut. Broadcast'ta datanın tamamı tüm process'lere dağıtılır. Scatter işleminde data parçalara bölünür ve bu parçalar farklı process'lere dağıtılır. Fonksiyonu ve parametreleri görelim:


MPI_Scatter(
    void* send_data,			// Gönderilecek data
    int send_count,			// Gönderilecek datanın boyutu, eleman sayısı
    MPI_Datatype send_datatype,		// Gönderilecek datanın tipi
    void* recv_data,			// Alınacak data
    int recv_count,			// Alınacak datanın boyutu, eleman sayısı
    MPI_Datatype recv_datatype,		// Alınacak datanın tipi
    int root,				// Root
    MPI_Comm communicator)		// World
Scatter'ın tam tersi işlemini yapan, ayrıştırdığımız dataları process'lerden toplayıp root'a aktaran işlem de Gather'dır. Fonksiyonu ve parametreleri görelim:


MPI_Gather(
    void* send_data,			// Gönderilecek data
    int send_count,			// Gönderilecek datanın boyutu, eleman sayısı
    MPI_Datatype send_datatype,		// Gönderilecek datanın tipi
    void* recv_data,			// Alınacak data
    int recv_count,			// Alınacak datanın boyutu, eleman sayısı
    MPI_Datatype recv_datatype,		// Alınacak datanın tipi
    int root,				// Root
    MPI_Comm communicator)		// World
Görüleceği üzere tüm parametreleri Scatter ile aynıdır. Bu iki fonksiyonu kullanarak bir örnek yapalım. Root process'imiz rastgele sayılardan oluşan bir array tanımlasın. Diğer process'ler bu arrayin belli kısımlarını alsın ve ortalamasını bulsun. Root fonksiyonu bu ortalamaları process'lerden toplasın ve toplanan ortalamaların ortalamasını alsın. Böylece ana array'in ortalamasını bulmuş olalım:


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <mpi.h>
#include <assert.h>

float *create_rand_nums(int num_elements) {						
  float *rand_nums = (float *)malloc(sizeof(float) * num_elements);
  assert(rand_nums != NULL);
  int i;
  for (i = 0; i < num_elements; i++) {
    rand_nums[i] = (rand() / (float)RAND_MAX);
  }
  return rand_nums;
}

float compute_avg(float *array, int num_elements) {					
  float sum = 0.f;
  int i;
  for (i = 0; i < num_elements; i++) {
    sum += array[i];
  }
  return sum / num_elements;
}

int main(int argc, char** argv) {

  int num_elements_per_proc = atoi(argv[1]), world_rank, world_size;
  srand(time(NULL));
  float *rand_nums = NULL;

  MPI_Init(NULL, NULL);
  MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
  MPI_Comm_size(MPI_COMM_WORLD, &world_size);

  if (world_rank == 0) {
    rand_nums = create_rand_nums(num_elements_per_proc * world_size);			
  }

  float *sub_rand_nums = (float *)malloc(sizeof(float) * num_elements_per_proc);	

  MPI_Scatter(rand_nums, num_elements_per_proc, MPI_FLOAT, sub_rand_nums, num_elements_per_proc, MPI_FLOAT, 0, MPI_COMM_WORLD);

  float sub_avg = compute_avg(sub_rand_nums, num_elements_per_proc);
  float *sub_avgs = NULL;

  if (world_rank == 0) {
    sub_avgs = (float *)malloc(sizeof(float) * world_size);
    assert(sub_avgs != NULL);
  }

  MPI_Gather(&sub_avg, 1, MPI_FLOAT, sub_avgs, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);

  if (world_rank == 0) {
    float avg = compute_avg(sub_avgs, world_size);
    printf("Avg of all elements is %f\n", avg);
  }

  if (world_rank == 0) {
    free(rand_nums);
    free(sub_avgs);
  }
  free(sub_rand_nums);

  MPI_Barrier(MPI_COMM_WORLD);
  MPI_Finalize();
}


Yorumlar

Henüz bir yorum bulunmuyor.
Yorum bırakın