我正在尝试用实时截止期来提高线程应用程序的性能。它运行在Windows Mobile上,用C/ C++编写。我怀疑频繁的线程切换可能会导致明显的开销,但既不能证明这一点,也不能证明这一点。众所周知,缺乏证据并不是相反的证明:)。
因此,我的问题是双重的:
发布于 2008-11-20 09:37:23
虽然您说您不想编写测试应用程序,但我在ARM9 Linux平台上的前一个测试中这样做是为了找出开销是什么。这只是两个线程,它将boost::thread::yield() (或者,你知道的)和一些变量递增,大约一分钟后(没有其他正在运行的进程,至少没有进程做一些事情),应用程序打印出它每秒可以执行多少次上下文切换。当然,这并不是很准确,但重点是两个线程都将CPU分配给对方,而且速度如此之快,以至于考虑开销已经没有任何意义了。所以,简单地去写一个简单的测试,而不是过多地考虑一个可能不存在的问题。
除此之外,您可以尝试使用性能计数器建议的1800。
哦,我还记得在Windows CE 4.X上运行的一个应用程序,在那里我们也有四个线程,有时会有密集的切换,并且从来没有遇到过性能问题。我们还尝试在完全不使用线程的情况下实现核心线程,但没有看到任何性能改进( GUI只是响应速度慢了很多,但其他一切都是一样的)。也许您可以尝试相同的方法,通过减少上下文切换的数量或完全删除线程(仅用于测试)。
发布于 2008-11-20 10:46:15
我怀疑你在任何现有的平台上都能在网络上找到这样的开销。存在太多不同的平台。开销取决于两个因素:
上执行不同的操作。
其他因素包括如何进行切换。在以下情况下,可以发生切换
:线程不再需要CPU时间,因为它正在阻塞某些操作或只是调用priority.
这3个场景在理论上可能有不同的线程切换时间。例如,我认为最后一个是最慢的,因为调用sleep()意味着CPU被返回给内核,内核需要设置一个唤醒调用,以确保线程在请求休眠的时间后被唤醒,然后它必须将线程从调度进程中删除,一旦线程被唤醒,它必须将线程再次添加到调度进程中。所有这些浸泡都需要一些时间。因此,实际的休眠调用可能比切换到另一个线程所需的时间更长。
我认为如果你想确定,你必须进行基准测试。问题在于,您通常必须将线程置于睡眠状态,或者必须使用互斥来同步它们。休眠或锁定/解锁互斥锁本身就有开销。这意味着您的基准测试也将包括这些开销。如果没有一个强大的分析器,以后就很难说出实际的切换使用了多少CPU时间,以及有多少CPU时间用于睡眠/互斥调用。另一方面,在现实生活场景中,您的线程也将休眠或通过锁进行同步。纯粹测量上下文切换时间的基准是一个综合基准,因为它不会对任何现实生活场景进行建模。如果基准基于现实生活中的场景,那么它们就更加“现实”。如果我的GPU在理论上每秒可以处理20亿个多边形,如果这个结果永远不能在现实生活中的3D应用程序中实现,那么GPU基准测试有什么用呢?知道现实生活中的3D应用程序可以让GPU处理多少个多边形,这不是更有趣吗?
不幸的是,我对Windows编程一无所知。我可以用Java或者C#为Windows写一个应用程序,但是Windows上的C/C++让我哭了。我只能提供一些POSIX的源代码。
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
uint32_t COUNTER;
pthread_mutex_t LOCK;
pthread_mutex_t START;
pthread_cond_t CONDITION;
void * threads (
void * unused
) {
// Wait till we may fire away
pthread_mutex_lock(&START);
pthread_mutex_unlock(&START);
pthread_mutex_lock(&LOCK);
// If I'm not the first thread, the other thread is already waiting on
// the condition, thus Ihave to wake it up first, otherwise we'll deadlock
if (COUNTER > 0) {
pthread_cond_signal(&CONDITION);
}
for (;;) {
COUNTER++;
pthread_cond_wait(&CONDITION, &LOCK);
// Always wake up the other thread before processing. The other
// thread will not be able to do anything as long as I don't go
// back to sleep first.
pthread_cond_signal(&CONDITION);
}
pthread_mutex_unlock(&LOCK); //To unlock
}
int64_t timeInMS ()
{
struct timeval t;
gettimeofday(&t, NULL);
return (
(int64_t)t.tv_sec * 1000 +
(int64_t)t.tv_usec / 1000
);
}
int main (
int argc,
char ** argv
) {
int64_t start;
pthread_t t1;
pthread_t t2;
int64_t myTime;
pthread_mutex_init(&LOCK, NULL);
pthread_mutex_init(&START, NULL);
pthread_cond_init(&CONDITION, NULL);
pthread_mutex_lock(&START);
COUNTER = 0;
pthread_create(&t1, NULL, threads, NULL);
pthread_create(&t2, NULL, threads, NULL);
pthread_detach(t1);
pthread_detach(t2);
// Get start time and fire away
myTime = timeInMS();
pthread_mutex_unlock(&START);
// Wait for about a second
sleep(1);
// Stop both threads
pthread_mutex_lock(&LOCK);
// Find out how much time has really passed. sleep won't guarantee me that
// I sleep exactly one second, I might sleep longer since even after being
// woken up, it can take some time before I gain back CPU time. Further
// some more time might have passed before I obtained the lock!
myTime = timeInMS() - myTime;
// Correct the number of thread switches accordingly
COUNTER = (uint32_t)(((uint64_t)COUNTER * 1000) / myTime);
printf("Number of thread switches in about one second was %u\n", COUNTER);
return 0;
}
输出
Number of thread switches in about one second was 108406
超过100,000并不是太糟糕,即使我们有锁定和条件等待。我猜想,如果没有这些东西,一秒钟内至少可能有两倍的线程切换。
发布于 2008-11-20 14:07:08
你不能估计它。你需要测量它。它将根据设备中的处理器而变化。
有两种相当简单的方法来测量上下文切换。一个涉及代码,另一个则不涉及。
首先,代码方式(伪代码):
DWORD tick;
main()
{
HANDLE hThread = CreateThread(..., ThreadProc, CREATE_SUSPENDED, ...);
tick = QueryPerformanceCounter();
CeSetThreadPriority(hThread, 10); // real high
ResumeThread(hThread);
Sleep(10);
}
ThreadProc()
{
tick = QueryPerformanceCounter() - tick;
RETAILMSG(TRUE, (_T("ET: %i\r\n"), tick));
}
显然,在循环中做,平均会更好。请记住,这不仅仅是测量上下文切换。您还测量了对ResumeThread的调用,并且不能保证调度程序会立即切换到您的另一个线程(尽管优先级10应该有助于增加切换到其他线程的可能性)。
您可以通过连接到调度器事件来使用CeLog获得更准确的度量,但这远不是一件简单的事情,而且文档也不是很好。如果你真的想走这条路,Sue Loh在上面有几个博客,搜索引擎可以找到。
非代码路线是使用远程内核跟踪器。安装eVC 4.0或平台构建器的评估版本以获取它。它将以图形方式显示内核正在执行的所有操作,您可以使用提供的光标功能直接测量线程上下文切换。同样,我相信Sue也有一篇关于使用Kernel Tracker的博客文章。
综上所述,您会发现CE进程内线程上下文切换非常非常快。进程切换是代价高昂的,因为它需要交换RAM中的活动进程,然后进行迁移。
https://stackoverflow.com/questions/304752
复制相似问题