Computing cpu's clock in cycles per second

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



  Since I have not been successful to determine the runtime
cpu frequency using the fedora tools:

$ sudo /usr/bin/cpufreq-info -f
$ sudo /usr/bin/cpufreq-info -w
$

They come up empty.

So, I wrote a simple program to determine an approximate
value for the number of cycles per second.

The algorithm is simple.

Start an one shot interval timer for N seconds  (can be an arg to the 
program), and M microseconds (can be an arg to the program).
The interval timer can be virtual (-v arg to the  program) or realtime 
(-r arg to the program).

be sure to set up a proper handler routine for the SIGALRM or SIGVTALRM, 
depending on -v or -r.

More on this later....

then simply run  a loop that increments count (type unsigned long, 
initialized to 0) until
the global var intr becomes none zero.

Now, how many instructions were executed just for the loop.

When I compiled the program with -S to see the assembler output,
it turns out to be a total of 7 instructions for the loop.
Now, let's assume each of the 7 instructions takes 2 or 3 cpu cycles. 
Lets say N cycles average per instruction.
so now you have count * 7 * N total cycles in the loop.
Divide that by the total number of seconds you set the timer for, and you
will get a pretty close approximation of the actual runtime cpu clock 
(per second).

Now, about the type of the interval  timer.
1. I found that using the virtual  interval timer yielded wrong values 
for count. Every time and each time it varies by thousand and sometimes 
millions.
2. That leaves the realtime interval timer.
3. In order to get a very close approximation to a realtime interval 
timer AND have a much more realistic value for the "count", the program
must be run as root, and niced to --20, like so:

sudo nice --20 ./freq -s120 -u0 -r

says run the program at the highest nice value, for 120 seconds and 0 
microseconds with realtime interval timer.

In my program I do  not bother to do the division, because I have no 
idea what each different cpu's
instructions cycles are for the specific 6 instruction in the loop.
I use bc  after the program prints the count to do the  math with long 
precision (scale=20)


The loop looks like this:

while (intr == 0) count++;

In assembly, it looks like this:



         jmp     .L25     ---------------------+
.L26:                                         |
         movl    count, %eax                   |
         addl    $1, %eax                      |
         movl    %eax, count                   |
.L25:                                         |
         movl    intr, %eax                    |
         testl   %eax, %eax                    |
         je      .L26     ---------------------+

Here's the program. I hope some folks on this list more familiar with 
realtime programming
can enhance it and share it with the rest of  us.


/* Program to compute the approximate cycles per second of a cpu clock */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <sys/time.h>
#include <sys/timeb.h>

#define TWO_MINUTES (120) // seconds

extern char *optarg;
extern int optind, opterr, optopt;

struct itimerval itv0;
struct timeb t0, t1;

long tv_sec = -1, tv_usec = -1;

struct sigaction doit;

unsigned count = 0;
int intr = 0;

void
alarm_handler(int sig)
{

     intr = 1;
}

void error(char *s)
{
     fprintf(stderr, "illegal option %s\n", (s == NULL) ? "unknown" : s);
     _exit(-1);
}

prt(int c)
{
     fprintf(stderr, "saw option %c\n", c);
}

main(int ac, char *av[])
{
     int opt;
     unsigned ms;
     unsigned itimer = -1;

     sleep(60);
     while ((opt = getopt(ac, av, "rs:u:v")) != -1) {
         switch(opt) {
             case 's': prt('s'); tv_sec  = atol(optarg); break;
             case 'u': prt('u'); tv_usec = atol(optarg); break;
             case 'r': prt('r'); itimer = ITIMER_REAL; break;
             case 'v': prt('v'); itimer = ITIMER_VIRTUAL; break;
             default: prt('?'); break; //error(optarg);
         }
     }

     if (tv_sec == -1)  tv_sec  = TWO_MINUTES; // 120 seconds.
     if (tv_usec == -1) tv_usec = 0;
     if (itimer == -1) itimer = ITIMER_REAL;

     itv0.it_value.tv_sec  = tv_sec;
     itv0.it_value.tv_usec = tv_usec;
     itv0.it_interval.tv_sec  = (long)0;
     itv0.it_interval.tv_usec = (long)0;

     doit.sa_handler = alarm_handler;

     if (itimer == ITIMER_VIRTUAL)
         sigaction(SIGVTALRM, &doit, (struct sigaction *)NULL);
     else    sigaction(SIGALRM, &doit, (struct sigaction *)NULL);
     ftime(&t0);
     if (itimer == ITIMER_VIRTUAL)
         setitimer(ITIMER_VIRTUAL, &itv0, (struct itimerval *)NULL);
     else    setitimer(ITIMER_REAL, &itv0, (struct itimerval *)NULL);

     while(intr == 0) count++;
     ftime(&t1);
     ms = ((unsigned)t1.time * 1000 + (unsigned)t1.millitm) -
          ((unsigned)t0.time * 1000 + (unsigned)t0.millitm);

     fprintf(stderr, "alarm after %u milliseconds \n", ms);
     // Above fprintf is just to show that the timer indeed ran for the 
specified
     // number of seconds.

     printf("count = %u\n", count);
}

-- 
users mailing list
users@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe or change subscription options:
https://admin.fedoraproject.org/mailman/listinfo/users
Guidelines: http://fedoraproject.org/wiki/Mailing_list_guidelines


[Index of Archives]     [Current Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]     [Fedora Docs]

  Powered by Linux