Search code examples
clinux-kerneloperating-systemcontext-switchrdtsc

Using rdtsc + rdtscp across context switch


I am trying to write a program to measure context switch. I have gone through this Intel's manual about rdtsc + rdtscp instructions.

Now, I want to use these time-stamp instructions across context switch. I have the general skeleton as follows:

// init two pipes P1, P2
fork();

set_affinity();              // same core

// parent's code:
    cpuid + rdtsc            // start timer
    write(timer to P1);

    read(timer from P2);     // blocks parent if timer value not written
    rdtscp + cpuid           // stop timer, get difference

// child's code:
    read(timer from P1);     // blocks child if timer value not written
    rdtscp + cpuid           // stop timer, get difference

    cpuid + rdtsc            // start timer
    write(timer to P2);

There are a few problem I am seeing with this code. Assuming the timer operations are correct,

If the OS chooses to context switch to some entirely different process (not the child or parent), it won't work.

This code will also include the time taken by the read() and write() system calls.

Ignoring these issues, is it a valid use of rdtsc + rdtscp instructions?

I know writing a kernel module and disabling preemption/interrupts is a better way

Solution

  • I've done this before, and it seems to be a valid way of measuring context switch time. Whenever doing timing of something this fine-grained, scheduling unpredictability is always going to come into play; usually you deal with that by measuring thousands of times and looking for figures like the minimum, media, or mean time interval. You can make scheduling less of an issue by running both processes with real-time SCHED_FIFO priority. If you want to know actual switching time (on a single cpu core) you need to bind both processes to a single cpu with affinity settings. If you just want to know latency for one process being able to respond to the output of another, letting them run on different cpus is fine.

    Another issue to keep in mind is that voluntary and involuntary context switches, and switches starting from user-space versus from kernel-space have different costs. Yours is likely to be voluntary. Measuring involuntary is harder and requires poking at shared memory from busy loops, or similar.