1. Язык параллельного
программирования Cray Chapel
Михаил Курносов 1, 2
1 Сибирский
2 Институт
государственный университет телекоммуникаций и информатики
физики полупроводников им. А.В. Ржанова СО РАН
Email: mkurnosov@gmail.com
WWW: http://www.mkurnosov.net
Семинар “Вычислительные системы”
6 ноября 2013
2. Модели параллельных вычислений
P
P
P
Memory
P
P
P
M
M
M
Shared memory model
Distributed memory model
C++11 Threads, OpenMP,
Intel Cilk Plus, Intel TBB,
NVIDIA CUDA, OpenCL, OpenACC
MPI, PVM, Shmem
Process/thread/task
Message passing
Memory (address space)
Locale memory access
2
3. Предпосылки возникновения модели PGAS
Распространение мультиархитектурной (гибридной) организации
вычислительных систем
Многопроцессорные NUMA-узлы с иерархической памятью
(HyperTransport, Intel QuickPath Interconnect)
Специализированные ускорители: GPU (NVIDIA, ATI), Intel Xeon Phi
Многомерные и
многоуровневые топологии
коммуникационных сетей:
AMD Opteron
Interlagos (16 cores)
2 nodes Cray XK7
Cray Gemeni
(3D torus)
Fujitsu Tofu
(6D mesh/torus)
IBM BG/Q 5D torus
Fat tree
3
4. Предпосылки возникновения модели PGAS
Разработка эффективных параллельных программ
для мультиархитектурных ВС требует владения стеком технологий
Internode communications:
MPI, Cray Chapel, IBM X10, Shmem, Unified Parallel C, Coarray Fortran,
Global Arrays
Multithreading: OpenMP, Intel TBB/Cilk Plus, C11/C++11 Threads
GPU: NVIDA CUDA, OpenCL,
OpenACC, OpenMP 4.0
AMD Opteron
Interlagos (16 cores)
2 nodes Cray XK7
Vectorization (SIMD):
SSE/AVX, AltiVec
SSE/AVX
MPI, Cray Chapel, Shmem,
Coarray Fortran, Unified Parallel C
NVIDIA CUDA,
OpenCL, OpenACC
OpenMP, Intel TBB, Cilk,
POSIX Threads
4
6. Partitioned Global Address Space – PGAS
Partitioned Global Address Space (PGAS) – модель параллельных вычислений
с разделенным глобальным адресным пространством
Память параллельной программы глобально адресуема (global address space)
Адресное пространство логически разбито (partitioned) на блоки локальной
памяти потоков/процессов
Языки семейства PGAS: Cray Chapel, IBM X10, Coarray Fortran, Global Arrays,
Titanium, Unified Parallel C, Sun Fortress (проект закрыт)
P
P
P
Local
memory
Local
memory
Local
memory
Process/thread/task
Memory (address space)
Message passing
Local memory access
Global address space
6
7. Cray Chapel
Cray Chapel – язык параллельного программирования,
реализующий модель вычислительной системы
с разделенным глобальным адресным пространством
(Partitioned Global Address Space – PGAS)
Язык создан и развивается Cray Inc.
Программа DARPA: High Productivity Computing Systems
BSD License
ОС: UNIX, GNU/Linux, Mac OS X, Windows (Cygwin)
2013 – Chapel 1.8
2012 – Chapel 1.7
2007 – Chapel 0.5
2006 – Chapel 0.4
http://chapel.cray.com
7
8. Дизайн Cray Chapel
ZPL, HPF: data parallelism, index sets, distributed arrays
CRAY MTA C/Fortran: task parallelism, synchronization
CLU (Ruby, Python, C#): iterators
Scala (ML, Matlab, Perl, Python, C#): type inference
Java, C#: OOP, type safety
C++: generic programming/templates
Chapel Language Specification (version 0.94):
http://chapel.cray.com/spec/spec-0.94.pdf
http://chapel.cray.com
8
9. Основные определения
Locale – абстракция вычислительной единицы, в рамках которой
выполняются задачи (tasks) и реализуется однородный доступ
к памяти
Locale – абстракция многопроцессорного SMP-узла, NUMA-узла
Задачи создаются динамически
Сеть InfiniBand (вычислительная сеть)
Ядро
Ядро
Процессор
Ядро
Общая память
Ядро
Процессор
Общая память
Frontend (login node)
Процессор
Ядро
Ядро
Общая память
Процессор
Ядро
Ядро
Compute node 1
Процессор
Ядро
Ядро
Общая память
Процессор
Ядро
Ядро
Compute node 2
Процессор
Ядро
Ядро
Общая память
Процессор
Ядро
Ядро
Compute node 3
Процессор
Ядро
Ядро
Процессор
Ядро
Ядро
Compute node 4
Сеть Gigabit Ethernet (сервисная сеть: NFS, DNS, DHCP, ssh, …)
Locale
Locale
Locale
Locale
9
10. Использование Chray Chapel на кластере Jet
Добавляем в конец файла ~/.bashrc строку
“source /opt/etc/chapel-vars.sh” (выполняется единожды):
$ cat ~/.bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
source /opt/etc/chapel-vars.sh
Отключаемся от кластера (exit) и заходим снова
$ ssh mkurnosov@jet.cpct.sibsutis.ru
$ which chpl
/opt/chapel-1.8.0/bin/linux64/chpl
10
12. Hello World!
proc main() {
// Write message from each locale
for loc in Locales do {
on loc {
writeln("Hello World from locale ", here.id,
" (", here.name, ")");
}
}
}
Компилируем программу:
$ chpl -o prog ./prog.chpl
Компилятор создает два исполняемых файла:
-rwxrwxr-x 1 prog
-rw-rw-r-- 1 prog.chpl
-rwxrwxr-x 1 prog_real
# Стартовый файл (инициализация)
# Код программы
12
13. Hello World!
Формируем job-файл для системы пакетной обработки
заданий TORQUE
$ cat task.job
#PBS -N MyChapelJob
#PBS -l nodes=4:ppn=8
#PBS -j oe
# Захватываем все ядра узла
cd $PBS_O_WORKDIR
chplrun ./prog
Ставим задание в очередь системы TORQUE:
$ qsub ./task.job
20890.jet
13
14. AMUDPRUN: GASNet launcher
Модуль amudprun (GASNet) запускает процессы на узлах
кластера по SSH
Скрипт chplrun запускает через amudprun программу на узлах
кластера – интегрирует Cray Chapel и TORQUE
$ cat /opt/bin/chplrun
#!/bin/sh
nodes=`cat $PBS_NODEFILE | uniq | tr "n" " "`
nnodes=`echo $nodes | wc -w`
export GASNET_SPAWNFN=S
export SSH_SERVERS="$nodes"
$@ -nl $nnodes
14
15. Возможности Cray Chapel
Поддержка объектно-ориентированного программирования
(class, record)
Статическая типизация
Модули (module) для реализации концепции пространств имен
(namespaces)
Task parallelism
Динамическое управление параллельными задачами
(begin, cobegin)
Примитивы синхронизации (типы sync, single)
Data parallelism:
Типы данных для управления распределенными массивами
(range, domain, array, …)
Конструкции для параллельных операций над распределенными
массивами (forall, coforall, reduce, scan)
15
16. Базовые типы данных (Primitive types)
Синтаксис определения переменных
var <VariableName>: <DataType>;
Базовые типы данных (primitive types):
void
bool – логический тип данных (значение true или false)
int – целочисленный тип (целое со знаком, с версии 1.5
занимает 64 бита)
uint – целочисленный тип (беззнаковое целое число)
Целочисленный тип с заданным размером
int(8), int(16), int(32), int(64)
uint(8), uint(16), uint(32), uint(64)
16
17. Базовые типы данных (Primitive types)
real – вещественный тип данных (64 бита, IEEE 754)
real(32), real(64)
complex – комплексный тип
(мнимая и действительная части типа real, 128 бит)
complex(64), complex(128)
string – строковый тип (ASCII символы)
17
18. Базовые типы данных (Primitive types)
var
var
var
var
var
var
var
i1: int = -4;
i2: uint = 0x3AFFDC;
i3: int(32) = 1000;
r1: real = 3.14;
r2: real = 45E-4;
c: complex = 3.14 + 2.72i;
s: string = "Hello, World";
writeln("i1 = ", i1, " i2 = ", i2, " i3 = ", i3);
writeln("r1 = ", r1, " r2 = ", r2);
writeln("c = ", c, " c.re = ", c.re,
" c.im = ", c.im);
writeln("s = ", s);
i1 = -4 i2 = 3866588 i3 = 1000
r1 = 3.14 r2 = 0.0045
c = 3.14 + 2.72i c.re = 3.14 c.im = 2.72
s = Hello, World
18
19. Константы
Константы времени компиляции (compile-time constants)
param <ConstName>: <DataType> = <Value>;
Константы времени выполнения (runtime-time constant)
const <ConstName>: <DataType> = <Value>;
param GridSize: int = 64;
const Cols = f(3);
19
20. Конфигурируемые переменные
Конфигурируемые переменные (configuration variables) –
переменные, начальные значения которых можно задавать
через аргументы командной строки программы или файл
config const <VarName>: <DataType>;
config const MatrixRows = 100;
config const MatrixCols = 100;
writeln(MatrixRows, " ", MatrixCols);
chpl –o prog ./prog.chpl
./prog --MatrixRows=64 --MatrixCols=32
64 32
20
21. Перечисляемый тип данных (enumerated)
Перечисляемый тип (Enumerated type) позволяет
задавать множество именованных констант
enum <EnumName> {<const1>, <const2>, ...};
enum NodeColor {Red = 2, Green, Blue};
var e: NodeColor = NodeColor.Green;
var k: int = e;
writeln("e = ", e, ", NodeColor.Green = ",
NodeColor.Green, ", k = ", k);
e = Green, NodeColor.Green = Green, k = 3
21
22. Ветвления (conditional expressions)
Ветвления if-else подобны ветвлениям в C/C++
var i = 3;
var flag = if (i % 2) then i / 2 + 1 else i / 2;
writeln("flag = ", flag);
if (flag > 100) {
flag = 1;
}
22
23. Ветвления (conditional expressions)
Ветвления select подобны ветвлениям switch в C/C++
var MsgType: int;
select (MsgType) {
when 1 {
// Process 1
}
when 2 {
// Process 2
}
otherwise {
// Process alternative cases
}
}
23
24. Цикл for
for <index-var-decl> in <iteratable-expr> do
expr
for (i, j) in (1..3, 4..6) do
write(i, " ", j, " ");
1 4 2 5 3 6
24
25. Цикл for
for <index-var-decl> in <iteratable-expr> do expr
for i in -3..2 do {
writeln(i, " ");
}
var A = for i in 0..10 do if i % 2 == 0 then i;
writeln(“A = ”, A);
-3
-2
-1
0
1
2
A = 0 2 4 6 8 10
25
26. Циклы while, do
while (condition) {
// Loop body
}
do {
// Loop body
} while (condition);
26
28. Переменное количество аргументов
proc WriteData(x ...?k) {
for param i in 1..k do
writeln(x(i));
}
proc sum(a: int...3) {
return a(1) + a(2) + a(3);
}
var x = sum(1, 2, 3);
/* x = 6 */
28
29. Модули (Modules)
Программа на Cray Chapel состоит из одного или
нескольких модулей (module)
Модули предназначены для управления областью
видимости переменных (namespaces)
В одном файле может быть описано несколько модулей
(названия модулей не привязаны к именам файлов)
Если в файле нет явного описания модуля, создается
модуль по умолчанию, имя которого совпадает
с названием файла (без расширения “.chpl”)
29
31. Использование модулей (use)
module ModuleA {
use ModuleB;
var x: int = 2;
proc main() {
ModuleB.x = 4;
ModuleB.printX();
}
}
module ModuleB {
var x: int = 3;
proc printX() {
writeln(“x = ", x);
}
}
31
32. Последовательность запуска программы
Выполнение программы начинается с инициализации всех
модулей – выполняется код модулей вне функций
В одном из модулей (главном модуле) вызывается
функция main()
Все модули, указанные в директивах use главного
модуля обходятся в глубину (depth-first traversal)
и инициализируются в обратном порядке (post order)
32
33. Инициализация модулей
module M1 {
use M2.M3;
use M2;
writeln("In M1’s initializer");
proc main() {
writeln("In main");
}
}
M1
use
use
M3
M2
module M2 {
use M4;
writeln("In M2’s initializer");
module M3 {
writeln("In M3’s initializer");
}
}
module M4 {
writeln("In M4’s initializer");
}
use
M4
Depth-first traversal:
post-order init
33
35. Массивы
Массив (array) – это отображение множества индексов
(domain) на набор однотипных элементов
ArrayName [DomainExpression] DataType
DomainExpression – множество индексов массива, домен
(domain) определяет структуру и размерность индексов
массива
const D: domain(2) = [1..10, 1..10];
var A: [D] real;
// Domain
// Array 10x10
var B: [-1..3] int = (4, 5, 1, 3, 9);
// Anon. domain
var A: [1..2] [1..3] real = [[1.1, 1.2, 1.3],
[2.1, 2.2, 2.3]];
35
36. Домены
Cray Chapel поддерживает домены различных видов
Dense (регулярные плотно заполненные массивы)
Strided (периодически заполненные массивы)
Sparse (разряженные массивы)
Unstructured (сетки произвольной структуры)
Домен может быть распределён по памяти нескольких
локалей
36
37. Доступ к элементам массива
var A: [1..10] real;
A(1) = 1.2;
A[2] = 3.4;
var B: [1..5, 1..5] real;
var ij: 2*int = (1, 1);
B(ij) = 1.1;
B((1, 2)) = 1.2;
B(1, 3) = 1.3;
B[ij] = -1.1;
B[(1, 4)] = 1.4;
B[1, 5] = 1.5;
37
38. Массивы
/* Массив с индексами: 1, 3, 5, 7, 9 */
var X: [1..10 by 2] int;
for i in X.domain do
writeln(i);
Ссылки на массивы (Array aliases)
/* AA – псевдоним массива A */
var A: [1..5, 1..5] int;
var AA: [0..2, 0..2] => A[2..4, 2..4];
/* AA(1, 1) = A(3, 3) */
38
39. Операции над доменами (Slicing)
var OuterD: domain(2) = {0..n + 1, 0..n + 1};
var InnerD: domain(2) = {1..n, 1..n};
var A, B: [OuterD] real;
// ...
A[InnerD] = B[InnerD];
// slice A[0..n + 1, 0] – first column of A
OuterD
InnerD
39
40. Перебор элементов массива
var A: [1..5, 1..5] real;
for a in A do
writeln(a);
# Перебор значений
for i in A.domain do
writeln(a[i]);
# Перебор индексов
var len: int = 5;
var S: [1..len] string = (“red”, “green”,
“black”, “yellow”,
“blue”);
for s in S do
write(a," ");
40
41. Присваивание массивов
var A: [1..5, 1..5] real;
var B: [1..5, 1..5] real;
A = B;
forall (a, b) in (A, B) do
a = b;
# Parallel loop
41
42. Записи и классы
Записи и классы – это составные типы данных,
содержащие методы и поля
При присваивании экземпляра записи (record) другому
её экземпляру выполняется копирование её полей
(аналог присваивания структур в языке C)
При присваивании экземпляра класса (class) другому
его экземпляру выполняется копирование ссылки на
объект класса
42
43. Классы
class GameObject {
var x, y: real;
var name: string;
proc GameObject(x: real, y: real) {
this.x = x;
this.y = y;
this.name = "Object";
}
proc GameObject(name: string) {
this.x = 0.0;
this.y = 0.0;
this.name = name;
}
}
var obj2 = new GameObject(34.25, 12.56);
var obj3 = new GameObject("Bullet");
writeln(obj3);
{x = 0.0, y = 0.0, name = Bullet}
43
44. Setters & Getters
class Counter {
var count: int;
var x: int;
proc x var {
if setter then {
count += 1;
writeln("Setter is called");
} else {
writeln("Getter is called");
}
return x;
}
setter = true
в поле записали
новое значение
setter = false
поле “читают”
}
var c = new Counter();
c.x = 4;
var temp = c.x;
/* setter = true */
/* setter = false */
44
45. Удаление объекта
В спецификации Cray Chapel подразумевается,
что runtime-система реализует сборку мусора и все
экземпляры классов удаляются автоматически
Для принудительного удаления объекта следует
использовать конструкцию delete
var obj = new GameObject(34.25, 12.56);
/* Code ... */
delete obj;
45
46. Тип Locale
Locale – это локальная память и множество параллельных задач,
использующих её (абстрактное представление SMP/NUMA-узла)
Тип данных locale:
proc locale.callStackSize: uint(64)
– размер стека задач, выполняющихся в этой локали
proc locale.id: int
– номер локали (0, 1, …)
proc locale.name: string
– имя локали
proc locale.numCores: int
– количество процессорных ядер доступных в локали
46
47. Предопределенные переменные
config const numLocales: int – количество локалей
const LocaleSpace: domain(1) = [0..numLocales-1];
const Locales: [LocaleSpace] locale –
массив локалей программы
here – ссылка на локаль, в которой выполняется текущая
задача
Процедура main запускается в локали 0 (Locales[0])
47
48. Ключевое слово On
Конструкция on задает локаль (locale), в которой следует
выполнять блок инструкций и размещать его данные
on <locale> do <expr>
var x: int = 10;
on Locales(1) {
var y: real = 3.14;
writeln(here.id);
}
Locale 0
x = 10
// Locale 0
// Locale 1
Locale 1
y = 3.14
48
49. Ключевое слово On
Конструкция on задает локаль (locale), в которой следует
выполнять блок инструкций и размещать его данные
on <locale> do <expr>
var a: int = 1;
on Locales(1) {
var b: int = 2;
writeln("Locale 1: a = ", a, " b = ", b);
}
// a = 1, b = 2
on Locales(1) {
// Launch a task on Locale 1 (empty stack)
// ERROR: error: 'b' undeclared
writeln("a = ", a, " b = ", b);
}
49
50. Locale
class C {}
record R {}
on Locales(1) {
var x: int;
var c: C;
var r: R;
// reference
// value
on Locales(2) {
on Locales(3) {
c = new C();
r = new R();
}
writeln(x.locale.id);
writeln(c.locale.id);
writeln(r.locale.id);
}
}
1
3
1
50
51. Скрытые обмены информацией
var x, y: real;
// x and y allocated on loc 0
on Locales(1) {
var z: real;
z = x + y;
// migrate task to loc 1
// z allocated on loc 1
// remote reads of x and y
on Locales(0) do
z = x + y;
on x do
z = x + y;
}
//
//
//
//
//
//
//
migrate back to loc 0
remote write to z
migrate back to loc 1
data migration to loc 0
remote write to z
migrate back to loc 1
migrate back to loc 0
Locale 0
x
y
Locale 1
z
51
52. Task parallelism: конструкция begin
Конструкция begin порождает новую задачу (task)
и выполняет в ней блок инструкций (в текущей локали)
begin <statement>
Выполнение родительской задачи не блокируется
for i in 1..3 do {
begin writeln("Task ", i);
}
Task 1
Task 2
Task 3
52
53. Task parallelism: конструкция begin
Конструкция cobegin порождает новую задачу для каждого оператора
в блоке
cobegin {
statement1();
statement1();
...
statementN();
}
Выполнение родительской задачи блокируется пока не завершат
работу все дочерние задачи
cobegin {
writeln("Task 1");
writeln("Task 2");
writeln("Task 3");
}
writeln("Main task");
Task
Task
Task
Main
1
2
3
task
53
54. Data parallelism: конструкция forall
Конструкция forall сообщает компилятору, что все итерации
цикла можно выполнять параллельно
Создание отдельной задачи для каждой итерации
не гарантируется
Выполнение продолжается когда все итерации цикла будут
завершены
var sum: int = 0;
forall i in 1..1000000 {
sum += i;
/* Data race */
}
writeln(sum);
forall i in 1..N do
a(i) = b(i);
54
55. Data parallelism: конструкция coforall
Конструкция coforall создает для каждой итерации цикла
отдельную задачу
Выполнение продолжается когда все итерации цикла
будут завершены
coforall i in iterator() {
loop_body();
}
config const ntasks = here.numCores;
coforall rank in 0..ntasks - 1 {
writeln("Task ", rank, " of ", ntasks);
}
55
56. Переменные синхронизации
Переменная синхронизации (synchronization variable) –
это переменная заданного типа имеющая логическое
состояние full (заполнена) или empty (пуста)
Переменная синхронизации не может быть прочитана
(read) пока она находится в состоянии empty
Переменная синхронизации не может быть записана
пока она находится в состоянии full
Типы переменных синхронизации (для базовых типов)
Тип переменной
Запись переменной
Чтение переменной
single
Один раз, состояние
меняется на full
Состояние
не меняется (full)
sync
Состояние
меняется на full
Состояние
меняется на empty
56
57. Переменные синхронизации
Если переменной синхронизации присвоено начальное
значение, то она в состоянии full
При попытке доступа к переменной (read, write) задачи
ожидают пока, она не перейдет в корректное состояние
var lock$: sync bool;
var sum: int = 0;
forall i in 1..100000 {
lock$ = true;
// Write: lock is full now
sum += i;
lock$;
// Read: lock is empty now
}
writeln(sum);
57
58. Переменные синхронизации
Если переменной синхронизации присвоено начальное
значение, то она в состоянии full
При попытке доступа к переменной (read, write) задачи
ожидают пока, она не перейдет в корректное состояние
var count$: sync int = 0;
begin count$ = count$ + 1;
begin count$ = count$ + 1;
begin count$ = count$ + 1;
58
59. Методы переменных синхронизации
readXX, readFE, readFF(), writeEF(), writeFF(),
reset(), isFull()
var x$: sync int;
var y$: single int;
var z: int;
x$ = 5;
y$ = 6;
z = x$ + y$;
// full now
// full now
// x – empty, y - full
x$.writeEF(5);
y$.writeEF(6);
z = x$.readFE() +
y$.readFF();
//
//
/*
/*
Ждет
Ждет
Ждет
Ждет
empty -> записывает -> full
empty -> записывает -> full
full -> читает -> empty */
full -> читает -> full */
59
61. Переменные синхронизации
coforall i in iterator()
loop_body();
var runningCount$: sync int = 1; // full
var finished$: single bool;
for i in iterator() {
runningCount$ += 1; // Number of tasks + 1 for main
begin {
loop_body();
var temp = runningCount$;
runningCount$ = temp - 1;
if temp == 1 then
finished$ = true;
}
}
var temp = runningCount$;
runningCount$ = temp - 1;
if temp == 1 then
finished$ = true;
finished$;
61
62. Числа Фибоначчи (sequential version)
proc fib(n: int): int {
if (n < 2) {
return n;
}
var x, y: int;
x = fib(n - 1);
y = fib(n - 2);
return x + y;
}
writeln("Fib(35) = ", fib(35));
62
63. Числа Фибоначчи (parallel version – single locale)
proc fib(n: int): int {
if (n < 2) {
return n;
}
var x$: sync int;
begin x$ = fib(n - 1);
var y: int = fib(n - 2);
return x$ + y;
// Wait for full x$
}
writeln("Fib(35) = ", fib(35));
63
64. Data parallelism: reductions & scans
var A: [1..10] int;
A = 1;
var sum = + reduce A;
writeln(sum);
var A, B, C: [1..5]
A = 1;
B = + scan A;
B[3] = -B[3];
C = min scan B;
int;
// A:
// B:
// B:
// C:
1
1
1
1
1
2
2
1
1 1 1
3 4 5
-3 4 5
-3 -3 -3
Поддерживаемые операции:
+, *, &&, ||, &, |, ^, min, max, minloc, maxloc
64
65. Data parallelism: distributions
Спецификатор dmapped задает алгоритм распределения домена
(массива) между памятью локалей
var D = [1..m];
var A: [D] real;
var D = [1..m] dmapped Block(boundingBox = [1..m]);
var A: [D] real;
Locale 0
Locale 1
Locale 2
Locale 3
65
66. Решение краевой задачи методом Якоби
Граничные
условия
Крестообразный
вычислительный
шаблон
66
67. Решение краевой задачи методом Якоби
config const n = 40;
// Размер сетки
config const eps = 1E-2;
param Pi: real = 3.141592653589793238462643;
const
const
const
const
const
const
BigD: domain(2) = {0..n + 1, 0..n + 1};
D: subdomain(BigD) = {1..n, 1..n}; // Без внешних границ
FirstRow: subdomain(BigD) = D.exterior(-1, 0);
LastRow: subdomain(BigD) = D.exterior(1, 0);
FirstCol: subdomain(BigD) = D.exterior(0, -1);
LastCol: subdomain(BigD) = D.exterior(0, 1);
var grid, newgrid: [BigD] real;
67
68. Решение краевой задачи методом Якоби
proc main() {
// Initial conditions
grid[D] = 0.0;
[(i, j) in FirstRow] grid[i, j] =
sin(Pi * (j: real / (n + 2.0)));
[(i, j) in LastRow] grid[i, j] =
sin(Pi * (j: real / (n + 2.0))) * exp(-Pi);
grid[FirstCol] = 0.0;
grid[LastCol] = 0.0;
Single locale version
(многопоточная)
var iters = 0;
do {
forall (i, j) in D {
newgrid[i, j] = (grid[i - 1, j] + grid[i + 1, j] +
grid[i, j - 1] + grid[i, j + 1]) * 0.25;
}
const maxdiff = max reduce abs(newgrid[D] - grid[D]);
grid[D] = newgrid[D];
iters += 1;
} while (maxdiff > eps);
}
68
69. Транспонирование матрицы (PTRANS)
T[i,
A
use BlockCycDist;
j] = A[j, i]
// Блочно-циклическое распределение массивов
config type eltType = real(64);
config const numrows = 100,
numcols = 100,
rowBlkSize = 8,
colBlkSize = 8,
beta = 1.0;
//
//
//
//
Строк в матрице
Столбцов в матрице
Строк в блоке
Столбцов в блоке
config const epsilon = 2.2e-16;
69
75. Открытые задачи
Развитие методов оптимизирующей компиляции
Оптимизация скрытых обменов
Обнаружение паттернов последовательного доступа
к удаленной памяти и укрупнение передаваемых блоков между
узлами (аналог векторизации кода, предвыборка, …)
Совмещение вычислений и обменов
Статический анализ Chapel-программ для обнаружения участков
кода, выполнение которых можно совместить с передачей
информации (overlapping)
Развитие методов динамического управления легковесными задачами
(task layer scheduling, hierarchical work stealing)
Развитие методов реализации переменных синхронизации
(software transactional memory?)
…
75