Context Switch

A CPU can still only be running one process at a time, but multitasking gets around that by scheduling which tasks will be running at any given time. The act of switching from one task to another is called Context Switching. 
 --CPU 一次只能运行一个进程,在multitasking 下, 当CPU 处理的进行需要从硬盘读取一些数据时,虽然这个时间也是按miliseconds来计算,但是这个时间还是要比CPU 运算的时间长,所以在CPU 的这个等待的时间里,可以将当前处理的task 切换出去,让CPU 去处理其他的task。 这个过程就叫作Context switch。

测试Context Switch time(进程上下文切换时间)

--------------------------------------------------
    创建两个进程(实时进程)并在它们之间传送一个令牌,如此往返传送一定的次数。其中一个进程在读取令牌时就会引起阻塞。另一个进程发送令牌后等待其返回时也处于阻塞状态。发送令牌带来的开销与上下文切换带来的开销相比,可以忽略不计。 (利用管道传递令牌)


测试程序(1) 使用gettimeofday()获取当前时间
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <sched.h>
#include <sys/types.h>
#include <unistd.h>      //pipe()

int main()
{
    int x, i,  fd[2], p[2] ;
    char send    = 's';
    char receive;
     pipe(fd);
     pipe(p);
    struct timeval tv;
    struct sched_param param;
    param.sched_priority = 0;

    while ((x = fork()) == -1);
    if (x==0) {
        sched_setscheduler(getpid(), SCHED_FIFO, &param);
        gettimeofday(&tv, NULL);//
        printf("Before Context Switch Time %u us\n", tv.tv_usec);
        for (i = 0; i < 10000; i++) {
             read(fd[0], &receive, 1);
             write(p[1], &send, 1);
        }
        exit(0);
    }
    else {
        sched_setscheduler(getpid(), SCHED_FIFO, &param);
        for (i = 0; i < 10000; i++) {
             write(fd[1], &send, 1);
             read(p[0], &receive, 1);
        }
        gettimeofday(&tv, NULL);
        printf("After Context SWitch Time %u us\n", tv.tv_usec);
    }
    return 0;
}


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

注释:

使用C语言编写程序需要获得当前精确时间(UNIX到现在的时间),或者为执行计时,可以使用gettimeofday()函数。
#include <sys/time.h>
int gettimeofday(struct timeval*tv, struct timezone *tz);
其参数tv是保存获取时间结果的结构体,参数tz用于保存时区结果(若不使用则传入NULL即可)。
结构体 timeval的定义为:
struct timeval{
long int tv_sec; // 秒数
long int tv_usec; // 微秒数
}
它获得的时间精确到微秒(1e-6 s)量级。在一段代码前后分别使用gettimeofday可以计算代码执行时间
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

测试结果(进程切换时间不超过5us)
--------------------------------------------------
Before Context Switch Time 617087 us
After Context SWitch Time 702420 us

702420us - 617087us = 85333 us
85333us / 20000    = 4.26665 us

进程切换时间为 4.26665  us

注: cpu MHz         : 2801.042






测试程序(2) 使用rdtsc()获取当前时间
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <sys/types.h>
#include <unistd.h>

long long rdtsc()
{
    __asm("rdtsc");
}

int main()
{
    int x, i, fd[2], p[2];
    char send    = 's';
    char receive;
    pipe(fd);
    pipe(p);
    struct sched_param param;
    param.sched_priority = 0;

    while ((x = fork()) == -1);
    if (x==0) {
        sched_setscheduler(getpid(), SCHED_FIFO, &param);
        printf("Before Context Switch Time %lld\n", rdtsc());
        for (i = 0; i < 10000; i++) {
            read(fd[0], &receive, 1);
            write(p[1], &send, 1);
        }
        exit(0);
    }
    else {
        sched_setscheduler(getpid(), SCHED_FIFO, &param);
        for (i = 0; i < 10000; i++) {
            write(fd[1], &send, 1);
            read(p[0], &receive, 1);
        }
        printf("After Context Switch Time %lld\n", rdtsc());
    }
    return 0;
}


测试结果(进程切换时间不超过5us)
--------------------------------------------------
Before Context Switch Time 16208184381648
After Context Switch Time 16208424333213

16208424333213 - 16208184381648 = 239951565(clock cycle)
239951565      * 0.357009998 ns = 85665107.74074687 ns
85665107.74074687 ns / 20000    = 4283.255387037 ns =  4.28325 5387037 us






注: cpu MHz         : 2801.042
---------------------------------------------
2 801 042 000Hz
clock cycle = 1 000 000 000 ns / 2 801 042 000 = 0.357009998ns

查看CPU性能参数
cat /proc/cpuinfo


测试程序(3) 可直接获得进程上下文切换时间 
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>        //drand48()
#include <sched.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>      //gettimeofday()
#include <time.h>


typedef unsigned long long u64;
double clockCycleTimeS,clockRateHZ;

/* 获取当前时间,返回秒 */
double second() {
    struct timeval tv;
    gettimeofday(&tv,0);
    return tv.tv_sec + 1e-6 * tv.tv_usec;
}

/* 获取当前时间,返回clock cycle */
u64 rdtsc() {
    u64 tsc;
    __asm__ __volatile__("rdtsc" : "=A" (tsc));
    return tsc;
}

/* 睡眠us微秒 */
void selectsleep(unsigned us) {
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = us;
    select(0, 0, 0, 0, &tv);
}

/* 计算当前CPU的工作频率 */
void calibrate() {
    double sumx = 0;
    double sumy = 0;
    double sumxx = 0;
    double sumxy = 0;
    double slope;
    const unsigned n = 30;
    unsigned i;

    for (i=0; i<n; i++) {
        double breal,real,ticks;
        u64 bticks;

        breal = second();
        bticks = rdtsc();
        selectsleep((unsigned)(10000 + drand48() * 200000));
        ticks = rdtsc() - bticks;
        real = second() - breal;

        sumx += real;
        sumxx += real * real;
        sumxy += real * ticks;
        sumy += ticks;
    }
    slope = ( (sumxy - (sumx*sumy) / n) /
              (sumxx - (sumx*sumx) / n) );
    clockRateHZ = slope;
    clockCycleTimeS = 1.0 / slope;
    printf("%3.3f MHz\n", clockRateHZ*1e-6);
}

int main()
{
    calibrate();

    int x, i, p1[2], p2[2], time[2];
    char send    = 's';
    char receive;
    u64 old_time;
    pipe(p1);
    pipe(p2);
    pipe(time);
    struct sched_param param;    
    param.sched_priority = 0;    

     while ((x = fork()) == -1);
    if (x==0)
    {
        sched_setscheduler(getpid(), SCHED_FIFO, &param);
         old_time = rdtsc();
         write(time[1], &old_time, sizeof(old_time));
        for (i = 0; i < 10000; i++) {
            read(p1[0], &receive, 1);
            write(p2[1], &send, 1);
        }
        exit(0);
    }
    else
    {
        u64 new_time;
        sched_setscheduler(getpid(), SCHED_FIFO, &param);
        for (i = 0; i < 10000; i++) {
            write(p1[1], &send, 1);
            read(p2[0], &receive, 1);
        }
         new_time = rdtsc();
         read(time[0], &old_time, sizeof(old_time));
        printf("Latency time = %3.3f us\n", 
                 1e6 * (new_time - old_time) * clockCycleTimeS / 20000 );
    }
    return 0;
}



测试结果(Linux-2.6.21 + RealTime Patch)
--------------------------------------------------
2801.226 MHz
Latency time =  8.129 us
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值