55
Лекция 12 (часть 2): Язык параллельного программирования IBM X10 Курносов Михаил Георгиевич к.т.н. доцент Кафедры вычислительных систем Сибирский государственный университет телекоммуникаций и информатики http://www.mkurnosov.net

Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Embed Size (px)

Citation preview

Page 1: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Лекция 12 (часть 2):

Язык параллельного

программирования IBM X10

Курносов Михаил Георгиевич

к.т.н. доцент Кафедры вычислительных систем

Сибирский государственный университет

телекоммуникаций и информатики

http://www.mkurnosov.net

Page 2: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Программные модели ВС

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

Page 3: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Программные модели ВС

33

P

M

P

M

P

M

P

M

P P

Shared memory model Distributed memory model

P P P

PGAS

Process/thread/task

Memory (address space)

Message passing

Memory access

Page 4: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

IBM X10

44

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

Page 5: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

IBM X10

55

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

Page 6: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Asynchronous PGAS

66

IBM X10 реализует расширенную версию модели PGAS –

Asynchronous Partitioned Global Address Space (APGAS)

APGAS = PGAS + динамическое управление

параллельными задачами

Модель PGAS расширена двумя конструкциями:

o place

o async

Page 7: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Основные понятия IBM X10

77

Place (область) – непрерывная часть адресного

пространства и множество потоков (activities) работающих

с ним (place можно представить как виртуальный

мультипроцессор с общей памятью – SMP-система)

Activity – поток (задача), выполняющийся в рамках

области (place, создаётся конструкциями async и at)

В общем случае n потоков (activities) может быть привязано

к m областям (places)

Page 8: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

IBM X10: Hello, World

88

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);

}

}

}

}

Page 9: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

IBM X10: Hello, World

99

$ 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

Page 10: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

IBM X10

1010

Выполнение программы начинается со статического метода

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>

Page 11: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Типы данных IBM X10

1111

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;

}

}

Page 12: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Типы данных IBM X10

1212

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;

Page 13: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Динамическое создание функций

1313

val r = new Random();

val rand = () => r.nextDouble();

val inCircle = countPoints(N, rand);

Page 14: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Классы IBM X10

14

class Counter {

var value: Int;

public def this() {

value = 0;

}

public def this(value: Int) {

this.value = value;

}

public def inc() {

value++;

}

public def getCount(): Int {

return value;

}

}14

this – указатель

на текущий объект

this() – конструктор

класса

Page 15: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Классы IBM X10

15

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

Page 16: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Классы IBM X10

16

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

Page 17: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Наследование классов IBM X10

1717

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)

Page 18: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Классы IBM X10

1818

Абстрактные классы (все методы абстрактные)

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) { ... }

}

Page 19: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Исключительные ситуации IBM X10

19

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

Page 20: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Исключительные ситуации IBM X10

20

{

throw new x10.io.FileNotFoundException(

“Bad path ” + path);

}

20

Page 21: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Массивы IBM X10

2121

Массив локальный для одной области (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

Page 22: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Массивы IBM X10

2222

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));

}

}

}

Page 23: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Массивы IBM X10

2323

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;

Page 24: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Point & Range

2424

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);

Page 25: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Массивы IBM X10

2525

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));

}

}

Page 26: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Массивы IBM X10

2626

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;

}

Page 27: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Places (области) & Activities (потоки)

2727

Метод 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()

Page 28: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

async

2828

Порождение нового потока (activity) в текущей областиasync S

Управление немедленно возвращается вызвавшему

потоку

В пределах блока S можно ссылаться на val-переменные

операторного блока из которого вызвана директива async

def start() {

val a = new Calc();

async a.run();

}

Page 29: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

finish

29

Директива 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

Page 30: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

public static def main(args: Array[String](1)) {

finish {

async {

for (i: Int = 0; i < 2; i++) {

async { /*...*/ }

}

finish async { /*...*/ }

}

}

}

async + finish

3030

Page 31: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

at

31

Директива at позволяет явно задать существующую

область P (place), в которой следует выполнить блок S

at(P) S

Новый поток в области P не создается, туда передается

выполнение текущего потока. После завершения блока S

выполнение потока возвращается в начальную область

Операция at требует копирования в область P данных

используемых блоком S – в области P создаются их

локальные копии

Поля классов со спецификатором transient не копируются

командой at, им присваиваются значения по умолчанию

31

Page 32: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

at

32

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);

}

32

1 [1,4,3]

0 [1,2,3]Place 0

o a = [1, 2, 3]

o at (1) {…}

o println(a)

Place 1

o a(1) = 4

o println(a)

Copy a

Page 33: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

at

33

/* Копирует поле f из a в b */

def copyRemoteFields(a, b) {

at (b.home) b.f =

at (a.home) a.f;

}

33

/* Выполняет метод удаленного объекта */

def invoke(obj, arg) {

at (obj.home) {

obj().fun(arg);

}

}

Page 34: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Спецификатор 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);

}

}

}

34

a=1 b=2

a=1 b=034

Page 35: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Запуск корневого потока

3535

1. Runtime-система отыскивает контейнер C (класс)

со статическим методом main

2. Формирует из аргументов командной строки

одномерный массив s строк и запускает корневой

поток следующим образом

finish async at (Place.FIRST_PLACE) {

C.main(s);

}

Page 36: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Atomic blocks

3636

Директива atomic создает в текущей области критическую

секцию Satomic S

Пока блок S не завершиться в него не войдут другие

потоки области

В пределах S нельзя: порождать потоки, использовать at

def add(x: T) {

atomic {

this.list.add(x);

this.size++;

}

}

Page 37: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Atomic blocks

3737

Директива atomic создает в текущей области критическую

секцию Satomic S

Пока блок S не завершиться в него не войдут другие

потоки области

В пределах S нельзя: порождать потоки, использовать at

atomic def add(x: T) {

this.list.add(x);

this.size++;

}

Page 38: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Conditional atomic block

3838

Директива 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;

}

Page 39: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Conditional atomic block

39

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

Page 40: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Distributed arrays

4040

Распределенный массив (Distributed array) –

это массив, распределенный между несколькими

областями (places)

X10.array.DistArray[T]

Распределение (distribution, X10.array.Dist) задает

распределение точек региона (region) по областям (places)

Page 41: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Distributions

4141

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

Page 42: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

DistArray

4242

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

0

1 2 3

Place 1

0

4 5 6

Place 2

0

7 8 9

Place 3

0

10 11 12

localA

globalA

Page 43: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Проход по распределенному массиву

4343

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);

}

}

}

Page 44: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Проход по распределенному массиву

4444

public static def main(Array[String](1)) {

/* ... */

var sum: Int = 0;

for (p in lSum.dist.places()) {

sum += (at (p) localSum(p.id));

}

}

Page 45: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

ateach

4545

Директива ateach позволяет выполнить блок S в каждой

областиateach (p in D) S

Действия ateach эквивалентны следующему фрагменту

for (place in D.places()) {

async at (place) {

for (p in D | here) {

S(p);

}

}

}

Page 46: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

IBM X10 Backends

4646

Java backend (x10c)

Один процесс – все области (places) в одной виртуальной

машине JVM (Java 5)

C++ backend (x10c++)

Один процесс на SMP-узел (1 область на SMP-узел)

Page 47: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Пример ArraySum (serial version)

47

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

Page 48: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Пример ArraySum (serial version)

48

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

Page 49: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Пример ArraySum (parallel version 1)

49

public class ArraySum {

/* ... */

def sum(a: Array[Int](1), l: Int, h: Int): Int {

var s: Int = 0;

for (i in l..(h - 1))

s += a(i);

return s;

}

def sum(nthreads: Int) {

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

-3 2 2 0 4 3 4 6 7 8 9 2 4 1 5 4 5 6 5 4 5 6

Activity 0 Activity 1 Activity 2

chunk

Page 50: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Пример ArraySum (parallel version 1)

50

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);

}

}50

Single place version

Page 51: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Пример ArraySum (parallel version 2)

51

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;

}

}

}51

Thread

0

Thread

1

Thread

2

Thread

0

Thread

1

Thread

2…data:

Page 52: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Числа Фибоначчи (serial version)

52

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

Page 53: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

Числа Фибоначчи (parallel version)

53

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

Page 54: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

public class Pi {

public static def main(args:Array[String](1)) {

val N = 100000;

val init = (i: Point) => {

val r = new Random();

var m: Double = 0.0D;

for (c in 1..N) {

val x = r.nextDouble();

val y = r.nextDouble();

if (x * x + y * y <= 1.0)

m++;

}

m

};

Вычисление числа Pi

5454

y

x

1

1

𝜋 ≈4𝑚

𝑛

Page 55: Лекция 12 (часть 2): Языки программирования семейства PGAS: IBM X10

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);

}

}

Вычисление числа Pi

5555