How to run a program with a lower clock speed in C

I need to imitate the operation of the hardware (NOT for video games).

This component runs at 1 GHz, and my computer runs at 2.5 and 2.7 GHz.

So, I'm trying to tell the computer to start this process at a lower speed.

I tried timers, but this will not be done: when working with small time intervals, the process will not track the time with accuracy (I will need to track milliseconds, and this cannot be done accurately) Also, to calculate the time intervals, you will lose some processor time

Keep in mind that I am not outsourcing for the community, I work on my own, but maybe you guys could help brainstorm :)

+5
source share
1 answer

Premise

From what I understand from your question and comments, you need to run a program with a 12.5 Hz processor. I might think of taking one step of the instructions as a debugger, but instead of waiting for one step of the instructions, it executes each instruction for every time delay (just like you said you tried). So, if this assumption is wrong, let me know and I will delete my answer because it is based on it.

Idea

If your hour meter is 80ms , it means that you can execute at least one command in 80ms . Unfortunately, the sleep function will only accept unsigned int arguments in seconds, so this will not work. However, there is a syscall nanosleep that allows you to adjust sleep in nanoseconds .

So, to convert these milliseconds to nano, you multiply it by 10 6 which will give you 80000000 nanoseconds sleep time. As you already mentioned, the time from calling the functions and the time of the emulator will be some time, but I think that the price you have to pay for the emulator (and you can always mess around with time to make finer settings). So nanosleep :

 #include <time.h> int nanosleep(const struct timespec *req, struct timespec *rem); struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; 

Another is the Linux ptrace system call

 #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); 

This function will allow you to do all kinds of actions with a monitored process, and I suggest you read the manual. This is very informative. This syscall is a basic debugging feature of the software, and you can read the tutorial on "How Debuggers Work" here.

In fact, my idea is taken from this tutorial (I read it a couple of days ago), and I am slightly modifying this code to create an emulator, so I also suggest reading the tutorial.


code

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/reg.h> #include <sys/user.h> #define MILLI 80 #define HZ ((double)1000/(double)MILLI) /* milli to nano */ #define m2n(a) (a*1000*1000) void run_target(char *prog) { printf("Emulating %.2lf Hz to proccess %s...\n\n", HZ, prog); if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { perror("ptrace"); return ; } execl(prog, prog, (char*)NULL); } void run_emulator(pid_t child) { int wait_status; struct timespec req; unsigned long int count = 1; /* set up the emulation speed */ req.tv_sec = 0; req.tv_nsec = m2n(MILLI); /* wait for stop on first instruction */ wait(&wait_status); while (WIFSTOPPED(wait_status)) { /* this loop will repeat at every instruction, so it executes the * instruction and sleeps for the amount of time needed to * emulate the wanted speed. */ if (ptrace(PTRACE_SINGLESTEP, child, 0, 0) < 0) { perror("ptrace"); return ; } wait(&wait_status); /* this does the sleep */ nanosleep(&req, NULL); } } int main(int argc, char *argv[]) { pid_t child; if (argc < 2) { fprintf(stderr, "Usage: %s [prog_name]\n", argv[0]); exit(EXIT_FAILURE); } child = fork(); if (!child) run_target(argv[1]); else if (child > 0) run_emulator(child); else { perror("fork"); exit(EXIT_FAILURE); } return 0; } 

To do a quick test, I wrote this simple fat(5) calculator in Assembly, which has 65 instructions (on my machine, of course):

  .section .data .section .text .globl _start .globl factorial _start: pushq $5 call factorial movq %rax, %rdi movq $0x3c, %rax syscall .type factorial, @function factorial: pushq %rbp movq %rsp, %rbp movq 16(%rbp), %rax cmpq $1, %rax je end_factorial decq %rax pushq %rax call factorial movq 16(%rbp), %rbx imulq %rbx, %rax end_factorial: movq %rbp, %rsp popq %rbp ret 

To assemble, link, run and see the result:

 $ as -o fat.o fat.s $ ld -o fat fat.o $ ./fat $ echo $? 120 $ 

So, it works and calculates the factorial of 5. So, if I'm right in mathematics, 65 teams will take 65/12.5 seconds to work on a 12.5 Hz processor, right? 65/12.5 = 5.2 .

 $ time ./lower ./fat Emulating 12.50 Hz to proccess ./fat... Returned: 30720 real 0m5.211s user 0m0.000s sys 0m0.008s 

Manual References

+2
source

All Articles