C++ 声明对象变量会使前面的所有指令变慢
我遇到了一个棘手的问题,我不知道是什么原因造成的。我希望你能帮我找到解决办法 框架:我使用CSR表示实现了一个稀疏矩阵类,并将此对象用作推荐系统的基础。该类定义如下:C++ 声明对象变量会使前面的所有指令变慢,c++,class,constructor,sparse-matrix,stdvector,C++,Class,Constructor,Sparse Matrix,Stdvector,我遇到了一个棘手的问题,我不知道是什么原因造成的。我希望你能帮我找到解决办法 框架:我使用CSR表示实现了一个稀疏矩阵类,并将此对象用作推荐系统的基础。该类定义如下: class sparse_matrix_csr { public: sparse_matrix_csr(); sparse_matrix_csr(const std::vector<int> &row_indices); sparse_matrix_csr
class sparse_matrix_csr
{
public:
sparse_matrix_csr();
sparse_matrix_csr(const std::vector<int> &row_indices);
sparse_matrix_csr(const std::vector<int> &row_indices, const size_t nb_columns);
// other member functions omitted
private:
std::vector<int> _row_indices;
std::vector<int> _row_start_indices;
std::vector<int> _column_indices;
std::vector<double> _values;
bool _column_sorted_by_index;
};
此构造函数接受稀疏矩阵行的索引以及每行中包含的元素数。事实上,在我考虑的应用程序中,我有相同的矩阵,这些矩阵仅在行中稀疏
问题:算法结构如下
\\ Instruction block 1
{
\\ Do something
}
sparse_matrix_csr mat(list_indices, nb_columns);
\\ Instruction block 2
{
\\ Do something
}
如果我单独运行第一个指令块(注释掉后面的所有指令),我的算法运行平稳。但是,如果我取消对算法的第二部分的注释,那么算法的第一部分会慢很多。我已经能够在mat
的声明中确定这种减速的临界线。但是,我无法在算法的第一部分解释这种追溯操作。完整的算法报告在我问题的末尾
我的考虑:我从未观察到这样的倒退行为,因此我有点困惑。我考虑过的一种可能性是,我在内存管理方面遇到了一个问题,导致算法的前一部分速度减慢。我目前正在研究一些矩阵,这些矩阵包含大约2e6个元素,即存储在2个向量中的大约4e6个值。我在另一篇关于堆栈溢出的文章中读到,std::vector中包含的数据是在堆中分配的。这总是真的吗?即使我像在上面的稀疏矩阵构造函数中那样初始化一个给定大小的向量
如果你需要澄清,不要犹豫
提前感谢,,
皮尔保洛
完整算法:
void collaborative_filtering_mpi (std::string ratings_file, std::string targets_file,
std::string output_file, int k_neighbors, double shrinkage_factor,
bool output_debug_data)
{
std::cout << "COLLABORATIVE FILTERING ALGORITHM - k = " << k_neighbors
<< " , d = " << shrinkage_factor << std::endl;
stopwatch sw_total;
sw_total.start();
//-------------------------------------
// STEP 1: Read data from input files
//-------------------------------------
std::cout << "1) Read input files: ";
stopwatch sw;
sw.start();
//-------------------------------
// 1.1) Read user rating matrix
//-------------------------------
// Initialization
sparse_matrix_csr user_item_rating_matrix(ratings_file, true, true, true); // file is sorted, skip header
//-------------------------------------------------
// 1.2) Read targets (user, item) to be predicted
//-------------------------------------------------
// Initialization
sparse_matrix_csr targets(targets_file, true, false, false); // do not read ratings column
sw.stop();
double time_input = sw.get_duration();
std::cout << time_input << std::endl;
//-----------------------------------------
// STEP 2: Pre-computations
//-----------------------------------------
std::cout << "2) Pre-computations: ";
sw.start();
//-----------------------------------------------------------------------
// 2.1) Sort user_item_rating_matrixand compute relevant sizes of the problem
//-----------------------------------------------------------------------
// Sort: if file is sorted, sort should do nothing.
user_item_rating_matrix.sort_columns_by_index();
// Compute list of users and list of items
std::vector<int> list_users;
user_item_rating_matrix.rows(list_users);
std::vector<int> list_items;
user_item_rating_matrix.columns(list_items);
// [DEBUG]: print user_rating_matrix
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_user_rating_matrix.txt");
ofs_debug << user_item_rating_matrix;
ofs_debug.close();
}
//-------------------------------------------------------------
// 2.2) Compute inverse user rating matrix (indexed by column)
//-------------------------------------------------------------
// Initialize item_user_rating_matrix: it is a sparse matrix with
// items on the rows, users on the columns and rating as values.
// This variable will be helpful when computing similarities.
sparse_matrix_csr item_user_rating_matrix;
// Compute item_user_rating<_matrix by transposing the user_rating_matrix
transpose (user_item_rating_matrix, item_user_rating_matrix);
// [DEBUG]: print item_user_matrix_on_file
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_item_user_matrix.txt");
ofs_debug << item_user_rating_matrix;
ofs_debug.close();
}
//-----------------------------------------------
// 2.3) sort targets and compute relevant sizes
//-----------------------------------------------
// Compute list of target items
std::vector<int> list_target_items;
targets.columns(list_target_items);
// [DEBUG]: print targets
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_targets.txt");
ofs_debug << targets;
ofs_debug.close();
}
//--------------------------------------------------------------
// 2.4) Compute difference between list_items and list_targets
//--------------------------------------------------------------
std::vector<int> list_non_target_items;
compute_difference_vector (list_items, list_target_items, list_non_target_items);
// [DEBUG]
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_difference_vector.txt");
ofs_debug << "list_items - size: " << list_items.size() << std::endl;
for (std::vector<int>::const_iterator iter = list_items.begin(); iter != list_items.end(); ++iter)
ofs_debug << (*iter) << ",";
ofs_debug << std::endl << std::endl;
ofs_debug << "list_target_items - size: " << list_target_items.size() << std::endl;
for (std::vector<int>::const_iterator iter = list_target_items.begin(); iter != list_target_items.end(); ++iter)
ofs_debug << (*iter) << ",";
ofs_debug << std::endl << std::endl;
ofs_debug << "list_non_target_items - size: " << list_non_target_items.size() << std::endl;
for (std::vector<int>::const_iterator iter = list_non_target_items.begin(); iter != list_non_target_items.end(); ++iter)
ofs_debug << (*iter) << ",";
ofs_debug << std::endl << std::endl;
ofs_debug.close();
}
//--------------------------------------------
// 2.5) Compute average rating for each user
//--------------------------------------------
dictionary<int, double> average_rating_vector;
compute_average_rating(user_item_rating_matrix, average_rating_vector);
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_average_rating_vector.txt");
for (dictionary<int, double>::const_iterator iter = average_rating_vector.begin();
iter != average_rating_vector.end(); ++iter)
ofs_debug << (*iter).get_key() << ": " << (*iter).get_value() << std::endl;
ofs_debug.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//-------------------------------------
// STEP 3: Similarity matrix
//-------------------------------------
std::cout << "3) Compute similarity matrix: ";
sw.start();
// Initialize similarity_matrix with target items on the rows.
sparse_matrix_csr similarity_matrix(list_target_items,
list_target_items.size() + list_non_target_items.size());
// compute similarity matrix
compute_similarity_matrix_mpi(similarity_matrix,
item_user_rating_matrix,
average_rating_vector,
list_target_items,
list_non_target_items,
shrinkage_factor);
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs("data_debug/debug_similarity_matrix.txt");
ofs << similarity_matrix;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//---------------------------------------------------------------
// STEP 4: Find top-K similar elements with positive similarity
//---------------------------------------------------------------
std::cout << "4) Find top-K similar elements:" << std::endl;
sw.start();
if (k_neighbors > 0)
{
//---------------------------------------------------
// 4.1) Sort similarity matrix by rating (row-wise)
//---------------------------------------------------
std::cout << " .... Sort similarity matrix by rating: ";
sw.start();
// Sort all the rows of the similarity_matrix by similarity.
// If two items have the same rating, sort them in descending order of item.
//similarity_matrix.sort_columns_by_value();
similarity_matrix.sort_columns_by_value();
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_sorted_by_rating.txt");
ofs << similarity_matrix;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//--------------------------------------------------------
// 4.2) Cut the useless columns of the similarity matrix
//--------------------------------------------------------
std::cout << " .... Reduce similarity matrix: ";
sw.start();
sparse_matrix_csr similarity_matrix_reduced(list_target_items,
k_neighbors);
reduce_similarity_matrix_mpi (similarity_matrix,
similarity_matrix_reduced,
k_neighbors);
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_reduced.txt");
ofs << similarity_matrix_reduced;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//---------------------------------------------------
// 4.3) Sort the reduced similarity matrix by items
//---------------------------------------------------
std::cout << " .... Sort similarity matrix by index: ";
sw.start();
// Sort all the rows of the similarity_matrix by index.
similarity_matrix_reduced.sort_columns_by_index();
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_sorted.txt");
ofs << similarity_matrix_reduced;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//-----------------------------------------
// STEP 5: Compute predictions for targets
//-----------------------------------------
std::cout << "5) Compute predictions: ";
sw.start();
compute_predicted_ratings_mpi (targets,
user_item_rating_matrix,
similarity_matrix_reduced);
sw.stop();
std::cout << sw.get_duration() << std::endl;
}
else
{
//---------------------------------------------------
// 4.3) Sort the reduced similarity matrix by items
//---------------------------------------------------
std::cout << " .... Sort similarity matrix by index: ";
sw.start();
// Sort all the rows of the similarity_matrix by index.
// similarity_matrix.sort_columns_by_index();
similarity_matrix.sort_columns_by_index();
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_sorted.txt");
ofs << similarity_matrix;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//-----------------------------------------
// STEP 5: Compute predictions for targets
//-----------------------------------------
std::cout << "5) Compute predictions: ";
sw.start();
compute_predicted_ratings_mpi (targets,
user_item_rating_matrix,
similarity_matrix);
sw.stop();
std::cout << sw.get_duration() << std::endl;
}
//-----------------------------------------------------
// STEP 6: Print the prediction matrix in output file
//-----------------------------------------------------
std::cout << "6) Print predictions on file: ";
sw.start();
std::ofstream ofs_output(output_file);
targets.print(ofs_output);
sw.stop();
double time_output = sw.get_duration();
std::cout << time_output << std::endl;
sw_total.stop();
double time_total = sw_total.get_duration();
std::cout << ">> Total computation time: " << time_total << std::endl;
std::cout << ">> Total computation time - no input/output: " << (time_total - time_input - time_output) << std::flush;
}
这一修改并没有改善情况。我目前在32位虚拟机和64位笔记本电脑上都有问题。我不知道是什么原因导致程序如此缓慢 这是很多代码。您是否尝试过简化它,直到问题消失,以缩小可能的原因(并减少代码供其他人使用)?尽管如此,还是要感谢您提出了一个整体结构良好的问题,即使代码中有注释!你是如何测量第一个区块的时间的,有没有第二个区块?很难说你是如何测量的。我不相信测量中没有错误。也就是说,您是否尝试使用
new
来分配它?我的猜测是,堆栈帧中的变量布局是这样的,当您添加那个大的ish对象时,其他局部变量不会完全适合缓存线。如果是这种情况,动态代码应该与注释掉的版本一样快。声明是否可能使用第一节中的一些输出,从而阻止编译器优化掉一些计算?为了测量执行时间,我执行代码,直到相似性\u矩阵\u的声明减少(排除)注释掉以下所有代码,我将其与添加声明的执行进行了比较。显然,编译器可能在这两种情况下应用了不同的优化,但我认为这不能解释如此缓慢的速度(超过x100)此外,相似性矩阵的初始化与以前的数据无关。最后,std::vector不应该在堆中初始化吗(即使没有新的数据)?
void collaborative_filtering_mpi (std::string ratings_file, std::string targets_file,
std::string output_file, int k_neighbors, double shrinkage_factor,
bool output_debug_data)
{
std::cout << "COLLABORATIVE FILTERING ALGORITHM - k = " << k_neighbors
<< " , d = " << shrinkage_factor << std::endl;
stopwatch sw_total;
sw_total.start();
//-------------------------------------
// STEP 1: Read data from input files
//-------------------------------------
std::cout << "1) Read input files: ";
stopwatch sw;
sw.start();
//-------------------------------
// 1.1) Read user rating matrix
//-------------------------------
// Initialization
sparse_matrix_csr user_item_rating_matrix(ratings_file, true, true, true); // file is sorted, skip header
//-------------------------------------------------
// 1.2) Read targets (user, item) to be predicted
//-------------------------------------------------
// Initialization
sparse_matrix_csr targets(targets_file, true, false, false); // do not read ratings column
sw.stop();
double time_input = sw.get_duration();
std::cout << time_input << std::endl;
//-----------------------------------------
// STEP 2: Pre-computations
//-----------------------------------------
std::cout << "2) Pre-computations: ";
sw.start();
//-----------------------------------------------------------------------
// 2.1) Sort user_item_rating_matrixand compute relevant sizes of the problem
//-----------------------------------------------------------------------
// Sort: if file is sorted, sort should do nothing.
user_item_rating_matrix.sort_columns_by_index();
// Compute list of users and list of items
std::vector<int> list_users;
user_item_rating_matrix.rows(list_users);
std::vector<int> list_items;
user_item_rating_matrix.columns(list_items);
// [DEBUG]: print user_rating_matrix
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_user_rating_matrix.txt");
ofs_debug << user_item_rating_matrix;
ofs_debug.close();
}
//-------------------------------------------------------------
// 2.2) Compute inverse user rating matrix (indexed by column)
//-------------------------------------------------------------
// Initialize item_user_rating_matrix: it is a sparse matrix with
// items on the rows, users on the columns and rating as values.
// This variable will be helpful when computing similarities.
sparse_matrix_csr item_user_rating_matrix;
// Compute item_user_rating<_matrix by transposing the user_rating_matrix
transpose (user_item_rating_matrix, item_user_rating_matrix);
// [DEBUG]: print item_user_matrix_on_file
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_item_user_matrix.txt");
ofs_debug << item_user_rating_matrix;
ofs_debug.close();
}
//-----------------------------------------------
// 2.3) sort targets and compute relevant sizes
//-----------------------------------------------
// Compute list of target items
std::vector<int> list_target_items;
targets.columns(list_target_items);
// [DEBUG]: print targets
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_targets.txt");
ofs_debug << targets;
ofs_debug.close();
}
//--------------------------------------------------------------
// 2.4) Compute difference between list_items and list_targets
//--------------------------------------------------------------
std::vector<int> list_non_target_items;
compute_difference_vector (list_items, list_target_items, list_non_target_items);
// [DEBUG]
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_difference_vector.txt");
ofs_debug << "list_items - size: " << list_items.size() << std::endl;
for (std::vector<int>::const_iterator iter = list_items.begin(); iter != list_items.end(); ++iter)
ofs_debug << (*iter) << ",";
ofs_debug << std::endl << std::endl;
ofs_debug << "list_target_items - size: " << list_target_items.size() << std::endl;
for (std::vector<int>::const_iterator iter = list_target_items.begin(); iter != list_target_items.end(); ++iter)
ofs_debug << (*iter) << ",";
ofs_debug << std::endl << std::endl;
ofs_debug << "list_non_target_items - size: " << list_non_target_items.size() << std::endl;
for (std::vector<int>::const_iterator iter = list_non_target_items.begin(); iter != list_non_target_items.end(); ++iter)
ofs_debug << (*iter) << ",";
ofs_debug << std::endl << std::endl;
ofs_debug.close();
}
//--------------------------------------------
// 2.5) Compute average rating for each user
//--------------------------------------------
dictionary<int, double> average_rating_vector;
compute_average_rating(user_item_rating_matrix, average_rating_vector);
if (output_debug_data)
{
std::ofstream ofs_debug("data_debug/debug_average_rating_vector.txt");
for (dictionary<int, double>::const_iterator iter = average_rating_vector.begin();
iter != average_rating_vector.end(); ++iter)
ofs_debug << (*iter).get_key() << ": " << (*iter).get_value() << std::endl;
ofs_debug.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//-------------------------------------
// STEP 3: Similarity matrix
//-------------------------------------
std::cout << "3) Compute similarity matrix: ";
sw.start();
// Initialize similarity_matrix with target items on the rows.
sparse_matrix_csr similarity_matrix(list_target_items,
list_target_items.size() + list_non_target_items.size());
// compute similarity matrix
compute_similarity_matrix_mpi(similarity_matrix,
item_user_rating_matrix,
average_rating_vector,
list_target_items,
list_non_target_items,
shrinkage_factor);
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs("data_debug/debug_similarity_matrix.txt");
ofs << similarity_matrix;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//---------------------------------------------------------------
// STEP 4: Find top-K similar elements with positive similarity
//---------------------------------------------------------------
std::cout << "4) Find top-K similar elements:" << std::endl;
sw.start();
if (k_neighbors > 0)
{
//---------------------------------------------------
// 4.1) Sort similarity matrix by rating (row-wise)
//---------------------------------------------------
std::cout << " .... Sort similarity matrix by rating: ";
sw.start();
// Sort all the rows of the similarity_matrix by similarity.
// If two items have the same rating, sort them in descending order of item.
//similarity_matrix.sort_columns_by_value();
similarity_matrix.sort_columns_by_value();
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_sorted_by_rating.txt");
ofs << similarity_matrix;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//--------------------------------------------------------
// 4.2) Cut the useless columns of the similarity matrix
//--------------------------------------------------------
std::cout << " .... Reduce similarity matrix: ";
sw.start();
sparse_matrix_csr similarity_matrix_reduced(list_target_items,
k_neighbors);
reduce_similarity_matrix_mpi (similarity_matrix,
similarity_matrix_reduced,
k_neighbors);
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_reduced.txt");
ofs << similarity_matrix_reduced;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//---------------------------------------------------
// 4.3) Sort the reduced similarity matrix by items
//---------------------------------------------------
std::cout << " .... Sort similarity matrix by index: ";
sw.start();
// Sort all the rows of the similarity_matrix by index.
similarity_matrix_reduced.sort_columns_by_index();
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_sorted.txt");
ofs << similarity_matrix_reduced;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//-----------------------------------------
// STEP 5: Compute predictions for targets
//-----------------------------------------
std::cout << "5) Compute predictions: ";
sw.start();
compute_predicted_ratings_mpi (targets,
user_item_rating_matrix,
similarity_matrix_reduced);
sw.stop();
std::cout << sw.get_duration() << std::endl;
}
else
{
//---------------------------------------------------
// 4.3) Sort the reduced similarity matrix by items
//---------------------------------------------------
std::cout << " .... Sort similarity matrix by index: ";
sw.start();
// Sort all the rows of the similarity_matrix by index.
// similarity_matrix.sort_columns_by_index();
similarity_matrix.sort_columns_by_index();
// [DEBUG]: print similarity matrix sorted by similarity
if (output_debug_data)
{
std::ofstream ofs ("data_debug/debug_similarity_matrix_sorted.txt");
ofs << similarity_matrix;
ofs.close();
}
sw.stop();
std::cout << sw.get_duration() << std::endl;
//-----------------------------------------
// STEP 5: Compute predictions for targets
//-----------------------------------------
std::cout << "5) Compute predictions: ";
sw.start();
compute_predicted_ratings_mpi (targets,
user_item_rating_matrix,
similarity_matrix);
sw.stop();
std::cout << sw.get_duration() << std::endl;
}
//-----------------------------------------------------
// STEP 6: Print the prediction matrix in output file
//-----------------------------------------------------
std::cout << "6) Print predictions on file: ";
sw.start();
std::ofstream ofs_output(output_file);
targets.print(ofs_output);
sw.stop();
double time_output = sw.get_duration();
std::cout << time_output << std::endl;
sw_total.stop();
double time_total = sw_total.get_duration();
std::cout << ">> Total computation time: " << time_total << std::endl;
std::cout << ">> Total computation time - no input/output: " << (time_total - time_input - time_output) << std::flush;
}
class sparse_matrix_csr
{
public:
\\ public methods omitted
private:
class sparse_matrix_csr_data
{
public:
sparse_matrix_csr_data() {}
sparse_matrix_csr_data(const std::vector<int> &row_indices): _row_indices(row_indices) {}
sparse_matrix_csr_data(const std::vector<int> &row_indices, const size_t nb_columns);
sparse_matrix_csr_data(const std::string file, bool file_is_sorted, bool skip_header, bool read_values);
// data
std::vector<int> _row_indices;
std::vector<int> _row_start_indices;
std::vector<int> _column_indices;
std::vector<double> _values;
bool _column_sorted_by_index;
};
std::shared_ptr<sparse_matrix_csr_data> _data;
};