多緒在Core2Duo上面效能降低問題

ganuse 2008-09-10 11:10:17
最近我寫一個單緒的 MEMCPY 卻發現他比在2個thread還快多
不知道為何
我程式如下


///////
*.cpp
///////
BOOL CMemcopy_TestDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here
m_bStop[0] = TRUE;
m_bStop[1] = TRUE;

return TRUE; // return TRUE unless you set the focus to a control
}

#include <afxmt.h>
#define WIDTH 720
#define HEIGHT 480
CCriticalSection g_CriticalSection[2];

DWORD CMemcopy_TestDlg::Video1Thread(LPVOID pv)
{
CMemcopy_TestDlg *pThis = (CMemcopy_TestDlg*)pv;
BYTE *ptsrc, *ptdst;
BYTE *bufin = new BYTE[ WIDTH*HEIGHT*3 ];
BYTE *bufout = new BYTE[ WIDTH*HEIGHT*3 ];

LARGE_INTEGER m_liPerfFreq, m_liPerfStart, liPerfNow;
QueryPerformanceFrequency(&m_liPerfFreq);
QueryPerformanceCounter(&m_liPerfStart);
DWORD nframe = 0;
char strMesg[256];

while( 1 )
{
ptsrc = bufin;
ptdst = bufout;

for( int j = 0; j < HEIGHT; j++ )
{
memcpy( ptdst, ptsrc, WIDTH*3 );
ptsrc += WIDTH*2;
ptdst += WIDTH*2;
}

nframe++;
if( nframe == 1000 )
{
QueryPerformanceCounter(&liPerfNow);
LONGLONG time = ( ((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000)/m_liPerfFreq.QuadPart);
sprintf( strMesg, "每秒 %d 次\n", (1000*1000)/time );
::OutputDebugString( strMesg );
QueryPerformanceCounter(&m_liPerfStart);
nframe = 0;
}

g_CriticalSection[ 0 ].Lock();
if( pThis->m_bStop[ 0 ] == TRUE )
{
g_CriticalSection[ 0 ].Unlock();
break;
}
g_CriticalSection[ 0 ].Unlock();
}

delete[] bufin;
delete[] bufout;
return 0;
}

DWORD CMemcopy_TestDlg::Video2Thread(LPVOID pv)
{
CMemcopy_TestDlg *pThis = (CMemcopy_TestDlg*)pv;
BYTE *ptsrc, *ptdst;
BYTE *bufin = new BYTE[ WIDTH*HEIGHT*3 ];
BYTE *bufout = new BYTE[ WIDTH*HEIGHT*3 ];

LARGE_INTEGER m_liPerfFreq, m_liPerfStart, liPerfNow;
QueryPerformanceFrequency(&m_liPerfFreq);
QueryPerformanceCounter(&m_liPerfStart);
DWORD nframe = 0;
char strMesg[256];

while( 1 )
{
ptsrc = bufin;
ptdst = bufout;

for( int j = 0; j < HEIGHT; j++ )
{
memcpy( ptdst, ptsrc, WIDTH*3 );
ptsrc += WIDTH*2;
ptdst += WIDTH*2;
}

nframe++;
if( nframe == 1000 )
{
QueryPerformanceCounter(&liPerfNow);
LONGLONG time = ( ((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000)/m_liPerfFreq.QuadPart);
sprintf( strMesg, "每秒 %d 次\n", (1000*1000)/time );
::OutputDebugString( strMesg );
QueryPerformanceCounter(&m_liPerfStart);
nframe = 0;
}

g_CriticalSection[ 1 ].Lock();
if( pThis->m_bStop[ 1 ] == TRUE )
{
g_CriticalSection[ 1 ].Unlock();
break;
}
g_CriticalSection[ 1 ].Unlock();
}

delete[] bufin;
delete[] bufout;
return 0;
}

void CMemcopy_TestDlg::OnOK()
{
if( m_bStop[0] == FALSE && m_bStop[1] == FALSE ) {
return;
}
m_bStop[ 0 ] = FALSE;
m_bStop[ 1 ] = FALSE;

DWORD nVideo1ThreadId;
DWORD nVideo2ThreadId;
HANDLE HndVideo1;
HANDLE HndVideo2;

HndVideo1 = CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)InitialVideo1Thread,
this,
0,
&nVideo1ThreadId );

if( HndVideo1 == INVALID_HANDLE_VALUE )
{
AfxMessageBox("Create WriteThread failure!");
}


HndVideo2 = CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)InitialVideo2Thread,
this,
0,
&nVideo2ThreadId );

if( HndVideo2 == INVALID_HANDLE_VALUE )
{
AfxMessageBox("Create WriteThread failure!");
}
}

void CMemcopy_TestDlg::OnCancel()
{
if( m_bStop[0]== FALSE && m_bStop[1]== FALSE ) {
return;
}

CDialog::OnCancel();
}

void CMemcopy_TestDlg::OnStop()
{
g_CriticalSection[ 0 ].Lock();
m_bStop[ 0 ] = TRUE;
g_CriticalSection[ 0 ].Unlock();

g_CriticalSection[ 1 ].Lock();
m_bStop[ 1 ] = TRUE;
g_CriticalSection[ 1 ].Unlock();
}

//////
*h
//////

class CMemcopy_TestDlg : public CDialog
{
// Construction
public:
CMemcopy_TestDlg(CWnd* pParent = NULL); // standard constructor

BOOL m_bStop[2];

DWORD Video1Thread(LPVOID pv);
static DWORD InitialVideo1Thread(LPVOID pv)
{
CMemcopy_TestDlg *pThis = (CMemcopy_TestDlg*)pv;
return pThis->Video1Thread(pThis);
}

DWORD Video2Thread(LPVOID pv);
static DWORD InitialVideo2Thread(LPVOID pv)
{
CMemcopy_TestDlg *pThis = (CMemcopy_TestDlg*)pv;
return pThis->Video2Thread(pThis);
}

// Dialog Data
//{{AFX_DATA(CMemcopy_TestDlg)
enum { IDD = IDD_MEMCOPY_TEST_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA

// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMemcopy_TestDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL

// Implementation
protected:
HICON m_hIcon;

// Generated message map functions
//{{AFX_MSG(CMemcopy_TestDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
virtual void OnOK();
virtual void OnCancel();
afx_msg void OnStop();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
...全文
490 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
tanfenghua518 2008-10-14
  • 打赏
  • 举报
回复
通用CPU只能解决大部分问题,可以看出为什么GOOGLE要定制自己的硬件,还有IBM要专门推出处理XML的DATAPOWER。
intel_www 2008-10-08
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 lanzhengpeng2 的回复:]
intel_www:
你机器多还不错?在Intel高干?
[/Quote]

呵呵,我的机器不仅多,而且还花样品种齐全呀。:)
intel_www 2008-10-08
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 lanzhengpeng2 的回复:]
哈哈,正好解决了我一个疑惑。
我的计算是一个射线对一个模型进行逐三角面求交问题,在老的AMD的双核机器上,多线程又性能提升,而在E6300上却有所下降,看来也是同样原因了。
不过,射线与三角形求交怎么也该是个运算密集性的吧,难道core系列这么快?快得能把内存甩开一大节?好歹我内存也是DDR875(超频使用),E6300被超到2.45GHz(原始1.8GHz,我是不是贪心了点?)
[/Quote]

这个倒是很难说是不是同样的原因,你最好试着用VTune看一下大概是个什么原因。

CPU的速度要比内存快很多很多,即使内存超频也是这样的。

lanzhengpeng2 2008-10-08
  • 打赏
  • 举报
回复
intel_www:
你机器多还不错?在Intel高干?
lanzhengpeng2 2008-10-08
  • 打赏
  • 举报
回复
哈哈,正好解决了我一个疑惑。
我的计算是一个射线对一个模型进行逐三角面求交问题,在老的AMD的双核机器上,多线程又性能提升,而在E6300上却有所下降,看来也是同样原因了。
不过,射线与三角形求交怎么也该是个运算密集性的吧,难道core系列这么快?快得能把内存甩开一大节?好歹我内存也是DDR875(超频使用),E6300被超到2.45GHz(原始1.8GHz,我是不是贪心了点?)
majiajun_no_5 2008-09-30
  • 打赏
  • 举报
回复
获益匪浅
milex 2008-09-30
  • 打赏
  • 举报
回复
牛人没我帅 帅的没我牛 呵呵
tomato_potato 2008-09-28
  • 打赏
  • 举报
回复
 留爪时间学习
majiajun_no_6 2008-09-27
  • 打赏
  • 举报
回复
hao
converf 2008-09-25
  • 打赏
  • 举报
回复
很有道理值得学习
lehedele 2008-09-24
  • 打赏
  • 举报
回复
N多高人牛人....此帖让我受益匪浅,值得收藏! 继续关注....
piternb 2008-09-23
  • 打赏
  • 举报
回复
顶哈
zhsj64 2008-09-23
  • 打赏
  • 举报
回复
太好了,顶
wlcy1988 2008-09-22
  • 打赏
  • 举报
回复
顶下
intel_www 2008-09-18
  • 打赏
  • 举报
回复
关于VTune的用可以看顶置的索引贴:http://topic.csdn.net/u/20080407/13/fcf18324-44ea-4a61-9011-a4bc11d48af5.html

还有一点,这个例子如果使用Intel的编译器的话性能又可以提高不少。LZ感兴趣的话可以试试。
intel_www 2008-09-17
  • 打赏
  • 举报
回复
LZ的程序也是一个很典型的例子,它很好的说明了下面几点:

1. CPU的微架构,尤其是L2 Cache的大小会直接影响程序的性能
2. 并不是所有的情况下多线程都可以提高程序的性能,尤其是程序本身是一个数据密集型而不是计算密集型时。这种情况下我们要小心仔细的分析数据访问模式和所使用的CPU微架构之间的关系,选取合理的数据大小和存取方式。
3. Intel VTune是分析微架构相关的性能问题的强有力工具。它可以快速的找到程序性能瓶颈所在。
intel_www 2008-09-17
  • 打赏
  • 举报
回复
换了一台机器:4核的QX6700,L2 Cache是8M.这时将HEIGHT再改回480,也就是每个线程仍然占用2MB。最后的测试结果是:

单线程:20000次/S
双线程:20000 * 2次/S
四线程:16949 + 17241 + 16949 + 17543 = 68682次/S

结果进一步印证了上面的结论:L2 Cache,程序数据集大小之间的关系直接影响程序的性能。


intel_www 2008-09-17
  • 打赏
  • 举报
回复
原因是你这个程序本身测试的内容是一个内存密集型的操作:在两块内存区域之间进行数据copy。在单线程模式下你的src和dst空间各占1MB的内存,总共2MB;而在双线程的模式下每个线程都要2MB,总共需要4MB的内存。在我的机器上E6400 Core 2 Duo的2级高速缓存的大小是2MB,正好可以放的下一个线程运行所需的数据,所以的得到的结果是6000多次每秒。而在双线程模式下,两个线程都无法将自己所需的数据完全放入2级缓存,而且会相互竞争2级缓存的空间,导致出现很高的2级缓存不命中的情况出现。这会极大的影响性能,所以最终的结果就是每个线程每秒1200多次。用Intel VTune可以很轻松的发现这一问题,你可看到在拷贝数据的mov指令上出现巨大数目的L2 Cache Miss.

如果你把数据的大小减半,比如把HEIGHT由480改成240。这样不管单线程还是双线程,所有的数据基本上都可以在2级缓存中放下。最后测的结果是:

单线程:22727次/S
双线程:17241次/S.两个线程加起来是34482次/S,比单线程模式快了52%.

intel_www 2008-09-11
  • 打赏
  • 举报
回复
你这段代码中的g_CriticalSection是不需要的。
ganuse 2008-09-11
  • 打赏
  • 举报
回复
IC..
g_CriticalSection只是方便我結束而已,
可是我拿掉 g_CriticalSection 也是一樣1個thread比2個快很多
一個一秒做6000次 , 2個thread時分別做 1200次 , 差太多了
是我 CreateThread 用錯, 還是我 static DWORD InitialVideo1Thread(LPVOID pv) 用錯
麻煩高手解答 , 感激不盡

567

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧