编写一个C程序来测量Linux操作系统中上下文切换所花费的时间
我们可以写一个c程序来找出在Linux环境下进行上下文切换所花费的时间吗?如果你有密码的话,你能分享一下吗?编写一个C程序来测量Linux操作系统中上下文切换所花费的时间,c,linux,context-switch,C,Linux,Context Switch,我们可以写一个c程序来找出在Linux环境下进行上下文切换所花费的时间吗?如果你有密码的话,你能分享一下吗? 谢谢分析切换时间非常困难,但是内核内延迟分析工具以及oprofile(可以分析内核本身)将在这方面帮助您 为了对交互式应用程序性能进行基准测试,我编写了一个名为latencybench的小工具,用于测量意外的延迟峰值: // Compile with g++ latencybench.cc -o latencybench -lboost_thread-mt // Should also
谢谢分析切换时间非常困难,但是内核内延迟分析工具以及oprofile(可以分析内核本身)将在这方面帮助您 为了对交互式应用程序性能进行基准测试,我编写了一个名为latencybench的小工具,用于测量意外的延迟峰值:
// Compile with g++ latencybench.cc -o latencybench -lboost_thread-mt
// Should also work on MSVC and other platforms supported by Boost.
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/date_time.hpp>
#include <algorithm>
#include <cstdlib>
#include <csignal>
volatile bool m_quit = false;
extern "C" void sighandler(int) {
m_quit = true;
}
std::string num(unsigned val) {
if (val == 1) return "one occurrence";
return boost::lexical_cast<std::string>(val) + " occurrences";
}
int main(int argc, char** argv) {
using namespace boost::posix_time;
std::signal(SIGINT, sighandler);
std::signal(SIGTERM, sighandler);
time_duration duration = milliseconds(10);
if (argc > 1) {
try {
if (argc != 2) throw 1;
unsigned ms = boost::lexical_cast<unsigned>(argv[1]);
if (ms > 1000) throw 2;
duration = milliseconds(ms);
} catch (...) {
std::cerr << "Usage: " << argv[0] << " milliseconds" << std::endl;
return EXIT_FAILURE;
}
}
typedef std::map<long, unsigned> Durations;
Durations durations;
unsigned samples = 0, wrongsamples = 0;
unsigned max = 0;
long last = -1;
std::cout << "Measuring actual sleep delays when requesting " << duration.total_milliseconds() << " ms: (Ctrl+C when done)" << std::endl;
ptime begin = boost::get_system_time();
while (!m_quit) {
ptime start = boost::get_system_time();
boost::this_thread::sleep(start + duration);
long actual = (boost::get_system_time() - start).total_milliseconds();
++samples;
unsigned num = ++durations[actual];
if (actual != last) {
std::cout << "\r " << actual << " ms " << std::flush;
last = actual;
}
if (actual != duration.total_milliseconds()) {
++wrongsamples;
if (num > max) max = num;
std::cout << "spike at " << start - begin << std::endl;
last = -1;
}
}
if (samples == 0) return 0;
std::cout << "\rTotal measurement duration: " << boost::get_system_time() - begin << "\n";
std::cout << "Number of samples collected: " << samples << "\n";
std::cout << "Incorrect delay count: " << wrongsamples << boost::format(" (%.2f %%)") % (100.0 * wrongsamples / samples) << "\n\n";
std::cout << "Histogram of actual delays:\n\n";
unsigned correctsamples = samples - wrongsamples;
const unsigned line = 60;
double scale = 1.0;
char ch = '+';
if (max > line) {
scale = double(line) / max;
ch = '*';
}
double correctscale = 1.0;
if (correctsamples > line) correctscale = double(line) / correctsamples;
for (Durations::const_iterator it = durations.begin(); it != durations.end(); ++it) {
std::string bar;
if (it->first == duration.total_milliseconds()) bar = std::string(correctscale * it->second, '>');
else bar = std::string(scale * it->second, ch);
std::cout << boost::format("%5d ms | %s %d") % it->first % bar % it->second << std::endl;
}
std::cout << "\n";
std::string indent(30, ' ');
std::cout << indent << "+-- Legend ----------------------------------\n";
std::cout << indent << "| > " << num(1.0 / correctscale) << " (of " << duration.total_milliseconds() << " ms delay)\n";
if (wrongsamples > 0) std::cout << indent << "| " << ch << " " << num(1.0 / scale) << " (of any other delay)\n";
}
使用rt补丁内核,我得到了更好的结果,几乎只有10-12毫秒
打印输出中的图例似乎存在舍入错误或其他问题(粘贴的源代码与版本不完全相同)。我从来没有真正完善过这个应用程序来发布…简短的回答-不。下面是详细的回答 上下文切换大致发生在以下情况之一:
切换本身是单向的,所以我们在userland中所能做的最好的事情(我想这就是你要问的)就是测量某种RTT,从我们的流程到另一个流程再到另一个流程。另一个过程也需要时间来完成它的工作。我们当然可以让两个或多个进程在这方面进行协作,但问题是内核不能保证下一个进程将被选中。使用RT scheduler可以预测地切换到给定的进程,但我这里没有建议,欢迎您提出建议。如果您具有超级用户权限,您可以运行带有上下文切换探测点的SystemTap程序,并打印每个进程的当前时间:
probe scheduler.ctxswitch {
printf("Switch from %d to %d at %d\n", prev_pid, next_pid, gettimeofday_us())
}
我不确定输出数据有多可靠,但这是一种快速简便的获取数字的方法。为什么不将此作为粗略估计
#include <ctime>
#include <cstdio>
#include <sys/time.h>
#include <unistd.h>
int main(int argc, char **argv) {
struct timeval tv, tvt;
int diff;
gettimeofday(&tv, 0);
diff = tvt.tv_usec - tv.tv_usec;
if (fork() != 0) {
gettimeofday(&tvt, 0);
diff = tvt.tv_usec - tv.tv_usec;
printf("%d\n", diff);
}
return 0;
}
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
结构timeval tv,tvt;
int-diff;
gettimeofday(&tv,0);
diff=tvt.tv_usec-tv.tv_usec;
如果(fork()!=0){
gettimeofday(&tvt,0);
diff=tvt.tv_usec-tv.tv_usec;
printf(“%d\n”,差异);
}
返回0;
}
注意:实际上我们不应该把null作为第二个参数,检查mangettimeofday。此外,我们还应该检查tvt.tv\u usec>tv.tv\u usec!只是一个草稿。你怎么看,用秒、毫秒甚至微秒来衡量上下文切换。所有这些都发生在纳秒以内。如果你想花那么多的时间在可以测量的上下文切换上,那么。。。
尝试一些在汇编上编写的实模式内核类型代码,您可能会看到一些东西。衡量上下文切换的成本有点棘手。我们可以通过在一个CPU上运行两个进程并在它们之间设置三个Linux管道来计算上下文切换所花费的时间
- 两个管道,用于在进程和
- 第三个将用于共享在子进程上花费的时间李>
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <stdlib.h>
#include <string.h>
#include <linux/unistd.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
pid_t getpid( void )
{
return syscall( __NR_getpid );
}
int main()
{
/*********************************************************************************************
To make sure context-switching processes are located on the same processor :
1. Bind a process to a particular processor using sched_setaffinity.
2. To get the maximum priority value (sched_get_priority_max) that can be used with
the scheduling algorithm identified by policy (SCHED_FIFO).**
**********************************************************************************************/
cpu_set_t set;
struct sched_param prio_param;
int prio_max;
CPU_ZERO( &set );
CPU_SET( 0, &set );
memset(&prio_param,0,sizeof(struct sched_param));
if (sched_setaffinity( getpid(), sizeof( cpu_set_t ), &set ))
{
perror( "sched_setaffinity" );
exit(EXIT_FAILURE);
}
if( (prio_max = sched_get_priority_max(SCHED_FIFO)) < 0 )
{
perror("sched_get_priority_max");
}
prio_param.sched_priority = prio_max;
if( sched_setscheduler(getpid(),SCHED_FIFO,&prio_param) < 0 )
{
perror("sched_setscheduler");
exit(EXIT_FAILURE);
}
/*****************************************************************************************************
1. To create a pipe for a fork, the parent and child processes use pipe to read and write,
read and write string, using this for context switch.
2. The parent process first to get the current timestamp (gettimeofday), then write to the pipe,.
Then the child should be read in from the back,
then the child process to write string, the parent process reads.
After the child process to get the current timestamp.
This is roughly the difference between two timestamps n * 2 times the context switch time.
*******************************************************************************************************/
int ret=-1;
int firstpipe[2];
int secondpipe[2];
int timepipe[2];
int nbytes;
char string[] = "Hello, world!\n";
char temp[] = "Sumit Gemini!\n";
char readbuffer[80];
char tempbuffer[80];
int i=0;
struct timeval start,end;
// Create an unnamed first pipe
if (pipe(firstpipe) == -1)
{
fprintf(stderr, "parent: Failed to create pipe\n");
return -1;
}
// create an unnamed Second pipe
if (pipe(secondpipe) == -1)
{
fprintf(stderr, "parent: Failed to create second pipe\n");
return -1;
}
// Create an unnamed time pipe which will share in order to show time spend between processes
if (pipe(timepipe) == -1)
{
fprintf(stderr, "parent: Failed to create time pipe\n");
return -1;
}
if((ret=fork())==-1)
perror("fork");
else if(ret==0)
{
int n=-1;
printf("Child ----> %d\n",getpid());
for(n=0;n<5;n++)
{
nbytes = read(firstpipe[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
write(secondpipe[1], temp, strlen(temp)+1);
}
gettimeofday(&end,0);
n = sizeof(struct timeval);
if( write(timepipe[1],&end,sizeof(struct timeval)) != n )
{
fprintf(stderr, "child: Failed to write in time pipe\n");
exit(EXIT_FAILURE);
}
}
else
{
double switch_time;
int n=-1;
printf("Parent ----> %d\n",getpid());
gettimeofday(&start,0);
/* Read in a string from the pipe */
for(n=0;n<5;n++)
{
write(firstpipe[1], string, strlen(string)+1);
read(secondpipe[0], tempbuffer, sizeof(tempbuffer));
printf("Received temp: %s", tempbuffer);
}
n = sizeof(struct timeval);
if( read(timepipe[0],&end,sizeof(struct timeval)) != n )
{
fprintf(stderr, "Parent: Failed to read from time pipe\n");
exit(EXIT_FAILURE);
}
wait(NULL);
switch_time = ((end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec))/1000.0;
printf("context switch between two processes: %0.6lfms\n",switch_time/(5*2));
}
return 0;
}
定义GNU源
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
pid\u t getpid(无效)
{
返回系统调用(\uuuunr\ugetpid);
}
int main()
{
/*********************************************************************************************
要确保上下文切换进程位于同一处理器上,请执行以下操作:
1.使用sched_setaffinity将进程绑定到特定处理器。
2.获取可与一起使用的最大优先级值(sched_get_priority_max)
由策略标识的调度算法(SCHED_FIFO)。**
**********************************************************************************************/
cpu_set_t set;
结构sched_param prio_param;
int prio_max;
CPU_零(&set);
CPU_集(0,&集);
memset(&prio_param,0,sizeof(struct sched_param));
if(sched_setaffinity(getpid(),sizeof(cpu_set_t),&set))
{
perror(“sched_setaffinity”);
退出(退出失败);
}
如果((prio_max=sched_get_priority_max(sched_FIFO))<0)
{
perror(“sched_get_priority_max”);
}
prio_param.sched_priority=prio_max;
如果(调度)设置调度程序(ge
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <stdlib.h>
#include <string.h>
#include <linux/unistd.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
pid_t getpid( void )
{
return syscall( __NR_getpid );
}
int main()
{
/*********************************************************************************************
To make sure context-switching processes are located on the same processor :
1. Bind a process to a particular processor using sched_setaffinity.
2. To get the maximum priority value (sched_get_priority_max) that can be used with
the scheduling algorithm identified by policy (SCHED_FIFO).**
**********************************************************************************************/
cpu_set_t set;
struct sched_param prio_param;
int prio_max;
CPU_ZERO( &set );
CPU_SET( 0, &set );
memset(&prio_param,0,sizeof(struct sched_param));
if (sched_setaffinity( getpid(), sizeof( cpu_set_t ), &set ))
{
perror( "sched_setaffinity" );
exit(EXIT_FAILURE);
}
if( (prio_max = sched_get_priority_max(SCHED_FIFO)) < 0 )
{
perror("sched_get_priority_max");
}
prio_param.sched_priority = prio_max;
if( sched_setscheduler(getpid(),SCHED_FIFO,&prio_param) < 0 )
{
perror("sched_setscheduler");
exit(EXIT_FAILURE);
}
/*****************************************************************************************************
1. To create a pipe for a fork, the parent and child processes use pipe to read and write,
read and write string, using this for context switch.
2. The parent process first to get the current timestamp (gettimeofday), then write to the pipe,.
Then the child should be read in from the back,
then the child process to write string, the parent process reads.
After the child process to get the current timestamp.
This is roughly the difference between two timestamps n * 2 times the context switch time.
*******************************************************************************************************/
int ret=-1;
int firstpipe[2];
int secondpipe[2];
int timepipe[2];
int nbytes;
char string[] = "Hello, world!\n";
char temp[] = "Sumit Gemini!\n";
char readbuffer[80];
char tempbuffer[80];
int i=0;
struct timeval start,end;
// Create an unnamed first pipe
if (pipe(firstpipe) == -1)
{
fprintf(stderr, "parent: Failed to create pipe\n");
return -1;
}
// create an unnamed Second pipe
if (pipe(secondpipe) == -1)
{
fprintf(stderr, "parent: Failed to create second pipe\n");
return -1;
}
// Create an unnamed time pipe which will share in order to show time spend between processes
if (pipe(timepipe) == -1)
{
fprintf(stderr, "parent: Failed to create time pipe\n");
return -1;
}
if((ret=fork())==-1)
perror("fork");
else if(ret==0)
{
int n=-1;
printf("Child ----> %d\n",getpid());
for(n=0;n<5;n++)
{
nbytes = read(firstpipe[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
write(secondpipe[1], temp, strlen(temp)+1);
}
gettimeofday(&end,0);
n = sizeof(struct timeval);
if( write(timepipe[1],&end,sizeof(struct timeval)) != n )
{
fprintf(stderr, "child: Failed to write in time pipe\n");
exit(EXIT_FAILURE);
}
}
else
{
double switch_time;
int n=-1;
printf("Parent ----> %d\n",getpid());
gettimeofday(&start,0);
/* Read in a string from the pipe */
for(n=0;n<5;n++)
{
write(firstpipe[1], string, strlen(string)+1);
read(secondpipe[0], tempbuffer, sizeof(tempbuffer));
printf("Received temp: %s", tempbuffer);
}
n = sizeof(struct timeval);
if( read(timepipe[0],&end,sizeof(struct timeval)) != n )
{
fprintf(stderr, "Parent: Failed to read from time pipe\n");
exit(EXIT_FAILURE);
}
wait(NULL);
switch_time = ((end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec))/1000.0;
printf("context switch between two processes: %0.6lfms\n",switch_time/(5*2));
}
return 0;
}