我试图提高实时截止期限下多线程应用程序的性能。它在Windows Mobile上运行,使用C/C++编写。我怀疑频繁的线程切换可能会导致明显的开销,但既不能证明也不能否定。众所周知,缺乏证据并不是相反证据。
因此我的问题有两个方面:
如果存在的话,我该在哪里找到任何关于线程上下文切换成本的实际测量数据?
在不花费时间编写测试应用程序的情况下,如何估算现有应用程序中的线程切换开销?
是否有人知道一种方法可以查找给定线程的上下文切换(开/关)次数?
我试图提高实时截止期限下多线程应用程序的性能。它在Windows Mobile上运行,使用C/C++编写。我怀疑频繁的线程切换可能会导致明显的开销,但既不能证明也不能否定。众所周知,缺乏证据并不是相反证据。
因此我的问题有两个方面:
如果存在的话,我该在哪里找到任何关于线程上下文切换成本的实际测量数据?
在不花费时间编写测试应用程序的情况下,如何估算现有应用程序中的线程切换开销?
是否有人知道一种方法可以查找给定线程的上下文切换(开/关)次数?
很不幸,我对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并不算太糟糕。我猜如果没有这些东西,每秒钟可能会有至少两倍的线程切换。
无法估计它,您需要测量它。而它将根据设备中的处理器而变化。
有两种相当简单的方法来测量上下文切换。其中一种涉及代码,另一种则不需要。
首先是使用代码的方式(伪代码):
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));
}
尽管你说你不想编写一个测试应用程序,但我在之前的ARM9 Linux平台测试中完成了这个任务,以找出额外开销。其中只有两个线程执行boost::thread::yield()(或其他操作)并增加一些变量,经过一分钟左右(没有其他正在运行的进程,至少没有做任何事情的进程),该应用程序打印出每秒可以执行多少次上下文切换。当然,这并不是真正的精确数据,但重点是两个线程彼此让出CPU,而且速度非常快,所以再考虑额外开销就没有意义了。
因此,请简单地编写一个简单的测试,而不要过于思考可能不存在的问题。
除此之外,您还可以像1800建议的那样使用性能计数器。
哦,我记得在运行Windows CE 4.X的应用程序中,我们也有四个线程进行了密集的切换,但从未遇到过性能问题。我们还尝试过完全不使用线程来实现核心线程功能,但没有看到性能改善(GUI响应速度慢了很多,但其他所有内容都是相同的)。也许您可以尝试相同的方法,通过减少上下文切换次数或完全删除线程(仅用于测试)来解决问题。
上下文切换非常昂贵。这不是因为CPU操作本身,而是因为缓存失效。如果您有一个密集的任务正在运行,它会填充CPU缓存,包括指令和数据,还有内存预取、TLB和RAM将优化工作区域的一些方面。
当您更改上下文时,所有这些缓存机制都将被重置,新线程将从“空白”状态开始。
接受的答案是错误的,除非您的线程只是递增计数器。当然,在这种情况下没有涉及缓存刷新。在没有像真实应用程序那样填充缓存的情况下,对上下文切换进行基准测试毫无意义。
我的50行C++代码展示了在Linux系统(QuadCore Q6600)中,上下文切换时间约为0.9微秒(2个线程为0.75微秒,50个线程为0.95微秒)。在此基准测试中,当线程获得时间量子时,它们立即调用yield。
上下文切换是昂贵的,根据经验法则,它会产生30µs的CPU开销。http://blog.tsunanet.net/2010/11/how-long-does-it-take-to-make-context.html
double * a;
...
for (i = 0; i < 1000; i ++)
{
a[i] = a[i] + a[i]
}
我不确定,但是你在Windows Mobile中是否有通常的性能计数器?你可以查看诸如每秒上下文切换之类的内容。虽然我不知道是否有一个特定的测量上下文切换时间的计数器。