C++ CPU 未充分利用
C++ CPU not full utilized
>我在C++遇到了奇怪的性能下降,有人可以帮助我确定问题所在吗?
我正在做一个基于特征库的样本外预测问题。我使用扩展窗口方法来合并新的观察向量,并使用LBFGS方法来最大化似然函数。
具体来说,在 for 循环中,我选择数据mY
( Y = mY.block(0,0,24,756+i)
Y
的子集块,并使用这个数据子集通过函数估计参数callLBFGS
并将估计值存储在 vP 向量中(我通过引用传递vP
)。接下来,我将vP
的值复制到结果矩阵mRet
中,并将mRet
写入csv文件。
我之所以将 WriteCSV 放入循环中,是因为callLBFGS
非常耗时。如果优化失败,我想中止程序和调试,但我不想丢失已经优化的估计值,所以我每次完成循环时都会将其写入 csv。我完全看不出将WriteCSV
放入循环中的问题,因为callLBFGS
通常需要长达 10 分钟的时间,但将 102 x 40 的矩阵写入 csv 通常需要几毫秒。
这是我的问题:我写的callLBFGS
函数是使用 OpenMP 的多线程,没有把WriteCSV
函数放在循环内,CPU 利用率为 95%-100%,但循环内有WriteCSV
函数,CPU 利用率下降到 50%-60%。
这很奇怪,超出了我的知识范围,考虑到callLBFGS
消耗的时间比WriteCSV
多数千倍。CPU 不应该花太多时间在调度和分叉新线程上。有人可以帮助我确定问题吗?非常感谢!
MatrixXd mY = mData.transpose();
double adFunc;
char *Result = "BFGSEst.csv";
VectorXd vP(102);
MatrixXd Y;
Matrix<double,102,40> mRet;
vP = IniPar.col(0);
for (int i = 0; i < 40; ++i) {
Y = mY.block(0,0,24,756+i);
callLBFGS(vP,&adFunc,Y,10000);
mRet.col(i) = vP;
WriteCSV(Result,mRet); /*this is the killer*/
}
我的函数调用LBFGS和WriteCSV看起来像这样:
void callLBFGS(VectorXd &vP, double *adFunc, MatrixXd &Y, int MaxIter);
void WriteCSV(char *filename, MatrixXd X);
编辑*非常感谢您的所有回复。下面是我对WriteCSV
的实现,相当幼稚。澄清一下,我说callLBFGS
最多需要 10 分钟是每次调用callLBFGS
最多需要 10 分钟(多维最小化)。因此,整个循环需要数小时才能完成。我知道如果callLBFGS
和WriteCSV
消耗的时间相似,那么CPU无法充分利用也就不足为奇了。但这里是WriteCSV
花费的时间比callLBFGS
少得多,我不应该期望在callLBFGS
的过程中CPU使用率下降到那么大的程度。
void WriteCSV(char *filename, MatrixXd X){
ofstream myfile;
myfile.open (filename);
for (int i = 0; i < X.rows(); ++i)
{
for (int j = 0; j < X.cols(); ++j)
{
myfile<<X(i,j);
if (j!=X.cols()-1)
{
myfile<<",";
}else{
myfile<<"n";
}
}
}
myfile.close();
}
抱歉,这应该只是一个评论,但我还不能
在 MatrixXd<> 中可能会无形地发生惰性评估。
惰性求值可能发生在 WriteCSV(...) 中,再加上必然的单线程 IO 会降低您的总 CPU 利用率。
延迟或延迟评估可以在任何地方,但可能隐藏在简单的检索或复制语句中,例如:
mRet.col(i) = vP;
或
myfile<<X(i,j);
其他海报可能都更正确,我赞同将 IO 线程化的建议。
考虑到您按值传递MatrixXd
,最快的解决方法是启动一个单独的线程来执行实际写入、分离并立即返回。
作为一个小小的改进,我会写','
而不是","
但这更像是一种风格。
对于 I/O 操作,您手中没有太多东西,因此您无法对此执行太多操作。因此,请将优化添加到 CPU 绑定进程或进程的 CPU 绑定部分!因为这在很大程度上掌握在你手中。此 writeCSV 函数是一个 I/O 绑定进程,它执行 40 次,而您未将其包含在循环中时执行一次。
我在代码中看到两个问题:
- 您正在使用C++流,这些流不以其高性能:) 而闻名
- 您正在等待文件 I/O 完成,然后再开始下一次迭代。
为了解决第一个问题,我会使用一个很好的旧printf()
。对于第二个 - 异步 I/O;创建传入矩阵的副本(您已经传递了它的副本),启动 I/O 并返回。
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- 编写一个函数以使用 n 百分比的 CPU 使用率
- 如何禁用 CPU 的无序执行
- CPU 瓶颈;处理具有许多非静态对象的 3D 场景渲染的简单方法
- 分别测量每个线程上花费的 CPU 时间(C++)
- 什么时候最好在子进程中使用 CPU 或 I/O 密集型代码 [ C++ ]
- 在程序运行时监视 VxWorks 中的任务 CPU 利用率
- 对于等待以 std::future wait() 返回的函数的 CPU 使用率或检查标志在循环中休眠一段时间哪个更好?
- 您选择的 CPU 不支持 x86-64 指令集
- 如何降低应用程序的 CPU 使用率?
- 对于 CPU 无法原子操作的类型,std::atomic 有什么意义?
- 如何区分CPU和内存瓶颈?
- 如何以编程方式获取任务管理器进程CPU使用率(不是PerfMon API)
- CPU 如何提供memory_order_acquire保证?
- 一段时间后 CPU 使用率高
- C/C++memcpu基准测试:测量CPU和墙时间
- 高CPU使用率,在API桌面复制中获取帧之间具有不同的超时间隔
- 超过CPU时间限制:当MPI_Sent一个非常大的int*时
- Tensorflow如何默认使用CPU核心