Язык Charm ++ Идеология Charm++ Charm++ - объектно-ориентированный язык программирования (расширение Си++), ориентированный на вычисления, управляемые потоком данных (data-driven computations). Историческая справка • Начало работ – конец 80-х годов в лаборатории параллельного программирования университета Illionois Urbana-Campaighn • Первая открытая реализация – 1993 • В 1999-2000 годах добавлены возможности динамической балансировки и перемещаемые объекты Сущности Charm++ • • • • • «Последовательные» объекты «Распределяемые» объекты (chare) Сообщения Группы объектов Массивы объектов Составляющие Charm++ приложения • Файлы с описанием интерфейса ко всем объектам, кроме последовательных. • Файлы с реализацией интерфейсов на Си ++. file.ci charmc module.def.h module.decl.h c++ module.C c++ prg Компиляция в Charm++ CHARM=/home/posypkin/UTILS/charm-5.8/bin/charmc hello: hello.o $(CHARM) -o hello hello.o -language charm++ hello.o: hello.C $(CHARM) -c hello.C hello.C: Hello.decl.h Hello.def.h touch hello.C Hello.decl.h Hello.def.h: hello.ci $(CHARM) hello.ci Модель выполнения Charm ++ приложения процессор узел Создание объектов Charm ++ chare mainchare RTS Распределяемые объекты Charm ++ Помимо обычных методов присутствует один или более входных (entry) методов, используемых для удаленного вызова. «Главные» объекты (mainchare) Один или несколько типов объектов должны наследовать mainchare. Они создаются системой поддержки времени выполнения в начале выполнения программы на процессоре с номером 0. Описание в интерфейсном модуле Один или несколько типов объектов должны наследовать mainchare. В интерфейсном модуле описание выглядит так: mainchare HelloMain { entry HelloMain(); entry void printDone(); }; Реализация Конструктор главного объекта имеет параметр поумолчанию типа CkArgMsg*, через который передаются параметры командной строки: HelloMain(CkArgMsg* m) { mCount = atoi(m->argv[1]); delete m; } Взаимодействие объектов Взаимодействие с объектом происходит через удаленный вызов методов. При этом параметры запаковываются и пересылаются на процессор, содержащий удаленный объект. Вызов асинхронный и без ожидания результата. объект прокси Передача параметров методу • Через параметры. Используется маршалинг (упаковка/распаковка) параметров. • Через специальные объекты – сообщения (message). Маршалинг параметров Маршалинг параметров базовых типов поддерживается системой. Для маршалинга параметров типов определенных пользователем требуется перегрузка метода pup или операции “|”: void pup(PUP::er p) { p | mA; p | mB; } hello.ci mainmodule Hello { readonly CProxy_HelloMain mainproxy; mainchare HelloMain { entry HelloMain(); entry void printDone(); }; chare Slave { entry Slave(); entry void hello(int); } }; hello.C #include <stdlib.h> #include "Hello.decl.h“ CProxy_HelloMain mainproxy; class HelloMain : public Chare{ public: HelloMain(CkArgMsg* m) { mCount = atoi(m->argv[1]); ckout << "Running " << CkNumPes() << " processors on " << CkNumNodes() << " nodes " << endl; mainproxy = thishandle; for(int i = 0; i < mCount; i ++) { CProxy_Slave proxy = CProxy_Slave::ckNew(); proxy.hello(i); } delete m; } void printDone() { mCount --; if(mCount == 0) CkExit(); } private: int mCount; }; class Slave : public Chare { public: Slave() {} void hello(int i) { ckout << "Hello from " << i << " on " << CkMyPe() << " processor " <<endl; mainproxy.printDone(); } }; #include "Hello.def.h" Сообщения Сообщения являются более низкоуровневым, но и более быстрым способом передачи данных, чем параметры. Синхронные методы возвращают сообщения. Сообщения – объекты C++, объявленные в интерфейсном модуле с ключевым словом message: message MyMessageType; entry myMethod(MyMessageType* m); Создание и передача сообщения в программе class MyMessageType : public CMessage_MyMessageType { int a; float b; } Сообщения создается с помощью оператора new: MyMessageType *m = new MyMessageType(); proxy.myMethod(m); При каждом вызове сообщение должно создаваться заново, т.к. при вызове оно удаляется! Сообщения переменной длины Объявление в интерфейсном модуле: message Vec{ int a[]; } Объявление в C++ файле: class Vec { int* a; }; Создание: Vec *m = new (10) Vec(…); Поиск максимума в массиве mainmodule Msort { message Vec { int vect[]; }; mainchare MsortMain { entry MsortMain(); }; chare Msort{ entry Msort(); entry void sort(Vec * ); entry void sortDone(int val); } }; #include <stdlib.h> #include "Msort.decl.h" void copyarray(int* dest, int* source, int len) { for(int i = 0; i < len; i ++) { dest[i] = source[i]; } ckout << endl; } class Vec : public CMessage_Vec { public: CkChareID mProxy; int mInit; int mLen; int* vect; Vec(int ); Vec(int, CkChareID); }; Vec::Vec(int len) { mInit = 1; mLen = len; } Vec::Vec(int len, CkChareID proxy) { mInit = 0; mLen = len; mProxy = proxy; } class MsortMain : public Chare{ public: MsortMain(CkArgMsg* msg) { int n; int* array; delete msg; ckout << "Enter N: " << endl; ckin >> n; array = new int[n]; for(int i = 0; i < n; i ++) { ckout << "Enter " << i << "-th element: " << endl; ckin >> array[i]; } Vec* m = new (n, 0) Vec(n); copyarray(m->vect, array, n); CProxy_Msort proxy = CProxy_Msort::ckNew(); proxy.sort(m); } }; class Msort : public Chare { public: Msort() { mCount = 0; } void sort(Vec* v) { ckout << "vector of " << v->mLen << " elements received " << endl; mInit = v->mInit; if(!mInit) mProxy = v->mProxy; if(v->mLen == 1) { CProxy_Msort proxy(mProxy); proxy.sortDone(v->vect[0]); } else { int l1; int l2; l1 = v->mLen / 2; l2 = v->mLen - l1; Vec* m1 = new (l1, 0) Vec(l1, thishandle); copyarray(m1->vect, v->vect, l1); CProxy_Msort proxy = CProxy_Msort::ckNew(); proxy.sort(m1); Vec* m2 = new (l2, 0) Vec(l2, thishandle); copyarray(m2->vect, v->vect + l1, l2); proxy = CProxy_Msort::ckNew(); proxy.sort(m2); } } void sortDone(int val) { if(mCount == 0) mVal = val; else mVal = MYMAX(val, mVal); mCount ++; if(mCount == 2) if(mInit) { ckout << "Maximum = " << mVal << endl; CkExit(); } else { CProxy_Msort proxy(mProxy); proxy.sortDone(mVal); } } private: bool mInit; int mCount; int mVal; CkChareID mProxy; };