void deryabin_m_cannons_algorithm_mpi::CannonsAlgo...

Criado em: 12 de fevereiro de 2025

Respondido usando O1 por Chat01

Pergunta

void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::DistributeDataIfRoot()
{
for (unsigned short k = 0; k < block_dimension_; ++k) {
std::copy(
input_matrix_A_.data() + (k * dimension_),
input_matrix_A_.data() + (k * dimension_) + block_dimension_,
local_input_matrix_A_.begin() + (k * block_dimension_)
);
std::copy(
input_matrix_B_.data() + (k * dimension_),
input_matrix_B_.data() + (k * dimension_) + block_dimension_,
local_input_matrix_B_.begin() + (k * block_dimension_)
);
}
for (unsigned short i = 0; i < block_rows_columns_; ++i) {
for (unsigned short j = 0; j < block_rows_columns_; ++j) {
if (i == 0 && j == 0) {
continue;
}
for (unsigned short k = 0; k < block_dimension_; ++k) {
int destination_proc = (i * block_rows_columns_) + j;
if (i == 0) {
world_.send(
destination_proc,
0,
input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
if (static_cast<int>((i * block_rows_columns_) + j - i) < static_cast<int>(i * block_rows_columns_)) {
world_.send(
destination_proc + block_rows_columns_ - i,
0,
input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
world_.send(
destination_proc - i,
0,
input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
}
}
if (j == 0) {
world_.send(
destination_proc,
1,
input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
if ((static_cast<int>((i - j) * block_rows_columns_) + j) < 0) {
world_.send(
((i + block_rows_columns_ - j) * block_rows_columns_) + j,
1,
input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
world_.send(
((i - j) * block_rows_columns_) + j,
1,
input_matrix_B_.data() + (((i * block_dimension_) + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
}
}
}
}
}
}

Разбей эту функцию на две более простых функции

Pensamento

Distribuindo dados

O código aqui está direcionando dados para resolver o problema de diodo em um contexto de algoritmo de Cannon. Interessante como ele adapta o processo de distribuição.

Reorganizando e enviando

Primeiro, o código está reorganizando os blocos de matrizes A e B nos processos locais. Em seguida, está enviando os blocos de matriz A para outros processos, ajustando dinamicamente os destinos.

Falando sobre os detalhes

Estou enviando blocos de matriz A e B para os processos apropriados, ajustando os destinos dinamicamente com base nas coordenadas. Isso está otimizando a comunicação e a eficiência no processo.

Distribuindo tarefas

Estou ajustando duas funções: uma para copiar blocos locais de A e B, e outra para enviar esses blocos para outros processos. Isso está melhorando a comunicação e eficiência geral.

Separando e preservando

Estou pensando em dividir a lógica: uma função para copiar e outra para enviar dados. Mantendo a lógica existente e usando inglês para os nomes.

Pensou por 15 segundos

Resposta

Ниже приведён пример, как можно разбить исходную функцию на две более простых. Первая функция будет выполнять локальное копирование блоков для корневого процесса, а вторая — рассылать остальные блоки по другим процессам.

cpp
void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::CopyLocalBlocks() { // Копируем локальный блок (0,0) для корневого процесса for (unsigned short k = 0; k < block_dimension_; ++k) { std::copy( input_matrix_A_.data() + (k * dimension_), input_matrix_A_.data() + (k * dimension_) + block_dimension_, local_input_matrix_A_.begin() + (k * block_dimension_) ); std::copy( input_matrix_B_.data() + (k * dimension_), input_matrix_B_.data() + (k * dimension_) + block_dimension_, local_input_matrix_B_.begin() + (k * block_dimension_) ); } } void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::SendBlocksToOtherProcesses() { for (unsigned short i = 0; i < block_rows_columns_; ++i) { for (unsigned short j = 0; j < block_rows_columns_; ++j) { // Корневой блок (i=0, j=0) уже скопирован локально, поэтому пропускаем if (i == 0 && j == 0) { continue; } for (unsigned short k = 0; k < block_dimension_; ++k) { int destination_proc = (i * block_rows_columns_) + j; // Отправка блоков матрицы A if (i == 0) { world_.send( destination_proc, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { if (static_cast<int>((i * block_rows_columns_) + j - i) < static_cast<int>(i * block_rows_columns_)) { world_.send( destination_proc + block_rows_columns_ - i, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { world_.send( destination_proc - i, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } } // Отправка блоков матрицы B if (j == 0) { world_.send( destination_proc, 1, input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { // Вычисляем реальный целевой процесс для блоков B с учётом циклического сдвига if ((static_cast<int>((i - j) * block_rows_columns_) + j) < 0) { world_.send( ((i + block_rows_columns_ - j) * block_rows_columns_) + j, 1, input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { world_.send( ((i - j) * block_rows_columns_) + j, 1, input_matrix_B_.data() + (((i * block_dimension_) + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } } } } } } void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::DistributeDataIfRoot() { // Сначала копируем локальный блок для корневого процесса CopyLocalBlocks(); // Затем рассылаем остальные блоки остальным процессам SendBlocksToOtherProcesses(); }

Краткие пояснения

  1. CopyLocalBlocks

    • Отвечает только за копирование блоков (0,0) матриц input_matrix_A_ и input_matrix_B_ в локальные буферы local_input_matrix_A_ и local_input_matrix_B_.
    • Благодаря этому, код становится чище: мы чётко видим, что здесь не происходит никакой сетевой отправки, а только локальные операции.
  2. SendBlocksToOtherProcesses

    • Содержит всю логику отправки остальных блоков всем процессам, кроме корневого (то есть для всех (i, j), кроме (0, 0)).
    • Разбивка на две функции позволяет проще понимать и поддерживать код. В одной функции сконцентрированы локальные копирования, а в другой — сетевые операции отправки по MPI.
  3. DistributeDataIfRoot

    • Вызывает по порядку:
      • CopyLocalBlocks,
      • SendBlocksToOtherProcesses.
    • Таким образом, сохраняется исходный порядок операций, но логика отделена на более понятные шаги.

Вы можете переименовывать функции так, как удобно для вашего проекта (например, InitializeLocalBlocks, DistributeBlocks, и т.д.). Главная идея — упростить чтение и поддержку кода путём разделения на более специализированные участки функционала.

Compartilhar esta Q&A