MPI Сбор массивов строк - PullRequest
       29

MPI Сбор массивов строк

1 голос
/ 26 апреля 2020

Я пытаюсь объединить коллекцию словарей в процесс root. Вот краткий пример:

#define MAX_CF_LENGTH 55

    map<string, int> dict;

    if (rank == 0)
    {
        dict = {
            {"Accelerator Defective", 33},
            {"Aggressive Driving/Road Rage", 27},
            {"Alcohol Involvement", 19},
            {"Animals Action", 30}};
    }
    if (rank == 1)
    {
        dict = {
            {"Driver Inexperience", 6},
            {"Driverless/Runaway Vehicle", 46},
            {"Drugs (Illegal)", 38},
            {"Failure to Keep Right", 24}};
    }
    if (rank == 2)
    {
        dict = {
            {"Lost Consciousness", 1},
            {"Obstruction/Debris", 8},
            {"Other Electronic Device", 25},
            {"Other Lighting Defects", 43},
            {"Other Vehicular", 7}};
    }

    Scatterer scatterer(rank, MPI_COMM_WORLD, num_workers);
    scatterer.gatherDictionary(dict, MAX_CF_LENGTH);

Идея внутри gatherDictionary() состоит в том, чтобы поместить каждый ключ в массив char в каждом процессе (дубликаты допускаются). После этого собираем все ключи в root и создаем окончательный (объединенный) словарь перед его трансляцией. Вот код:

void Scatterer::gatherDictionary(map<string,int> &dict, int maxKeyLength)
{
    // Calculate destination dictionary size
    int numKeys = dict.size();
    int totalLength = numKeys * maxKeyLength;
    int finalNumKeys = 0;
    MPI_Reduce(&numKeys, &finalNumKeys, 1, MPI_INT, MPI_SUM, 0, comm);

    // Computing number of elements that are received from each process
    int *recvcounts = NULL;
    if (rank == 0)
        recvcounts = new int[num_workers];

    MPI_Gather(&totalLength, 1, MPI_INT, recvcounts, 1, MPI_INT, 0, comm);

    // Computing displacement relative to recvbuf at which to place the incoming data from each process
    int *displs = NULL;
    if (rank == 0)
    {
        displs = new int[num_workers];

        displs[0] = 0;
        for (int i = 1; i < num_workers; i++)
            displs[i] = displs[i - 1] + recvcounts[i - 1] + 1;
    }

    char(*dictKeys)[maxKeyLength];
    char(*finalDictKeys)[maxKeyLength];
    dictKeys = (char(*)[maxKeyLength])malloc(numKeys * sizeof(*dictKeys));
    if (rank == 0)
        finalDictKeys = (char(*)[maxKeyLength])malloc(finalNumKeys * sizeof(*finalDictKeys));

    // Collect keys for each process
    int i = 0;
    for (auto pair : dict)
    {
        strncpy(dictKeys[i], pair.first.c_str(), maxKeyLength);
        i++;
    }

    MPI_Gatherv(dictKeys, totalLength, MPI_CHAR, finalDictKeys, recvcounts, displs, MPI_CHAR, 0, comm);

    // Create new dictionary and distribute it to all processes
    dict.clear();
    if (rank == 0)
    {
        for (int i = 0; i < finalNumKeys; i++)
            dict[finalDictKeys[i]] = dict.size();
    }

    delete[] dictKeys;
    if (rank == 0)
    {
        delete[] finalDictKeys;
        delete[] recvcounts;
        delete[] displs;
    }

    broadcastDictionary(dict, maxKeyLength);
}

Я уверен в broadcastDicitonary() правильности, поскольку я уже проверял это. Отладка в функции сбора Я получаю следующие частичные результаты:

Recvcounts:
220
220
275

Displacements:
0
221
442

FinalDictKeys:
Rank:0 Accelerator Defective
Rank:0 Aggressive Driving/Road Rage
Rank:0 Alcohol Involvement
Rank:0 Animals Action
Rank:0 
Rank:0 
Rank:0 
Rank:0 
Rank:0 
Rank:0 
Rank:0 
Rank:0 
Rank:0 

Поскольку собираются только данные root, мне интересно, имеет ли это какое-то отношение к распределению символов, даже если это должно быть смежным Я не думаю, что это связано с отсутствующим нулевым символом в конце, так как для каждой строки / ключа уже есть много отступов. Заранее благодарим за указание на какие-либо упущения или улучшения и, пожалуйста, прокомментируйте, если вам нужна дополнительная информация.

Если вы хотите sh, чтобы проверить это самостоятельно, я поместил в один файл только код все вместе , он готов к компиляции и запуску (конечно, это работает с процессами 3 MPI). Код здесь

1 Ответ

2 голосов
/ 26 апреля 2020
displs[i] = displs[i - 1] + recvcounts[i - 1] + 1;

То, что + 1 в конце, излишне. Измените его на:

displs[i] = displs[i - 1] + recvcounts[i - 1];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...