Опубликован: 19.10.2012 | Доступ: свободный | Студентов: 299 / 65 | Длительность: 05:51:00
Лекция 1:

Intel® CilkTM Plus – общая характеристика и ключевые слова

Лекция 1: 123 || Лекция 2 >

Структура Intel® CilkTM Plus

Ключевые слова (всего 3!):

  • cilk_spawn – порождение задачи;
  • cilk_for – распараллеливание цикла;
  • cilk_sync – синхронизация задач.

Низкие накладные расходы.

Гиперобъекты (редукторы)

Редукторы – "параллельные" глобальные переменные, позволяющие избежать гонок за данными и блокировок.

Эффективное управление редукторами обеспечивается системой исполнения Cilk-программ

Функции прикладного программного интерфейса (API)

  • __cilkrts_set_param("nworkers", "4")
  • __cilkrts_get_nworkers()
  • __cilkrts_get_total_workers()
  • __cilkrts_get_worker_number()

Расширенная индексная нотация

Отличает CilkTM Plus от CilkTM.

Удобная запись операций с массивами.

Более высокая эффективность операций с массивами (компилятор порождает исполняемый код, использующий векторные инструкции).

Сходство с сечениями массивов языка Fortran, при различии в синтаксисе и реализации.

if (a[:] > b[:]) {
c[:] = d[:] * e[:];
} else {
c[:] = d[:] * 2;
}

Элементные (векторные) функции

Элементные функции обеспечивают векторизацию вычисления математических функций.

Аргументы элементных функций – векторы значений.

Возвращается вектор результата, конформный векторному аргументу.

Пример:

__declspec (vector) double heat_distribution(
double XL, double YL, double t, double sigma, double time)
{
double time_sqrt = sqrt(time);
double d1 = (log(S/K)+r*time)/(sigma*time_sqrt)+0.5*sigma*time_sqrt;
double d2 = d1-(sigma*time_sqrt);
return S*N(d1) - K*exp(-t*r)*N(d2);

Директива SIMD

Векторизация тех фрагментов кода, которые необходимо векторизовать – подсказка векторизующему компилятору.

Используются векторные регистры (AVX) процессора.

Используется векторное расширение команд процессора SSE (Streaming SIMD Extension).

Компилятор генерирует векторизованный код.

Программист гарантирует корректность векторной семантики.

Циклы остаются без изменений.

Пример

void saxpy( float a, float x[], float y[], size_t n ) {
#pragma simd
    for( size_t i=0; i<n; ++i )
        y[i] += a*x[i];
}

Файл заголовков

#include <cilk/cilk.h>

Переменные окружения

Основная - CILK_NWORKERS (количество потоков).

Ключевые слова

Ключевое слово cilk_spawn

cilk_spawn является псевдонимом для _Сilk_spawn.

Обозначает точку порождения. В этой точке создается новая задача, выполнение которой может быть продолжено данным потоком или захвачено другим (параллельным) потоком.

cilk_spawn является указанием системе исполнения на то, что данная функция может (но не обязана) выполняться параллельно с функцией, из которой она вызвана.

Синтаксис (допустим любой из трех):

cilk_spawn имя_функции_потомка()
type var = cilk_spawn имя_функции_потомка()
var = cilk_spawn имя_функции_потомка()

Допускается:

var = cilk_spawn (object.*pointer)(args);

cilk_spawn [&]{ g(f()); }();

cilk_spawn g(f());

Два последних варианта – в первом обе функции выполняются в потомке, во втором случае сначала выполняется f(), затем – потомок.

Порождение с использованием лямбда-выражения:

cilk_spawn [&]{
    for( int i=0; i<n; ++i ) 
        a[i] = 0;
} ();
...
cilk_sync; 

Не допускается:

g(cilk_spawn f());

Пример:

void floyd_warshall() {
  for (int k = 0; k < n; ++k) 
    for (int i = 0; i < n; ++i)
      cilk_spawn work(k,i);
}

Ключевое слово cilk_sync

cilk_sync является псевдонимом для _Cilk_sync.

Обозначает точку синхронизации. В этой точке выполнение задач синхронизируется (барьерная синхронизация).

Выполнение функции с точкой синхронизации невозможно параллельно с потоком. Оно приостанавливается до тех пор, пока не будет завершен потомок. Затем выполнение функции возобновляется.

Неявно точка синхронизации присутствует в конце каждой функции.

Пример:

public:
    CilkSpawnSum(int nThreads) : _nThreads(nThreads), result(0) {}
    virtual double FindSum(SimpleArray &data) {
        for(int i=0; i<_nThreads; i++) {
            cilk_spawn _SumComputer(data, 
                i * data.GetSize() / _nThreads, 
                (i+1) * data.GetSize() / _nThreads);
        }
        cilk_sync;
        return result.get_value();
    }
Лекция 1: 123 || Лекция 2 >