void deryabin_m_cannons_algorithm_mpi::CannonsAlgo...
Criado em: 12 de fevereiro de 2025
Criado em: 12 de fevereiro de 2025
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_
);
}
}
}
}
}
}
Эта функция имеет когнитивную сложность 33, разбей эту функцию на две более простых функции, когнитивная сложность каждой из которых не будет превышать пороговое значение в 25
Ниже приведён пример, как можно разбить изначальную функцию на две более простых, чтобы снизить её когнитивную сложность. Идея в том, чтобы отдельно вынести логику копирования «локального» блока данных и логику отправки блоков другим процессам.
cppvoid 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; // Отправка фрагмента 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 { 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_ ); } } } } } }
Ниже показан способ вынести копирование данных в отдельную функцию CopyLocalBlocks()
, а логику рассылки – в функцию SendRemoteBlocks()
. Затем в основном методе DistributeDataIfRoot()
мы просто вызываем эти две функции по порядку.
cpp// Новая функция №1 — копирует локальный блок матриц A и B void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::CopyLocalBlocks() { // Копируем локальную часть матрицы A и B в local_input_matrix_A_ и local_input_matrix_B_ 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_) ); } } // Новая функция №2 — рассылает блоки матрицы A и B другим процессам void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::SendRemoteBlocks() { // Проходим по всем блокам (i, j) for (unsigned short i = 0; i < block_rows_columns_; ++i) { for (unsigned short j = 0; j < block_rows_columns_; ++j) { // Пропускаем локальный блок (0, 0), он уже скопирован в CopyLocalBlocks() 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 { 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() { // 1. Копируем локальный блок CopyLocalBlocks(); // 2. Рассылаем остальные блоки SendRemoteBlocks(); }
Таким образом, мы получаем более «плоскую» структуру кода, в которой каждая из функций решает свою задачу:
Каждая отдельная функция теперь имеет более низкую когнитивную сложность по сравнению с исходным вариантом, где все действия были собраны в одном методе.