import Qt.labs.presentation 1.0 import QtQuick 2.3 import QtQuick.Controls 1.3 import QtMultimedia 5.3 import QtWebKit 3.0 ApplicationWindow { id: window title: "DTK Distributed" visible: true /* visibility: "FullScreen" */ width: 1280 height: 720 OpacityTransitionPresentation /* Presentation */ { id: presentation width: parent.width height: parent.height showNotes: true Keys.forwardTo: [video, elapsed] // FIXME: how can i get QWindow::FullScreen in QML ? (using hardcoded 5 is ugly) Keys.onPressed: { if (event.key == Qt.Key_F11) { (window.visibility == 5) ? window.visibility = "Windowed" : window.visibility = "FullScreen"} } SlideCounter {} Elapsed { id: elapsed duration: 90 * 60 // 90 mn } Image { id: background source: "images/Arc-Brave.png" opacity: 0.5 width: parent.width height: parent.height anchors.centerIn: parent } Image { id: dtklogo source: "images/dtk-logo.png" opacity: 0.7 anchors.top: parent.top anchors.right: parent.right anchors.margins: 10 } Image { id: inriaLogo mipmap: true source: "images/inria-transparent.png" width: 404 / 1.7 height: 145 / 1.7 anchors.bottom: parent.bottom anchors.left: parent.left anchors.margins: 0 } Slide { title: "DREAMtech - DTK Distributed" centeredText: "Nicolas Niclausse / Thibaud Kloczko / Julien Wintz" } Slide { title: "Plan" content: [ "Contexte & Motivations", "Management des ressources", "Application distribuées", "Conteneurs distribués" ] } Slide { title: "Contexte" textFormat: Text.RichText content: [ "ADT DTK (depuis 2012) ", " méta plateforme, pour développer des plateformes modulaires (plugins)", " multi Plateforme, C++, Qt", " num3sis, axel, medInria, enas, carbonQuant, pib, inalgae, bolis, winpos", "layers DTK:", " dtkCore", " dtkComposer", " dtkPlot", " dtkLinearAlgebraSparse", " dtkDistributed", ] } Slide { title: "dtkDistributed: Motivations" content: [ "Faciliter l\'utilisation des ressources de calcul dans le code", " indépendances vis à vis des gestionnaires de ressources (oar, torque, accès direct)", " déploiement automatique", " ssh (tunnelling si besoin), MPI_comm_spawn ", "Simplifier l\'écriture d\'applications distribuées (API de haut niveau)", "Faciliter le prototypage", " pas de dépendances en dur sur des bibliothèques tierces (MPI)", " implémentation par défaut multi plateforme (communicateur qthread)", "Faciliter les intéractions calcul / visualisation ", ] } Slide { title: "dtkDistributed: Historique" content: [ "fin 2011: premier prototype du resource manager", "2012: communicateur v0, intégration dans le composer dtk", "fin 2012: visu intéractive de simulation distante dans le composer num3sis", "2013: refonte du communicator sous forme de plugins", "mi 2014: vecteur et graphe distribués", "2015: intégration dans le layer algèbre sparse", ] } Slide { title: "Management de ressources via dtkDistributed" textFormat: Text.RichText content: [ "3 composants:", " 1 contrôleur: dtkDistributedController (sur la machine cliente (laptop par ex.))", " 1 serveur dtkDistributedServer (sur la frontale du cluster), qui instancie un ressource manager", " OAR", " Torque", " SSH", " N slaves dtkDistributedSlave (sur un(des) noeud(s) d\'un cluster)", ] notes: "Le contrôleur et le serveur sont optionnels, on peut lancer aussi une application distribuées manuellement sur le cluster ou via kali" } Slide { title: "Management de ressources via dtkDistributed" Rectangle { width: parent.width * 0.6 height: parent.height anchors.centerIn: parent //opacity: 0.0 color : "lightgrey" radius: 10 Image { width: parent.width height: parent.height id: dtkdistributed source: "images/dtkDistributed_controller.png" /* mipmap: true */ anchors.margins: 10 } } } Slide { title: "Application distribuées" content: [ "Communicator", "Messages", "Policy, Settings", "Distributed application", ] } Slide { title: "Communicator" content: [ "dtkDistributedCommunicator", " interface pour le calcul parallèle", " paradigme de programmation inspiré de MPI", " inclus des primitives de:", " déploiement", " communication", " synchronisation" ] } Slide { title: "Communicator" content: [ "implémenté sour forme de plugins", " qthread (par défaut)", " MPI", " MPI3", "primitives de communication", " send/receive/ireceive/broadcast/reduce", " barrier/wait", "buffers distribués", " get/put/accumulate", ] } Slide { title: "Communicator: sérialisation" content: [ "primitives de communications compatibles avec:", " tableau de type simple", " QVariant", "sérialisation via le QVariant: ", ] CodeSection { height: parent.height * 0.45 anchors.bottom: parent.bottom text: 'Q_DECLARE_METATYPE(monType) qRegisterMetaTypeStreamOperators("monType"); qRegisterMetaTypeStreamOperators("monType*"); // handle the pointer version of qdatastream operators << and >> #include ; QDataStream& operator<<(QDataStream& s, const monType& data); QDataStream& operator>>(QDataStream& s, monType& data);' } } CodeSlide { title: "Communicator: sérialisation" code:'// rank 0 is sending each slave it\'s mesh if (d->communicator->rank() == 0) { dtkContainerVector *meshes = d->partitioner->meshes(); for(qlonglong i = 1; i < meshes->count(); ++i) { QVariant v = QVariant::fromValue(meshes->at(i)); d->communicator->send(v, i, tagSend); delete meshes->at(i); } } else { // each slave received it\'s mesh QVariant v; d->communicator->receive(v, 0, tagSend); d->mesh = v.value(); }' } CodeSlide { title: "Communicator: sérialisation, vraie version" code:'// rank 0 is sending each slave it\'s mesh if (d->communicator->rank() == 0) { dtkContainerVector *meshes = d->partitioner->meshes(); for(qlonglong i = 1; i < meshes->count(); ++i) { d->communicator->send(meshes->at(i), i, tagSend); delete meshes->at(i); } } else { // each slave received it\'s mesh d->communicator->receive(d->mesh, 0, tagSend); } ' } Slide { title: "Communicator: spawn" textFormat: Text.RichText content: [ "déploiement du communicateur: spawn()", " qthread : instanciation d\'une pool de thread (QThreadPool)", " mpi : MPI_Comm_Spawn", " Pas besoin de mpirun (avec openmpi)", "exécution du code parallèle: exec(QRunnable)", " QRunnable: méthode virtuelle run() à implémenter", ] } Slide { title: "Messages" textFormat: Text.RichText content: [ "échange de messages entre contrôleur, serveur et slave", "protocole basé sur JSON et du pseudo HTTP", "interface C++: dtkDistributedMessage", " Plusieurs méthodes:", " STATUS: demande d\'état du cluster", " OKSTATUS: état du cluster", " NEWJOB: création d\'un job", " DELJOB: suppression d\'un job", " DATA: échange de données (QVariant)", " ...", ] } Slide { title: "Policy & Settings" content: [ "policy:", " permet de choisir l\'implémentation (qthread, mpi, mpi3)", " permet de spécifier les machines sur lequel l\'application tourne", " s\'interface avec Torque, OAR", " variable d\'environnement DTK_NUM_PROCS", "Settings:", " fichier ini", " défini vers le plugins path", " autres options ...", ] } Slide { title: "dtkDistributedApplication" textFormat: Text.RichText content: [ "simplifie l\'invocation d\'une application", " configure automatiquement la policy", " initialise le plugin manager du communicator", "options en ligne de commande", " nombre de procs, policy, etc.", " ajout d\'option spécifiques.", "déploiement de l\'application (spawn)", "exécution des taches de calcul (exec)" ] CodeSection { width: parent.width / 2.4 anchors.right: parent.right text:'dtkDistributed::create(argc,argv); QCommandLineParser *parser=app->parser(); app.initialize(); app.spawn(); app.exec(work); app.unspawn(); ' } } Slide { title: "Distributed application" CodeSection { text: '# myappli --help Usage: myappli [options] Lorem ipsum dolor sit amet, consectetur adipiscing elit Options: --myoption myappli option(s) --policy dtkDistributed policy (default is qthread) --np number of processes --hosts hosts (multiple hosts can be specified) -h, --help Displays this help. -v, --version Displays version information. --settings settings file --verbose verbose plugin initialization --nw, --no-window non GUI application (no window) --loglevel log level used by dtkLog (default is info) --logfile log file used by dtkLog; default is: /home/nniclaus/.local/share/inria/dtk DistributedSlave/dtkDistributedSlave.log' } } CodeSlide { title: "Example de slave" code: 'int main(int argc, char **argv) { dtkDistributedAbstractApplication *app=dtkDistributed::create(argc,argv); QCommandLineParser *parser = app->parser(); parser->setApplicationDescription("DTK distributed slave application."); QCommandLineOption serverOption("server", "Server URL", "URL"); parser->addOption(serverOption); app->initialize(); if (!parser->isSet(serverOption)) { qCritical() << "Error: no server set ! Use --server " ; return 1; } slaveWork work; work.server = parser->value(serverOption); app->spawn(); app->exec(&work); app->unspawn(); return 0; }' } CodeSlide { title: "Example de slave (suite) " code: 'class slaveWork : public QRunnable { public: QString server; public: void run(void) { dtkDistributedCommunicator *c=dtkDistributed::communicator::instance(); dtkDistributedSlave slave; slave.connectFromJob(server); QThread::sleep(5); if (c->rank() == 0) { QString s = QString::number(c->size()); QString hello = "I\'m the master slave, we are "+s+" slaves"; QVariant v(hello); dtkDistributedMessage m(dtkDistributedMessage::DATA,slave.jobId(), dtkDistributedMessage::CONTROLLER_RANK, v); m.send(slave.socket()); } QThread::sleep(5); slave.disconnectFromJob(server); }};' } Slide { title: "Examples d\'application avec contrôleur/slave" content: [ "Dashboard QML", " Objet 'dtkDistributedController' instancié en QML", " Serveur sur la frontale choisie", " Lance un job Slave via le serveur", " Affiche les données envoyées par le slave", ] } Slide { id: dashboardSlide title: "DTK Distributed Dashboard" Background { id: backgroundb } Dashboard { id: dashboard path: workingDirectory } } Slide { title: "Contrôleur intégré dans numComposer" Rectangle { id: videorect width: height * 1.59 height: parent.height anchors.centerIn: parent border.color : "black" color: "transparent" Video { id: video width: parent.width height: parent.height-8 anchors.top: parent.top anchors.left: parent.left source: "http://num3sis.inria.fr/blog/wp-content/uploads/sampling-aero-nef.mp4" /* source: "file:///tmp/sampling-aero-nef.mp4" */ autoPlay: false Keys.onSpacePressed: { video.playbackState == MediaPlayer.PlayingState ? video.pause() : video.play() event.accepted = true; } Keys.onDownPressed: video.seek(video.position - 5000) Keys.onUpPressed: video.seek(video.position + 5000) } ProgressBar { id: slider width: parent.width height: 8 anchors.left: parent.left anchors.bottom: parent.bottom value: video.position/ video.duration } } } Slide { title: "Conteneurs distribués" content: [ "étude d'un cas a priori simple", "état de l'art", "organisation des classes", "dtkDistributedArray", "dtkDistributedGraphTopology", "retour sur le cas initial." ] } Slide { title: "Calcul de maximum sur un graphe" Rectangle { width: parent.width * 0.8 height: parent.height anchors.centerIn: parent //opacity: 0.0 color : "lightgrey" radius: 10 Image { width: parent.width height: parent.height id: graph_sequential source: "images/graph.png" /* mipmap: true */ anchors.margins: 10 } } } Slide { title: "Calcul de maximum sur un graphe" CodeSection { anchors.top: parent.top height : parent.height * 0.25 text: 'Foreach vertex in graph { Foreach neighbour of vertex { max_values[vertex_id] = Max(max_values[vertex_id], values[neighbour_id]); } }' } content: [ "","", "Structure de graphe simple", "Algorithme simple" ] } Slide { title: "Calcul de maximum sur un graphe distribué" Rectangle { width: parent.width * 0.8 height: parent.height anchors.centerIn: parent //opacity: 0.0 color : "lightgrey" radius: 10 Image { width: parent.width height: parent.height id: graph_part source: "images/graph_part.png" /* mipmap: true */ anchors.margins: 10 } } } Slide { title: "Calcul de maximum sur un graphe distribué" CodeSection { anchors.top: parent.top height : parent.height * 0.75 text: '// Local Computation Foreach vertex in subGraph { Foreach neighbour of vertex { max_values[vertex_id] = Max(max_values[vertex_id], values[neighbour_id]); } // Boundary computation Foreach boundary in subGraph { Foreach vertex of Boundary { local_max_values[local_id] = max_values[vertex_id]; } Send(local_max_values); Receive(extern_max_values); Foreach vertex of Boundary { max_values[vertex_id] = Max(max_values[vertex_id], extern_max_values[ext_id]); } }' } content: [ "","","","","", "Complexité accrue en terme de structure et d'algorithme" ] } Slide { title: "Calcul du maximum sur les voisins des voisins" content: [ ":-/", "Refaire les structures", "Repenser l'algorithmie", "...", "Tout compte fait, on va s\'en passer..." ] } Slide { title: "Bibliothèques existantes" content: [ "Parallel Standard Library (PSTL) -> plus maintenu", "Intel Threadings Building Blocks (TBB) -> seulement multithread", "Parallel Object-Oriented Methods and Applications (POOMA) -> pas de structure de graphe", "Standard Template Adaptive Parallel Library (STAPL) -> ni sources ni binaires", "Fortran Coarray (OpenCorrays) -> code C qui génère du Fortran!" ] } Slide { title: "dtkDistributed Containers" // Rectangle { // width: parent.width // height: parent.height // anchors.centerIn: parent // opacity: 0.8 // color : "lightgrey" // radius: 10 Image { anchors.centerIn: parent width: parent.width * 0.9 height: parent.height id: dtkDistributedContainers source: "images/dtkDistributed.png" /* mipmap: true */ anchors.margins: 10 } //} } CodeSlide { title: "dtkDistributedArray : API" code: 'template < typename T > class dtkDistributedArray : public dtkDistributedContainer { public: dtkDistributedArray(const qlonglong& size, dtkDistributedMapper *mapper); ~dtkDistributedArray(void); public: bool empty(void) const; qlonglong size(void) const; void fill(const T& value); void setAt(const qlonglong& index, const T& value); T at(const qlonglong& index) const; T operator[](const qlonglong& index) const; public: iterator begin(void); iterator end(void); const T *data(void) const; T *data(void);' } CodeSlide { title: "dtkDistributedArray : Sequential initialization" code: 'qlonglong N = 16257; dtkDistributedCommunicator *comm = dtkDistributed::communicator::instance(); qlonglong *input = new qlonglong[N]; for (int i = 0; i < N; ++i) { input[i] = i; } dtkDistributedArray array(N); if (comm->wid() == 0) { for (int j = 0; j < N; ++j) { array.setAt(j, input[j]); } for (int j = 0; j < N; ++j) { if(array.at(j) != input[j]) { return false; } } } comm->barrier();' } CodeSlide { title: "dtkDistributedArray : Parallel initialization" code: 'qlonglong N = 16257; dtkDistributedCommunicator *comm = dtkDistributed::communicator::instance(); qlonglong *input = new qlonglong[N]; for (int i = 0; i < N; ++i) { input[i] = i; } dtkDistributedArray array(N); dtkDistributedArray::iterator ite = array.begin(); dtkDistributedArray::iterator end = array.end(); for(int i = 0; ite != end; ++ite, ++i) { *ite = input[array.mapper()->localToGlobal(i, comm->wid())]); } comm->barrier();' } Slide { title: "dtkDistributedArray : globale vs locale" CodeSection { id : globaleapi width: parent.width * 0.475 height: parent.height * 0.5 anchors { left: parent.left verticalCenter: parent.verticalCenter } gradient: Gradient { GradientStop { position: 0; color: Qt.rgba(0.9, 0.9, 0.9, 0.5); } GradientStop { position: 1; color: Qt.rgba(0.6, 0.6, 0.6, 0.5); } } border.color: parent.textColor; antialiasing: true text: ' bool empty(void) const; qlonglong size(void) const; void fill(const T& value); void setAt(const qlonglong& id, const T& val); T at(const qlonglong& id) const; T operator[](const qlonglong& id) const;' } CodeSection { width: parent.width * 0.475 height: parent.height * 0.5 anchors { right: parent.right verticalCenter: parent.verticalCenter } gradient: Gradient { GradientStop { position: 0; color: Qt.rgba(0.9, 0.9, 0.9, 0.5); } GradientStop { position: 1; color: Qt.rgba(0.6, 0.6, 0.6, 0.5); } } border.color: parent.textColor; antialiasing: true text: ' iterator begin(void); iterator end(void); const T *data(void) const; T *data(void);' } } Slide { title: "dtkDistributedArray : architecture" CodeSection { id: array_top width: parent.width height: parent.height * 0.35 anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter gradient: Gradient { GradientStop { position: 0; color: Qt.rgba(0.9, 0.9, 0.9, 0.5); } GradientStop { position: 1; color: Qt.rgba(0.6, 0.6, 0.6, 0.5); } } border.color: parent.textColor; antialiasing: true text: '// all processes duplicate the mapper dtkDistributedCommunicator *comm; dtkDistributedMapper *mapper;' } CodeSection { id: array_left width: parent.width * 0.3 height: parent.height * 0.5 anchors.top: array_top.bottom anchors.left: parent.left anchors.topMargin: parent.height * 0.1 gradient: Gradient { GradientStop { position: 0; color: Qt.rgba(0.9, 0.9, 0.9, 0.5); } GradientStop { position: 1; color: Qt.rgba(0.6, 0.6, 0.6, 0.5); } } border.color: parent.textColor; antialiasing: true text: '// unit process #0 dtkArrayData *data; dtkDSBufferManager *bm; dtkDSArrayCache *cache;' } CodeSection { id: array_center width: parent.width * 0.3 height: parent.height * 0.5 anchors.top: array_top.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: parent.height * 0.1 gradient: Gradient { GradientStop { position: 0; color: Qt.rgba(0.9, 0.9, 0.9, 0.5); } GradientStop { position: 1; color: Qt.rgba(0.6, 0.6, 0.6, 0.5); } } border.color: parent.textColor; antialiasing: true text: '// unit process #1 dtkArrayData *data; dtkDSBufferManager *bm; dtkDSArrayCache *cache;' } CodeSection { id: array_right width: parent.width * 0.3 height: parent.height * 0.5 anchors.top: array_top.bottom anchors.right: parent.right anchors.topMargin: parent.height * 0.1 gradient: Gradient { GradientStop { position: 0; color: Qt.rgba(0.9, 0.9, 0.9, 0.5); } GradientStop { position: 1; color: Qt.rgba(0.6, 0.6, 0.6, 0.5); } } border.color: parent.textColor; antialiasing: true text: '// unit process #2 dtkArrayData *data; dtkDSBufferManager *bm; dtkDSArrayCache *cache;' } } CodeSlide { title: "dtkDistributedArray : allocation mémoire" code: 'template inline void dtkDistributedArray::allocate(void) { // Communicator creates the buffer manager matching its // implementation (Qthread, MPI, MPI3) bm = comm->createBufferManager(); // Buffer manager allocates the memory according to size given by // the mapper void *local_buffer = bm->allocate(mapper->localSize()); // This buffer initializes the local container data = dtkArrayData::fromRawData(buffer, mapper->localSize()); }' } CodeSlide { title: "dtkDistributedArray : accès aux valeurs" code: 'template inline T dtkDistributedArray::at(qlonglong id) const { // Identifies the unit process that has the value qint32 owner = mapper->owner(id); // Identifies the local position of the value on the owner qlonglong pos = id - mapper->firstId(owner); // If the owner is the local process the access is direct if (this->wid() == owner) { return data[pos]; // Else the remote value is asked by the buffer manager } else { T val; bm->get(owner, pos, &val); return val; } }' } CodeSlide { title: "Buffer Manager : accès aux valeurs en Qthread" height: parent.height * 0.55 content: ["","","","","","Accès direct au buffer cible"] code: 'void qthDistributedBufferManager::get(qint32 owner, qlonglong pos, void *array, qlonglong nelement = 1) { // Owner id enables to get the right shared buffer char *buffer = d->buffers[owner]; // Copy into array is done from pos to pos + nelement memcpy(array, buffer + pos * d->object_size, d->object_size * nelement); }' } CodeSlide { title: "Buffer Manager : accès aux valeurs en MPI" height: parent.height * 0.4 code: 'void mpiDistributedBufferManager::get(qint32 owner, qlonglong pos, void *array, qlonglong nelement = 1) { // Size of the memory to get qlonglong array_size = d->object_size * nelements; // Copy into array from the memory of the owner at position pos MPI_Get(array, array_size, MPI_BYTE, owner, pos, array_size, MPI_BYTE, d->win); }' textFormat: Text.RichText content: [ "","","","", "Utilisation de MPI One-Sided Communication", " permet à un processus d'accéder à un espace d'adresse d'un autre processus sans la participation explicite de celui-ci.", " permet de simplifier le programme et de coder comme en mémoire partagée" ] } Slide { title: "MPI One-Sided Communication" textFormat: Text.RichText content: [ "MPI_Win_Create", " crée une fenêtre pour l'accès par d'autres processus à une zone mémoire", "MPI_Win_Free", " détruit la fenêtre", "MPI_Get / MPI_Put", " lecture/écriture asynchrone sur une zone mémoire exposée par une fenêtre", "Bibliothèques utilisant MPI One-Sided Communication :", " OpenCoarrays pour les Coarrays en Fortran 2008", " OpenShmem implémentation de PGAS (Partitioned Global Address Space)" ] } CodeSlide { title: "dtkDistributedGraphTopology : API" code: 'class dtkDistributedGraphTopology : public dtkDistributedContainer { public: dtkDistributedArray(qlonglong vertex_count, dtkDistributedMapper *mapper); ~dtkDistributedArray(void); void addEdge(qlonglong from, qlonglong to, bool oriented = false); void build(void); qlonglong vertexCount(void) const; qlonglong edgeCount(void) const; qlonglong neighbourCount(qlonglong vertex_id) const; Neighbours operator[](qlonglong vertex_id) const; iterator begin(void) const; iterator end(void) const; };' } CodeSlide { title: "dtkDistributedGraphTopology : Construction" height: parent.height * 0.4 textFormat: Text.RichText content: ["","","","","Structure type ParCSR mais avec des dtkDistributedArray", " Vertex_to_FirstEdge : index de la première arête de chaque sommet", " Edge_to_Vertex : index du sommet cible de chaque arête"] code: 'dtkDistributedGraphTopology graph(18); // Add edges into provisionnal local data structure of the graph graph.addEdge(0, 1); graph.addEdge(1, 2); ... graph.addEdge(16, 17); // Build the true structures of the graph graph.build();' } CodeSlide { title: "dtkDistributedGraphTopology : API globale" height: parent.height * 0.56 textFormat: Text.RichText content: ["","","","","","dtkDistributedNavigator interroge le graphe via l'API globale.",] code: 'typedef dtkDistributedNavigator > Neighbours; // Gets a navigator for neighbours of a vertex Neighbours n = graph[i]; qlonglong n_count = n.size(); // Can iterate over all the neighbours of the vertex Neighbours::iterator nit = n.begin(); Neighbours::iterator nend = n.end(); for(; nit != nend; ++nit) { // Access to id of each neighbour qDebug() << *nit; }' } CodeSlide { title: "dtkDistributedGraphTopology : API locale" height: parent.height * 0.4 textFormat: Text.RichText content: ["","","","","En combinant iterator local et navigator global, on peut:", " accéder aux sommets voisins non-locaux", " accéder aux voisins des voisins non-locaux", " accéder aux voisins des voisins non-locaux des voisins non-locaux ;-)"] code: 'typedef dtkDistributedIterator iterator; // Iterates over all local vertices iterator vit = graph.begin(); iterator vend = graph.end(); for(; vit != vend; ++vit) { // Access to all the neighbours of the local vertex Neighbours n = *vit; }' } CodeSlide { title: "Calcul du maximum sur les voisins des voisins" code: 'dtkDistributedGraphTopology::iterator it = graph.begin(); dtkDistributedGraphTopology::iterator end = graph.end(); for(;it != end; ++it) { dtkDistributedGraphTopology::Neighbours n = *it; dtkDistributedGraphTopology::Neighbours::iterator nit = n.begin(); dtkDistributedGraphTopology::Neighbours::iterator nend = n.end(); for(;nit != nend; ++nit) { dtkDistributedGraphTopology::Neighbours nn = graph[*nit]; dtkDistributedGraphTopology::Neighbours::iterator nnit = nn.begin(); dtkDistributedGraphTopology::Neighbours::iterator nnend = nn.end(); for(;nnit != nnend; ++nnit) { max_values[it.id()] = qMax(max_values[it.id()], values[*nnit]); } } }' } Slide { title: "En résumé, ..." textFormat: Text.RichText content: [ "Avec :", " une structure fondamentale :", " dtkDistributedArray", " une structure aggrégatrice :", " dtkDistributedGraphTopology", " et des structures périphériques d'accès :", " dtkDistributedIterator", " dtkDistributedNavigator", "le code utilisateur parallèle s'écrit comme en séquentiel", "YES, WE CAN !"] } Slide { title: "Algèbre Linéaire Creuse" content: [ "dtkDistributedSparseMatrix", "dtkLinearSolverSparse" ] } Slide { title: "dtkSparseMatrix" textFormat: Text.RichText content: [ "dtkSparseMatrix: Abstraction de Sparse Matrix", " itérateur de lignes:
dtkSparseMatrixLine dtkSparseMatrix::begin()/end()", " itérateur sur les éléments de lignes:
dtkSparseMatrixLineElement dtkSparseMatrixLine::begin()/end()", "dtkSparseMatrixData: implémentation séquentielle", "dtkDistributedSparseMatrixData: implémentation parallèle:", " dtkDistributedGraphTopology", " dtkDistributedArray (valeurs)", ] } CodeSlide { title: "dtkSparseMatrix" code: 'dtkSparseMatrixLine line_it = mat.begin(); dtkSparseMatrixLine line_end = mat.end(); for (; line_it != line_end; ++line_it) { dtkSparseMatrixLineElement elt_it = line_it.begin(); dtkSparseMatrixLineElement elt_end = line_it.end(); qlonglong i = line_it.id(); for(;elt_it != elt_end; ++elt_it) { qlonglong j = elt_it.id(); // accès à value via l\'iterateur: value = (*elt_it); // modification via i,j (numérotation globale) mat(i,j) += coef; // en MPI, \'+=\' implémenté via MPI_Accumulate() } } ' } Slide { title: "dtkSparseSolver" content: [ "API générique (séquentielle/parallèle)", "implémentations sous forme de plugins", " dtkSparseSolverJacobi (générique)", " hypreDistributedSparseSolver", " utilisation de la dtkDistributedSparseMatrixData", " accès direct aux buffers locaux ", " à venir: mumps, MaPHyS, ...", ] } CodeSlide { title: "dtkSparseSolver API" code:'template < typename T > class dtkSparseSolver : public QRunnable { public: dtkSparseSolver(void) {;} virtual ~dtkSparseSolver(void) {;} public: virtual void setMatrix(dtkSparseMatrix *matrix) = 0; virtual void setRHSVector(dtkVector *rhs_vector) = 0; virtual void setSolutionVector(dtkVector *sol_vector) = 0; virtual void setOptionalParameters(const QHash& parameters); virtual void setOptionalParameters(const QHash& parameters); public: virtual void run(void) = 0; public: virtual dtkVector *solutionVector(void) const = 0;' } CodeSlide { title: "dtkSparseSolverJacobi: implémentation générique" code: 'while(!stop_criterion) { line_it = mat.begin(); line_end = mat.end(); tmp=sol; d->variation=0; for (; line_it != line_end; ++line_it) { dtkSparseMatrixLineElement elt_it = line_it.begin(); dtkSparseMatrixLineElement elt_end = line_it.end(); neighbour = 0; diag = 0; qlonglong i = line_it.id(); for(;elt_it != elt_end; ++elt_it) { qlonglong j = elt_it.id(); if (j != i) { neighbour += (*elt_it) * tmp[j];} else { diag = (*elt_it); }} sol[i] = (rhs.at(i) - neighbour) / diag ;} tmp -= sol; d->variation = tmp.asum(); if(iteration_count == 0) { variation_ini = d->variation;} if(iteration_count == d->number_of_iterations || d->variation/variation_ini < d->residual_reduction_order) stop_criterion = true; ++iteration_count; sol.clearCache(); tmp.clearCache();}' } Slide { title: "dtkSparseMatrixSolverApp" CodeSection { text: '>./bin/dtkSparseMatrixSolverApp --help Usage: ./bin/dtkSparseMatrixSolverApp [options] DTK sparse matrix solver. Options: --matrix matrix (matrixmarket format) --rhs rhs vector (matrixmarket format) --sol solution vector to be written --refsol reference solution --impl implementation --solver solver implementation. --iterations number of iterations --rro residual reduction order --policy dtkDistributed policy --np number of processes --hosts hosts (multiple hosts can be specified) -h, --help Displays this help. -v, --version Displays version information. --settings settings file --verbose verbose plugin initialization --nw, --no-window non GUI application (no window) --loglevel log level used by dtkLog --logfile log file used by dtkLog;' } } Slide { title: "Max des voisins des voisins" fontFamily: 'Courier New' content: [ "graphe, noeuds: 10M arcs: 75M ", "cluster nef, nœuds Xeon 20 cœurs, infiniband 40G", "openmpi-1.8.5.rc2", " mpi3 1 thread: 30.0 sec", " mpi3 2 threads: 15.4 sec", " mpi3 10 threads: 3.4 sec", " mpi3 20 threads: 2.0 sec", " mpi3 2x20 threads: 7.7 sec", " mpi3 4x20 threads: 13.6 sec", " mpi3 8x20 threads: 21.5 sec", ] } Slide { title: "Jacobi générique vs Hypre" fontFamily: 'Courier New' content: [ "matrice 13k x 13k, nnz: 365k, jacobi: 1512 iter.", "cluster nef, nœuds Xeon 20 cœurs, infiniband 40G", "openmpi-1.8.5.rc1", " jacobi sequentiel: 5.3 sec", " jacobi 20 procs: 1.1 sec", " jacobi 2x20 procs: 13.4 sec", " jacobi 10x4 procs: 7.3 sec", " hypre 1 proc: 0.7 sec", " hypre 4x4 procs: 0.14 sec", ] } Slide { title: "solveur Jacobi, résultats préliminaires" fontFamily: 'Courier New' content: [ "matrice 2M x 2M, nnz: 138M", "jacobi: 100 iterations", "cluster nef, nœuds Xeon 20 cœurs, infiniband 40G", "mvapich 2.1", " jacobi 1 proc: 188 sec", " jacobi 20 procs: 30 sec", " jacobi 4x20 procs: 101 sec", ] } Slide { title: "plugin MPI3: Retour d\'expérience" textFormat: Text.RichText content: [ "optimisations en mémoire partagés", " MPI_Win_allocate_shared", " MPI_Comm_split_type avec MPI_COMM_TYPE_SHARED", "communications RMA (One Sided) with Passive target", "implémentations MPI3 encore peu matures: ", " bugs remontés à openmpi, mvapich (corrigés)", " mais: An important part of MPI-3 deals with improved semantics and features for MPI RMA to address some of these criticisms and make MPI RMA a portable runtime system that can provide high-performance and feature-rich one-sided communication support to applications. Jeff Squyres" ] } Slide { title: "Perspectives" textFormat: Text.RichText content: [ "ADT SIMON (Jérémie Labroquère et Tristan Cabel)", " intégration de dtkSparseMatrix et dtkSparseSolver dans numWindSimulator (presque fait)", " dtkMesh basé sur dtkDistributedGraphTopology", " refonte de numWindSimulator basé sur dtkMesh distribué", " plugins MaPHyS", "optimisations ", "intégration dans le composer des structures distribuées de haut niveau", ] } Slide { title: "API documentation" ScrollView { height: parent.height width: parent.width WebView { id: webview url: "http://dtk-legacy.inria.fr/docs" anchors.fill: parent onNavigationRequested: { // detect URL scheme prefix, most likely an external link var schemaRE = /^\w+:/; if (schemaRE.test(request.url)) { request.action = WebView.AcceptRequest; } else { request.action = WebView.IgnoreRequest; // delegate request.url here } } } } } Slide { title: "Contacts" centeredText: "dtk-team@inria.fr" } } } /* dtkDistributed introduit un certain nombre de conteneurs (Array, Graph) qui ont vocation à masquer à l’utilisateur le recours explicite à des procédures de communication entre les processus. */ /* Le but étant de donner à l’utilisateur, autant que possible, la possibilité de programmer “comme en séquentiel”: */