Лекция 5. Метод конечных разностей (параллельные алгоритмы в стандарте MPI)Alexey Paznikov
ЛЕКЦИЯ 5. Метод конечных разностей (параллельные алгоритмы в стандарте MPI)
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
TMPA-2013 Chupilko: Verification of Correct Behaviour of HDL ModelsIosif Itkin
Tools & Methods of Program Analysis (TMPA-2013)
Ivannikov, V.P., Kamkin, A.S., Chupilko, M.M., Institute for System Programming, ISP RAS
Verification of Correct Behaviour of HDL-Models of Digital Equipment Based on the Dynamic Comparison of Tracks
Слайды по представлению графов в памяти компьютера. Примеры кода на языке C++. Акценты расставлены на дообъектных представлениях, которые могут быть использованы школьниками при решении олимпиадных задач по программированию.
Лекция 5. Метод конечных разностей (параллельные алгоритмы в стандарте MPI)Alexey Paznikov
ЛЕКЦИЯ 5. Метод конечных разностей (параллельные алгоритмы в стандарте MPI)
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
http://cpct.sibsutis.ru/~apaznikov/teaching
TMPA-2013 Chupilko: Verification of Correct Behaviour of HDL ModelsIosif Itkin
Tools & Methods of Program Analysis (TMPA-2013)
Ivannikov, V.P., Kamkin, A.S., Chupilko, M.M., Institute for System Programming, ISP RAS
Verification of Correct Behaviour of HDL-Models of Digital Equipment Based on the Dynamic Comparison of Tracks
Слайды по представлению графов в памяти компьютера. Примеры кода на языке C++. Акценты расставлены на дообъектных представлениях, которые могут быть использованы школьниками при решении олимпиадных задач по программированию.
Статический и динамический полиморфизм в C++, Дмитрий ЛевановYandex
На примере некоторых архитектурных решений Крипты Дмитрий расскажет о способах реализации полиморфного поведения в программах на C++, о преимуществах и недостатках этих способов, а также о новых возможностях C++11.
Слайды использовались на краткосрочных курсах повышения квалификации учителей информатики, 2 лекции по 1 час 20 минут.
Изложен опорный (предельно ужатый) материал по основами C++.
31 мая – 1 июня в Киеве состоялась конференция HOTCODE 2013.
Сергей Тепляков, эксперт Luxoft Training по .Net, С++ и архитектуре приложений, выступил с докладом «C# Deep Dive».
Тезисы доклада:
«Когда-то в далеком 2002-м году язык C# был прост, как 2 копейки. Но у любого «живого» языка есть одна особенность, приятная и неприятная одновременно — в язык начинают добавляться новые возможности, чтобы наши с вами типовые задачи решались проще и эффективнее. Но с каждой новой возможностью появляются и свои тонкости, незнание которых может лишить столь нужных в нашей жизни конечностей, причем иногда самым изощренным образом. А поскольку язык C# развивается очень динамично, то за время жизни на его просторах появилось много маленьких грабелек, которые мы с вами и научимся обходить ;)».
Similar to Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10 (20)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10
1. Лекция 12 (часть 2):
Язык параллельного
программирования IBM X10
Курносов Михаил Георгиевич
к.т.н. доцент Кафедры вычислительных систем
Сибирский государственный университет
телекоммуникаций и информатики
http://www.mkurnosov.net
2. Программные модели ВС
Вычислительная
система с общей
памятью
(SMP, NUMA, GPU)
Вычислительная
система с
распределенной
памятью
(Cluster, MPP)
Shared
memory model
OpenMP,
Intel Cilk Plus,
Intel TBB, CUDA,
OpenCL, OpenACC
Intel Cluster OpenMP
Distributed
memory model
MPI, PVM
MPI, PVM
Partitioned
global address
space model
IBM X10, Cray Chapel,
Unified Parallel C,
OpenSHMEM
IBM X10, Cray Chapel,
Unified Parallel C,
OpenSHMEM
2
3. Программные модели ВС
P
P
P
M
Shared memory model
P
P
P
M
M
M
Distributed memory model
P
P
P
Process/thread/task
Memory (address space)
Message passing
Memory access
PGAS
3
4. IBM X10
IBM X10 – это объектно-ориентированный язык
параллельного программирования, реализующий
модель вычислительной системы с разделённым
глобальным адресным пространством
(Partitioned Global Address Space – PGAS)
Синтаксис IBM X10 основан на Java
Разработка начата в исследовательском центре
IBM им. Т. Уотсона (Thomas J. Watson Research Center)
Программа IBM PERCS (Productive, Easy-to-use, Reliable
Computing System): Blue Watters, X10, POWER7, GPFS
http://x10-lang.org
4
5. IBM X10
IBM X10 – это объектно-ориентированный язык
параллельного программирования, реализующий
модель вычислительной системы с разделённым
глобальным адресным пространством
(Partitioned Global Address Space – PGAS)
2013 – IBM X10 2.4.0
…
2009 – IBM X10 2.0
2006 – IBM X10 1.0
Лицензия: Eclipse Public License v1.0
ОС: IBM AIX (Power), IBM Blue Gene/P, GNU/Linux,
Apple Mac OS X, Microsoft Windows
5
6. Asynchronous PGAS
IBM X10 реализует расширенную версию модели PGAS –
Asynchronous Partitioned Global Address Space (APGAS)
APGAS = PGAS + динамическое управление
параллельными задачами
Модель PGAS расширена двумя конструкциями:
o place
o async
6
7. Основные понятия IBM X10
Place (область) – непрерывная часть адресного
пространства и множество потоков (activities) работающих
с ним (place можно представить как виртуальный
мультипроцессор с общей памятью – SMP-система)
Activity – поток (задача), выполняющийся в рамках
области (place, создаётся конструкциями async и at)
В общем случае n потоков (activities) может быть привязано
к m областям (places)
7
8. IBM X10: Hello, World
import x10.io.Console;
class HelloWorld {
public static def main(Array[String](1)) {
finish for (p in Place.places()) {
async at (p) {
Console.OUT.println(
"Hello, World: place " + p.id);
}
}
}
}
8
9. IBM X10: Hello, World
$ x10c++ -o HelloWorld ./HelloWorld.x10
$ export X10_NPLACES=4
$ ./HelloWorld
Hello, World: place 1
Hello, World: place 2
Hello, World: place 3
Hello, World: place 0
9
10. IBM X10
Выполнение программы начинается со статического метода
main (присутствует только у одного класса)
Спецификаторы доступа как в Java:
public, private, protected, static
Объявление переменных (Java’s non-final)
var <name>: type
Обобщенные типы (Generic type):
Array[String], Array[Int], Array[Double]
Одномерный массив из 100 элементов:
var values: Array[Double](100)
Создание неизменяемого объекта (immutable, Java’s final)
val <name> = <value>
10
11. Типы данных IBM X10
public class Test
{
public static def main(args: Array[String](1)) {
val w = 5;
val x = w as Double;
val y = 3.0;
val z = y as Int;
val d1 = (Math.log(8.0) /
Math.log(2.0)) as Int;
val d2 = Math.pow(2, d1) as Int;
}
}
11
12. Типы данных IBM X10
Byte, Short, Int, Long (8-bit, 16-bit, 32-bit, 64-bit)
UByte, UShort, UInt, ULong (8-bit, 16-bit, 32-bit, 64-bit)
Float, Double (IEEE single & double prec.)
Char (16-bit Unicode)
String, File, …
Function (ссылка на функцию):
(arg1Type, arg2Type, ...) => returnType
var funSum: (Array[Double](1)) => Double;
Приведение типов – оператор as:
var i: Int = 100;
var j: Long = i as Long;
12
14. Классы IBM X10
class Counter {
var value: Int;
public def this() {
value = 0;
}
this – указатель
на текущий объект
this() – конструктор
класса
public def this(value: Int) {
this.value = value;
}
public def inc() {
value++;
}
public def getCount(): Int {
return value;
}
}
14
15. Классы IBM X10
public class Driver {
public static def main(args: Array[String](1)) {
val c1 = new Counter();
val c2 = new Counter(12);
for (var i: Int = 0; i < 10; i++) {
c1.inc();
}
Console.OUT.println("c1 = " +
c1.getCount());
Console.OUT.println("c2 = " +
c2.getCount());
}
}
15
16. Классы IBM X10
class Team {
public static val MEMBERS_MAX = 1024;
public val name: String;
private var members: Array[String](1);
public def this() {
this(“Team”, MEMBERS_MAX);
}
public def this(name: String, size: Int) {
this.name = name;
members = new Array[String](1..size);
}
public def addMember(member: String): Int { }
protected def showMembers() { }
static def resize(team: Team, size: Int): Team { }
}
16
17. Наследование классов IBM X10
class SoccerTeam extends Team {
public var leader: String;
public var goalkeeper: String;
public def this() {
super("SoccerTeam", 11);
}
public def this(name: String, size: Int,
leader: String,
goalkeeper: String)
{
super("SoccerTeam", 11);
this.leader = leader;
this.goalkeeper = goalkeeper;
}
}
Реализовано одиночное наследование
классов (single inheritance)
17
18. Классы IBM X10
Абстрактные классы (все методы абстрактные)
public abstract class Team { ... }
public abstract def getTeamName(): String;
Интерфейсы
public interface Vector[T] {
def add(item: T);
def delete(item: T);
def getByIndex(index: Int): T;
public static VERSION = “1.0.4”;
}
class VectorString implements Vector[String] {
public def add(item: String) { ... }
}
18
19. Исключительные ситуации IBM X10
public class ReadDBL2 {
public static def main(args: Array[String](1)) {
val inputPath = args(0);
val In = new File(inputPath);
var r: FileReader = null;
try {
r = new FileReader(In);
while(true)
Console.OUT.println(r.readDouble());
} catch(eof: x10.io.EOFException) {
Console.OUT.println("Done!");
} catch(ioe: x10.io.IOException) {
Console.ERR.println(ioe);
} finally {
if (r != null) r.close();
}
}
}
19
21. Массивы IBM X10
Массив локальный для одной области (Place)
x10.array.Array
Индекс в n-мерном массиве
x10.array.Point
Множество точек (индексов)
x10.array.Region
Конструктор класса Array
Array[T](R, init)
1) R - Region (1..ArraySize)
2) Функция инициализации элементов: (Point) => 0
Свойства массива: a.region, a.size, a.rank
21
22. Массивы IBM X10
public class Driver {
public static def main(args: Array[String](1)) {
val size = 100;
val region = 1..size; /* IntRange */
val a = new Array[Int](region,
(Point) => 0);
for ([i] in a) {
a(i) = i;
Console.OUT.println(a(i));
}
}
}
22
23. Массивы IBM X10
val A1 = new Array[Int](1..10, 0);
A1(4) = A1(4) + 1;
val A4 = new Array[Int]((1..2) * (1..3) * (1..4) *
(1..5), 0);
A4(2, 3, 4, 5) = A4(1, 1, 1, 1) + 1;
23
24. Point & Range
Point p = [1, 2, 3, 4, 5];
Console.OUT.println(p.rank);
/* p.rank = 5 */
Console.OUT.println(p.get(2));
/* p.get(2) = 3 */
val r1 = 1..100;
val r2 = r1 as Region(1);
val r3 = (0..99) * (-1..20);
24
25. Массивы IBM X10
public class Driver {
public static def main(args: Array[String](1)) {
val x = new Array[String](1..1000, "oh!");
/* y = [11, 22, 33] */
val y = new Array[Int](1..3,
(i: Point(1)) =>
11 * i(0)
/* Таблица умножения */
val z = new Array[Int]((0..9) * (0..9),
(p: Point(2)) =>
p(0) * p(1));
}
}
25
26. Массивы IBM X10
static def sumArray(a: Array[Int], b: Array[Int])
{ src.region == dest.region } = {
for (p in src.region)
dest(p) += src(p);
}
public static def sum(vec: Array[Int]): Int {
var s: Int = 0;
for (p in vec)
s += vec(p);
return s;
}
26
27. Places (области) & Activities (потоки)
Метод main выполняется в потоке области 0 (place 0) –
root activity
Количество областей фиксировано и задается при запуске
программы (#export X10_NPLACES=N)
o Place.places – массив областей
o Place.places()(0) – доступ к области 0
o Place.id – номер области
o Place.MAX_PLACES
o Place.FIRST_PLACE = 0, Place.LAST_PLACE
o here – ссылка на текущую область
o Place.next(), Place.prev()
27
28. async
Порождение нового потока (activity) в текущей области
async S
Управление немедленно возвращается вызвавшему
потоку
В пределах блока S можно ссылаться на val-переменные
операторного блока из которого вызвана директива async
def start() {
val a = new Calc();
async a.run();
}
28
29. finish
Директива finish ожидает завершения дочерних потоков,
порожденных в блоке S
finish S
В главном потоке (корневом, main) неявно выполняется
синхронизация (finish)
def start(data) {
val a = new Calc();
val b = new Calc();
finish {
async a.run();
async b.run();
}
}
29
30. async + finish
public static def main(args: Array[String](1)) {
finish {
async {
for (i: Int = 0; i < 2; i++) {
async { /*...*/ }
}
finish async { /*...*/ }
}
}
}
30
31. at
Директива at позволяет явно задать существующую
область P (place), в которой следует выполнить блок S
at(P) S
Новый поток в области P не создается, туда передается
выполнение текущего потока. После завершения блока S
выполнение потока возвращается в начальную область
Операция at требует копирования в область P данных
используемых блоком S – в области P создаются их
локальные копии
Поля классов со спецификатором transient не копируются
командой at, им присваиваются значения по умолчанию
31
32. at
public static def main(Array[String](1)) {
val a = [1, 2, 3];
at(here.next()) {
a(1) = 4;
Console.OUT.println(here.id + " " + a);
}
Console.OUT.println(here.id + " " + a);
}
1 [1,4,3]
0 [1,2,3]
Place 0
o a = [1, 2, 3]
o at (1) {…}
o println(a)
Place 1
Copy a
o a(1) = 4
o println(a)
32
33. at
/* Копирует поле f из a в b */
def copyRemoteFields(a, b) {
at (b.home) b.f =
at (a.home) a.f;
}
/* Выполняет метод удаленного объекта */
def invoke(obj, arg) {
at (obj.home) {
obj().fun(arg);
}
}
33
34. Спецификатор transient полей классов
class Trans {
public val a: Int = 1;
transient public val b: Int = 2;
public def test() {
Console.OUT.println("a=" + a + " b=" + b);
at(here) {
Console.OUT.println("a=" + a +
" b=" + b);
}
}
}
a=1 b=2
a=1 b=0
34
35. Запуск корневого потока
1. Runtime-система отыскивает контейнер C (класс)
со статическим методом main
2. Формирует из аргументов командной строки
одномерный массив s строк и запускает корневой
поток следующим образом
finish async at (Place.FIRST_PLACE) {
C.main(s);
}
35
36. Atomic blocks
Директива atomic создает в текущей области критическую
секцию S
atomic S
Пока блок S не завершиться в него не войдут другие
потоки области
В пределах S нельзя: порождать потоки, использовать at
def add(x: T) {
atomic {
this.list.add(x);
this.size++;
}
}
36
37. Atomic blocks
Директива atomic создает в текущей области критическую
секцию S
atomic S
Пока блок S не завершиться в него не войдут другие
потоки области
В пределах S нельзя: порождать потоки, использовать at
atomic def add(x: T) {
this.list.add(x);
this.size++;
}
37
38. Conditional atomic block
Директива when блокирует выполнение потоков области
и не допускает их входа в критическую секцию S пока
выражение E не примет значение истина
when (E) S
Выражение E должно быть атомарным
В пределах S нельзя: порождать потоки, использовать at
def pop(): T {
var res: T;
when (size > 0) {
res = list.removeAt(0);
size--;
}
return res;
}
38
39. Conditional atomic block
class DataBuffer[T] {
var data: T;
var filled: Boolean;
def this(data: T) {
this.data = data; this.filled = true;
}
public def send(data: T) {
when (!filled) {
this.data = data; this.filled = true;
}
}
public def receive(): T {
when (filled) {
data: T = this.data;
filled = false;
return data;
}
}
}
39
40. Distributed arrays
Распределенный массив (Distributed array) –
это массив, распределенный между несколькими
областями (places)
X10.array.DistArray[T]
Распределение (distribution, X10.array.Dist) задает
распределение точек региона (region) по областям (places)
40
41. Distributions
class Driver {
public static def main(Array[String](1)) {
val R <: Region = 1..100;
val D1 <: Dist = Dist.makeBlock(R);
val D2 <: Dist = Dist.makeConstant(R, here);
}
}
D1 равномерно распределяет регион R по всем областям
(на сколько этом возможно), каждой области назначена
непрерывная последовательность индексов региона
D2 назначает все точки региона R области here
41
42. DistArray
public static def main(Array[String](1)) {
val D1 = Dist.makeUnique();
val D2 = Dist.makeBlock(1..12);
val localA: DistArray[Int] =
DistArray.make[Int](D1, ((Point) => 0));
val globalA: DistArray[Int] =
DistArray.make[Int](D2,
(([i]: Point(1)) => i));
}
Place 0
localA
globalA
Place 1
Place 2
Place 3
0
0
0
0
123
456
789
10 11 12
42
43. Проход по распределенному массиву
public static def main(Array[String](1)) {
val D1 = Dist.makeUnique();
val D2 = Dist.makeBlock(1..12);
val lSum: DistArray[Int] =
DistArray.make[Int](D1, ((Point) => 0));
val gSum: DistArray[Int] =
DistArray.make[Int](D2, (([i]: Point(1)) => i));
finish {
for (p in gSum.dist.places()) {
async at (p) {
for (localPoint in gSum | here)
lSum(p.id) += gSum(localPoint);
}
}
}
43
44. Проход по распределенному массиву
public static def main(Array[String](1)) {
/* ... */
var sum: Int = 0;
for (p in lSum.dist.places()) {
sum += (at (p) localSum(p.id));
}
}
44
45. ateach
Директива ateach позволяет выполнить блок S в каждой
области
ateach (p in D) S
Действия ateach эквивалентны следующему фрагменту
for (place in D.places()) {
async at (place) {
for (p in D | here) {
S(p);
}
}
}
45
46. IBM X10 Backends
Java backend (x10c)
Один процесс – все области (places) в одной виртуальной
машине JVM (Java 5)
C++ backend (x10c++)
Один процесс на SMP-узел (1 область на SMP-узел)
46
47. Пример ArraySum (serial version)
public class ArraySum {
var sum: Int;
val data: Array[Int](1);
def this(size: Int) {
/* 1-dim array filled with 1 */
data = new Array[Int](size, 1);
sum = 0;
}
def computeSum() {
sum = 0;
for (i in data) {
sum += data(i);
}
}
}
47
48. Пример ArraySum (serial version)
public class ArraySum {
/* ... */
public static def main(args: Array[String](1)) {
var size: Int = 10;
if (args.size >= 1)
size = Int.parse(args(0));
val a = new ArraySum(size);
a.computeSum();
Console.OUT.println(“Sum: " + a.sum);
}
}
48
49. Пример ArraySum (parallel version 1)
public class ArraySum {
/* ... */
def sum(a:
var s:
for (i
s
return
}
Array[Int](1), l: Int, h: Int): Int {
Int = 0;
in l..(h - 1))
+= a(i);
Activity 1
Activity 2
Activity 0
s;
-3 2 2 0 4 3 4 6 7 8 9 2 4 1 5 4 5 6 5 4 5 6
def sum(nthreads: Int) {
chunk
sum = 0;
val chunk = data.size / nthreads;
finish for (p in 0..(nthreads - 1)) async {
val sumlocal = sum(data, p * chunk,
(p + 1) * chunk);
atomic sum += sumlocal;
}
}
}
49
50. Пример ArraySum (parallel version 1)
public class ArraySum {
/* ... */
public static def main(args: Array[String](1)) {
var nthreads: Int = 1;
var size: Int = 10;
if (args.size >= 1)
size = Int.parse(args(0));
if (args.size >= 2)
nthreads = Int.parse(args(1));
val a = new ArraySum(size);
a.sum(nthreads);
Console.OUT.println("Result: " + a.sum);
}
}
Single place version
50
51. Пример ArraySum (parallel version 2)
public class ArraySum {
/* ... */
}
def sum_roundrobin(nthreads: Int) {
sum = 0;
finish for (p in 0..(nthreads - 1)) async {
var sumlocal: Int = 0;
for (var i: Int = p; i < data.size;
i += nthreads)
{
sumlocal += data(i);
}
atomic sum += sumlocal;
}
data: Thread Thread Thread Thread Thread Thread …
}
0
1
2
0
1
2
51
52. Числа Фибоначчи (serial version)
class Fib {
static def fib(n: Int): Int {
if (n < 2)
return n;
val x = fib(n - 1);
val y = fib(n - 2);
return x + y;
}
public static def main(args:Array[String](1)) {
val n = fib(30);
Console.OUT.println("Fib = " + n);
}
}
52
53. Числа Фибоначчи (parallel version)
class Fib {
static def fib_parallel(n: Int): Int {
val x: Int;
val y: Int;
if (n < 2) return n;
finish {
async x = fib(n - 1);
y = fib(n - 2);
}
return x + y;
}
public static def main(args:Array[String](1)) {
val n = fib_parallel(30);
Console.OUT.println("Fib = " + n);
}
}
53
54. Вычисление числа Pi
public class Pi {
public static def main(args:Array[String](1)) {
val N = 100000;
val init = (i: Point) => {
y
val r = new Random();
1
var m: Double = 0.0D;
1 x
for (c in 1..N) {
val x = r.nextDouble();
val y = r.nextDouble();
4𝑚
if (x * x + y * y <= 1.0)
𝜋≈
𝑛
m++;
}
m
};
54
55. Вычисление числа Pi
public class Pi {
public static def main(args:Array[String](1)) {
val N = 100000;
val init = (i: Point) => { /* ...*/ };
val r = DistArray.make[Double](
Dist.makeUnique(), init);
val pi = 4 * r.reduce(
(x: Double, y: Double) =>
x + y, 0.0) /
(N * Place.MAX_PLACES);
Console.OUT.println("Pi = " + pi);
}
}
55