Как сделать мою программу быстрее с помощью Open MPI?Моя программа Open MPI в настоящее время работает медленнее, чем оригинал, что я не понимаю? - PullRequest
1 голос
/ 05 апреля 2019

Я написал программу для назначения, которая взламывает пароли, используя атаку по словарю, и пытаюсь ускорить ее, используя Open MPI, но моя версия Open MPI медленнее, и я не уверен, почему или чего я не понимаю. Зашифрованные пароли генерируются с использованием соли и строки, передаваемой в unix-функцию «crypt».

Из того, что я узнал по просмотрам лекций в классе, я пришел к этому.

main.cc:

//****************************************************
// File: main.cc
// Author: Jordan Ward
// Purpose: Crack passwords in the form word+number
// or number+word where number can be at most
// three digits long using
// Open MPI to make it more efficient.
//*****************************************************

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <unistd.h>
#include <mpi.h>

using namespace std;

// Builds the list of encrypted passwords,
// list of dictionary words, and list of salts.
void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
            vector<string> &salts);

// Builds the list of possible guesses.
void build_guesses(vector<string> &guesses, vector<string> &words);

// Tries each of the salts with each of
// the strings in the list of guesses to see
// if they match the ecrypted passwords.
void crack(string pass, vector<string> &salts, vector<string> &guesses);

// Broadcasts the vectors to all other processes.
void broadcast_receive(vector<string> &encPass, vector<string> &words,
                       vector<string> &salts, vector<string> &guesses);

// Converts a vector of strings to a vector of chars
vector<char> convert(vector<string> &strings);

int main(int argc, char *argv[]) {
    vector<string> encPass;
    vector<string> words;
    vector<string> salts;
    vector<string> guesses;

    int numProcesses;
    int procNum;

    MPI_Init(NULL, NULL);

    MPI_Comm_size(MPI_COMM_WORLD, &numProcesses);   // Get the number of processes
    MPI_Comm_rank(MPI_COMM_WORLD, &procNum);        // Get the process number

    if(procNum == 0) {
        file_IO(argc, argv, encPass, words, salts);
        build_guesses(guesses, words);
    }

    broadcast_receive(encPass, words, salts, guesses, numProcesses, procNum);

    if(procNum != 0) {
        for(size_t i = 0; i < encPass.size(); i++) {
            if(i % procNum == 0) {
                size_t del = encPass[i].rfind("$");         // Finds the last "$" in the string
                string pass = encPass[i].substr(del);       // Pass is a substring starting at the last "$"
                crack(pass, salts, guesses);
            }
        }
    }

    MPI_Finalize();
    return 0;
}


void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
            vector<string> &salts) {

    if(argc < 3) {
        cout << "One or more files were not specified." << endl;
        cout << "Correct format is 'mpiexec a.out file1 file2'" << endl;
        exit(1);
    }

    ifstream secretPass(argv[1]);
    string singlePass;

    while(getline(secretPass, singlePass)) {
        encPass.push_back(singlePass);
    }

    secretPass.close();

    ifstream dictionary(argv[2]);
    string word;

    while(getline(dictionary, word)) {
        words.push_back(word);
    }

    dictionary.close();

    ifstream salt("salts");
    string s;

    while(getline(salt, s)) {
        salts.push_back(s);
    }

    salt.close();
}

void build_guesses(vector<string> &guesses, vector<string> &words) {
    //one word and one number
    for(size_t i = 0; i < words.size(); i++) {
        for(size_t j = 0; j < 10; j++) {
            guesses.push_back(words[i] + to_string(j));
        }
    }

    //one number and one word
    for(size_t i = 0; i < 10; i++) {
        for(size_t j = 0; j < words.size(); j++) {
            guesses.push_back(to_string(i) + words[j]);
        }
    }

    //one word and two numbers
    for(size_t i = 0; i < words.size(); i++) {
        for(size_t j = 0; j < 10; j++) {
            for(size_t x = 0; x < 10; x++) {
                guesses.push_back(words[i] + to_string(j) + to_string(x));
            }
        }
    }

    //two numbers and one word
    for(size_t i = 0; i < 10; i++) {
        for(size_t j = 0; j < 10; j++) {
            for(size_t x = 0; x < words.size(); x++) {
                guesses.push_back(to_string(i) + to_string(j) + words[x]);
            }
        }
    }

    //one word and three numbers
    for(size_t i = 0; i < words.size(); i++) {
        for(size_t j = 0; j < 10; j++) {
            for(size_t x = 0; x < 10; x++) {
                for(size_t y = 0; y < 10; y++) {
                    guesses.push_back(words[i] + to_string(j) + to_string(x) + to_string(y));
                }
            }
        }
    }

    //three numbers and one word
    for(size_t i = 0; i < 10; i++) {
        for(size_t j = 0; j < 10; j++) {
            for(size_t x = 0; x < 10; x++) {
                for(size_t y = 0; y < words.size(); y++) {
                    guesses.push_back(to_string(i) + to_string(j) + to_string(x) + words[y]);
                }
            }
        }
    }
}

void crack(string pass, vector<string> &salts, vector<string> &guesses) {
    for(size_t i = 0; i < salts.size(); i++) {
        for(size_t j = 0; j < guesses.size(); j++) {
            string ep = crypt(guesses[j].c_str(), salts[i].c_str());

            if(ep.compare(salts[i] + pass) == 0) {
                cout << "Password: " + guesses[j] << endl;
            }
        }
    }

    cout << "Password not found" << endl;
}

void broadcast_receive(vector<string> &encPass, vector<string> &words,
                       vector<string> &salts, vector<string> &guesses) {

    int buffer[5];

    buffer[0] = encPass.size();
    buffer[1] = words.size();
    buffer[2] = salts.size();
    buffer[3] = guesses.size();

    MPI_Bcast(buffer, 4, MPI_INT, 0, MPI_COMM_WORLD);

    encPass.resize(buffer[0]);
    words.resize(buffer[1]);
    salts.resize(buffer[2]);
    guesses.resize(buffer[3]);

    vector<char> ep = convert(encPass);
    vector<char> w = convert(words);
    vector<char> s = convert(salts);
    vector<char> g = convert(guesses);

    MPI_Bcast(ep.data(), ep.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
    MPI_Bcast(w.data(), w.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
    MPI_Bcast(s.data(), s.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
    MPI_Bcast(g.data(), g.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
}

vector<char> convert(vector<string> &strings) {
    vector<char> cstrings;
    cstrings.reserve(strings.size());

    for(string s : strings) {
        for(size_t i = 0; i < strlen(s.c_str()); i++) {
            cstrings.push_back(s.c_str()[i]);
        }
    }

    return cstrings;
}

Мой мыслительный процесс:

Если номер процесса равен 0, прочитайте файлы и постройте векторы со строками из файлов, а затем создайте список догадок.

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

Что я делаю неправильно или не понимаю, что делает это медленнее, чем оригинал без кода Open MPI? Исходный код будет просто одним и тем же файлом без функций broadcast_receive и convert и, очевидно, без вызовов MPI в основной функции.

Я компилирую с mpic++ -std=c++11 -Wall main.cc -lcrypt, а затем запускаю с mpiexec a.out enc_passwords words, где enc_passwords - это небольшой файл с некоторыми зашифрованными паролями, сгенерированными из функции crypt, а words - это небольшой список слов для построения догадок.

1 Ответ

0 голосов
/ 08 апреля 2019

Относительно вашего первого вопроса (почему MPI не «быстрее»?), Вам нужно задать два вопроса:

В: Действительно ли работа распределяется параллельно между несколькими процессорами?

В: Превышают ли издержки передачи сообщений фактическую работу, которую вы пытаетесь распараллелить?

Это должно помочь с обоими вопросами:

Часто задаваемые вопросы по OpenMPI: Performance Tools

Что касается вашего последующего комментария, "... но по какой-то причине он вызывает массу ошибок." : пожалуйста, предоставьте MCVE . Или просто вернитесь обратно к «рабочему» коду.

...