Unified Parallel C

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку
Unified Parallel C (UPC)
Парадигма:Паралельна, імперативна (процедурна), структурна
Творці:UPC Consortium
Останній реліз:2.12.2/2011-5-18
Система типізації:Статична
Основні реалізації:GNU UPC, IBM XL UPC Compilers, HP UPC, Berkeley UPC, Michigan Tech MuPC, Cray UPC
Під впливом від:C, AC,Split-C, Parallel C Preprocessor
ОС:Крос-платформена
Сторінка інтернет:upc.gwu.edu

Unified Parallel C (UPC) - розширення мови програмування С, призначене для високопродуктивних обчислень на масштабних паралельних комп'ютерах, в тому числі на SMP/NUMA системах з загальною пам'яттю (єдиним адресним простором) і з розподіленою пам'яттю (наприклад, на кластерах). Програмісту надається доступ до всього глобального розділеного адресного простору (PGAS), збережені в ньому змінні можуть читатися і змінюватися будь-яким процесором. При цьому кожне значення зберігається у фізичній пам'яті одного з процесорів. UPC використовує модель SPMD (Single Program Multiple Data) в якій ступінь паралелізму фіксується при запуску програми, зазвичай на рівні один потік виконання на ядро ​​процесора.

Для вираження паралелізму UPC додає до ISO C 99 конструкції:

  • Явну паралельну модель виконання;
  • Загальний (поділений) адресний простір;
  • Примітиви синхронізації і модель консистентності пам'яті;
  • Примітиви управління пам'яттю.

На UPC значно вплинули три більш ранніх паралельних розширення: ISO C 99: AC, Split-C[en], і Parallel C Preprocessor (PCP). UPC не є їхньою надбудовою, а скоріше спробою об'єднати кращі їх сторони. UPC комбінує зручність програмування в парадигмі загальної пам'яті, рівень контролю за розподілом даних і продуктивності парадигми передачі повідомлень. Підтримується на різних HPC платформах.

UPC доволі простий в програмуванні, особливо для С-програмістів та порівнянні с іншими парадигмами паралельного програмування ( MPI, Charm++ ). Продуктивність UPC схожа з MPI.

Вручну оптимізований код с блоковими пересилками даних, все ж значно простіше, ніж MPI. Мова і середа виконання ( runtime ) беруть на себе рутинну роботу по комунікації.

Особливості UPC[ред. | ред. код]

Філософія[ред. | ред. код]

Філософія мови схожа на С:

  • Багато можливостей;
  • Потребує акуратності.

Реалізації[ред. | ред. код]

Існують різні реалізації стандарту UPC:

  • UPC @ GWU - розробляють стандарт http://upc.gwu.edu;
  • Berkeley UPC;
  • UPC @ MTU;
  • UPC @ Florida;
  • GCC UPC.

Доступні засоби розробки і налагодження:

  • TotalView;
  • Eclipse Parallel Tools Platform.[1]

Основні елементи[ред. | ред. код]

1) Два типи змінних:

  • Private (за замовчуванням );
  • Shared ( спеціальна директива ).

2) Shared масиви і розподіл даних по процесорам;

3) Розподіл обчислень по процесорам;[1]

4) Синхронізація і забезпечення консистентності пам'яті;

Модель виконання[ред. | ред. код]

Декілька потоків виконують одну і ту ж програму, але обробляють різні дані (SPMD):

  • Подібно MPI;
  • Немає неявної синхронізації;
  • MYTHREAD - номер даного потоку, THREADS - загальна кількість потоків;
  • Число потоків може задаватися під час компіляції, так і під час виконання ( подібно mpirun - np N)

Синхронізація застосовується тількі тоді, коли це необхідно:

  • Бар'єри;
  • Блокування (Locks);
  • Контроль консистентності пам'яті.[1]
Рис. 1 Представлення

Модель представлення пам'яті[ред. | ред. код]

Пам'ять розподілена між потоками, частина цієї пам'яті є локальною і доступна тільки потоку - власнику, інша частина пам'яті — глобальна (доступна для всіх потоків).

Управління розподілом даних[ред. | ред. код]

Приклади:[1]

Рис. 2. Результат прикладу
1 shared int x; /* will have affinity to thread 0 */
2 shared int y[THREADS];
3 int z;
4 
5 THREADS = 3 /* нехай буде 3 потоки */
Рис. 3. Результат (sharedintA[4][THREADS])
1 sharedintA[4][THREADS];

Блоковий розподіл даних (за замовчуванням розмір блоку 1)[ред. | ред. код]

shared [block - size ] type array[N];

Приклад:

Рис. 4. THREADS = 4
1 shared [3] int A [4] [THREADS];
2 THREADS = 4;

Матричне множення[ред. | ред. код]

Рис. 5. Результат матричного множення
 1 // vect_mat_mult.c
 2 #include<upc_relaxed.h>
 3 shared[THREADS] int a[THREADS][THREADS];
 4 shared int b[THREADS], c[THREADS];
 5 void main (void){
 6     nt i, j; 
 7     upc_forall( i = 0 ; i < THREADS ; i++; i){
 8         c[i] = 0;
 9         for( j=0 ; j< THREADS ; j++)
10           c[i] += a[i][j]*b[j];
11     }
12 }

Приклад паралельного скалярного множення[ред. | ред. код]

Приклад:[2]

# include <upc_relaxed.h>
# define N 1000 * THREADS

shared float A[N], B[N];
shared float MUL[N];

void scalar_mul_a_b()
{
   int i;
   upc_forall(i = 0; i < N; i++; i)
       MUL[i] = A[i] * B[i];
}

Розпаралелювання циклів[ред. | ред. код]

Синтаксис[ред. | ред. код]

upc_forall (init; test; loop; affinity)

statyment

Семантика[ред. | ред. код]

  • Ітерації циклу виконуються в потоках відповідно до локалізації параметра "affinity";
  • affinity - цілочисельний вираз або посилання на загальний об'єкт.[2]

Приклад[ред. | ред. код]

shared int a [100], b[100], c[100];
int i;
upc_forall (i = 0; i<100; i++; a[i])
    a[i] = b[i] * c[i];

Службові операції[ред. | ред. код]

Отримання розміру локальної частини глобального об'єкта:

upc_localsizeof (type-name or expression);

Отримання розміру блока глобального об'єкта:

upc_blocksizeof ( type - name or expression);

Отримання розміру елемента глобального об'єкта:

upc_elemsizeof ( type - name or expression);

Операції копіювання і ініціалізації[ред. | ред. код]

Копіювання з загальної пам'ять в загальну

upc_memcpy (dst, src, size)

Копіювання з локальної пам'яті в загальну

upc_memput (dst, src, size)

Копіювання з загальної пам'яті в локальну

upc_memget (dst, src, size)

Ініціалізація загальної пам'яті

upc_memset (dst, src, size)

Використовуваний блок загальної пам'яті повинен бути безперервним і належати одному і тому ж потоку!

Динамічний розподіл пам'яті[ред. | ред. код]

  1. Динамічний розподіл пам'яті можливий для загальної пам'яті;
  2. Операції виділення пам'яті можуть бути, як колективними, так і локальними для потоків ( префікс колективних операцій - all ).

Синтаксис[ред. | ред. код]

shared void *upc_all_alloc ( size_t nblocks, size_t nbytes );

Семантика[ред. | ред. код]

  • Виділення загальної (глобальної) пам'яті;
  • block_size - розмір блока, nblocks - кількість блоків;
  • Результат виділення пам'яті відповідає дійсності:
    shared[nbytes] char[nblocks* nbytes]
    
  • Дана операція виділення пам'яті є колективною.
  • Виділення загальної пам'яті тільки для поточного потоку, виконується за допомогою функції upc_global_alloc.

Джерела[ред. | ред. код]

Посилання[ред. | ред. код]