【发布时间】:2014-07-18 06:50:47
【问题描述】:
为了在 C++ 中进行特征分解,我使用例程“zhpev”。该例程嵌入在一个较大软件的 dll 文件中,并在运行时被彻底使用。在大约 5000 次“zhpev”调用之后,我测量了运行时间。前 900 次运行时评估一切正常。运行时间约为 0.7 秒,变化不大。然而,900 次运行时间评估,运行时间突然从 0.7 秒增加到 2.7 秒,变化很大。
我做了以下观察:
- 运行时问题与“zhpev”的输入数据无关。
- 例程“zhpev”在一个小程序中运行良好且稳定。似乎是与其他部分的交互造成了麻烦。
- 将“zhpev”替换为另一个特征分解例程后,一切运行顺利,运行时间几乎没有变化。
- 无论是否使用多线程,都会出现运行时问题。
- 我不使用动态内存分配。所有变量都分配为静态变量。
- 问题与Visual C++ function suddenly 170 ms slower (4x longer) 类似,但是,我无法在我的代码中检测到任何内存泄漏。
抱歉,由于我正在处理的项目太大,我无法发布任何代码。
如果有任何提示可以帮助我停止这种奇怪的行为,我将不胜感激!
编辑 例程“zhpev”适用于双精度大小为 32x32 的复杂 Hermitian 矩阵。因此,一次处理的数据块相当小。
更新 1)分页不是这里的问题。我在系统选项中禁用了页面文件。运行时间问题仍未解决。 2) 在不同的 Windows 计算机上运行应用程序也会导致相同的运行时间问题。但是,现在运行时间增加的开始发生在 1400 次运行时间评估之后。
更新 我发现只有在线程内调用“zhpev”时才会出现运行时问题。有了这个,我可以创建一个小代码示例,我会遇到同样的问题。
让我解释一下我的代码
- 我使用了http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx的多线程示例
- 在线程函数中,我插入了包含“zhpev”的函数“eigendecomposition”
- 我还包括了测量运行时间的函数。
这是我的代码
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include "stdafx.h"
#include "mkl_lapack.h"
#include "mkl_service.h"
#include <time.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <iostream>
using namespace std;
#define CACHE_LINE 32
#define CACHE_ALIGN __declspec(align(CACHE_LINE))
#define MAX_THREADS 2
#define BUF_SIZE 255
DWORD WINAPI MyThreadFunction( LPVOID lpParam );
void ErrorHandler(LPTSTR lpszFunction);
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// This is the critical function.
void Eigendecomposition();
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
typedef struct MyData {
int val1;
int val2;
} MYDATA, *PMYDATA;
int _tmain()
{
PMYDATA pDataArray[MAX_THREADS];
DWORD dwThreadIdArray[MAX_THREADS];
HANDLE hThreadArray[MAX_THREADS];
std::ofstream ofs;
double tstart;
double tend;
double proc_time_pure;
for(int j=0;j<10000;j++){
// Start one iteration
tstart = clock();
// Create MAX_THREADS worker threads.
for( int i=0; i<MAX_THREADS; i++ )
{
pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(MYDATA));
if( pDataArray[i] == NULL )
{
ExitProcess(2);
}
pDataArray[i]->val1 = i;
pDataArray[i]->val2 = i+100;
// Create the thread to begin execution on its own.
hThreadArray[i] = CreateThread(
NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
pDataArray[i], // argument to thread function
0, // use default creation flags
&dwThreadIdArray[i]); // returns the thread identifier
if (hThreadArray[i] == NULL)
{
ErrorHandler(TEXT("CreateThread"));
ExitProcess(3);
}
} // End of main thread creation loop.
// Wait until all threads have terminated.
WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
for(int i=0; i<MAX_THREADS; i++)
{
CloseHandle(hThreadArray[i]);
if(pDataArray[i] != NULL)
{
HeapFree(GetProcessHeap(), 0, pDataArray[i]);
pDataArray[i] = NULL; // Ensure address is not reused.
}
}
tend = clock();
proc_time_pure = tend-tstart;
// Print processing time into console and write it into a file
printf(" Processing time: %4.3f \n", proc_time_pure/1000.0);
ofs.open ("Processing_time.txt", std::ofstream::out | std::ofstream::app);
ofs << proc_time_pure/1000.0 << " ";
ofs.close();
}
return 0;
}
DWORD WINAPI MyThreadFunction( LPVOID lpParam )
{
HANDLE hStdout;
PMYDATA pDataArray;
TCHAR msgBuf[BUF_SIZE];
size_t cchStringSize;
DWORD dwChars;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if( hStdout == INVALID_HANDLE_VALUE )
return 1;
pDataArray = (PMYDATA)lpParam;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Critical function
Eigendecomposition();
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
return 0;
}
void ErrorHandler(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code.
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message.
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK);
// Free error-handling buffer allocations.
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
void Eigendecomposition(){
const int M = 32;
typedef MKL_Complex16 double_complex;
const char jobz = 'V';
const char uplo = 'L'; // lower triangular part of input matrix is used
const MKL_INT dim = M;
const MKL_INT ldz = M;
const MKL_INT LWORK = (2*M-1);
const MKL_INT LRWORK = (3*M-2);
MKL_INT info = 0;
double_complex A_H_MKL[(M*M+M)/2];
CACHE_ALIGN double_complex work[LWORK];
CACHE_ALIGN double rwork[LRWORK];
double D[M];
double_complex U[M][M];
for(int i=0;i<500;i++ ){
// Create the input matrix
for (int tmp=0; tmp < (M*M+M)/2; tmp++){
A_H_MKL[tmp].real = 1 ;
A_H_MKL[tmp].imag = 0;}
// This is the mkl function
zhpev(&jobz, // const char* jobz,
&uplo, // const char* uplo,
&dim, // const MKL_INT* n,
(double_complex *)&A_H_MKL[0], // double_complex* ap,
(double *)&D[0], // double* w,
(double_complex *)&U[0][0], // double_complex* z,
&ldz, // const MKL_INT* ldz,
work, // double_complex* work,
rwork, // double* rwork,
&info); // MKL_INT* info
}
}
【问题讨论】:
-
资源泄漏(内存或其他)不一定在您的代码中,它实际上可能是库中的错误。
-
谢谢,约阿希姆。但是,在没有任何大型环境的小测试函数中运行例程“zhpev”不会导致运行时间增加。因此,我认为问题的根源是“zhpev”和我的代码的一些问题的结合。
-
那你有没有想过这个函数可能需要对某些参数集和/或数据进行更多的计算?或者您可能在较慢的呼叫中有更多数据?还是您每次都使用完全相同的参数和相同的数据大小调用函数?
-
输入数据不是这里的问题。使用相同的输入调用函数会导致与不同的输入数据相同的行为。
-
这是相当大的内存占用。碎片化怎么办? zphev 可能会尝试一次分配大量数据。如果没有连续的可用内存空间块,内存管理器可能会意外地提前打开分页...
标签: c++ visual-studio intel-mkl