如何在C语言中以较低的时钟速度运行程序

5

我需要模拟一款硬件的工作方式(不是用于视频游戏)。

这个组件以1 Ghz的速度运行,而我的电脑以2.5和2.7 Ghz的速度运行。

因此,我正试图告诉电脑以更低的速度运行特定的进程。

我尝试过使用定时器,但这样做行不通:当处理时间间隔很小的时候,进程无法准确地跟踪时间(我需要跟踪毫秒,并且不能整洁地完成)。 而且计算时间间隔会损失一些CPU时间。

请记住,我不是外包给社区的,我是自己在工作,但也许你们可以帮助进行头脑风暴 :)


4
也许这个对你有用。否则,你可以使用虚拟机来解决它。 - bazz-dee
3
你可以尝试使用虚拟机,http://superuser.com/questions/297550/how-can-i-simulate-a-slow-machine-in-a-vm。不过,我认为你的问题在这里算是离题了。 - marcinj
1
获取一个具有降频功能的现代主板,问题解决了。但是你的目标架构是否与你的个人电脑相同,只是时钟速率不同?1GHz ARM与1GHz Intel并不完全兼容,即使是Intel每一代也存在差异。 - Non-maskable Interrupt
1
你是否试图模拟一个在固定时钟1GHz下执行某些操作的硬件?如果是这样,即使在1GHz时钟CPU上运行程序也无法保证模拟/仿真的固定1GHz锁步。 - melak47
2
那么购买一台约30美元的1GHz ARM设备是您唯一的选择。没有其他解决方案,包括虚拟机,在运行2.5GHz时都无法给您以1GHz(...和与另一个平台相当)运行的错觉。虚拟机(VMs)像计时器一样,受到调度精度和调度量子的影响。您最多只能粗略模拟长时间的计算密集型任务的近似总体数字,但这根本不适用于例如响应性。 - Damon
显示剩余9条评论
1个回答

3

前提

根据您的问题和评论,我理解您需要在 12.5 Hz 的 CPU 上运行程序。我可以考虑单步执行指令,就像调试器一样,但是它会在每个 时间延迟 中执行每个指令(类似于您尝试过的内容)。所以,如果这个前提是错误的,请告诉我,我将删除我的答案,因为它是基于此的。

思路

如果您的时钟计数为 80ms,那么这意味着您至少可以在 80ms 内执行一个指令。不幸的是,sleep 函数只接受以 为单位的无符号整数参数,所以这不起作用。然而,有一个系统调用 nanosleep,它可以让您调整睡眠时间,单位为 nanoseconds

因此,要将毫秒转换为纳秒,您需要将其乘以106,这将给您80000000纳秒的睡眠时间。正如您已经提到的,从调用函数和模拟器时间中会有一些时间浪费,但我认为这是使用模拟器所必须付出的代价(并且您可以随时调整时间以进行更精细的调整)。因此,nanosleep是:

#include <time.h>

int nanosleep(const struct timespec *req, struct timespec *rem);

struct timespec {
       time_t tv_sec;        /* seconds */
       long   tv_nsec;       /* nanoseconds */
};

另一个是Linux系统调用ptrace

#include <sys/ptrace.h>

long ptrace(enum __ptrace_request request, pid_t pid,
               void *addr, void *data);

这个函数将让您对跟踪的进程进行各种操作,建议您阅读手册,它非常有用。该系统调用是调试软件的基本功能,并且您可以在调试器如何工作教程中阅读相关内容。

实际上,我的想法来自于那篇教程(我几天前读了它),我将稍微修改那段代码以执行模拟器,因此我也建议您阅读该教程。


代码

#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;
}

为了进行快速测试,我用汇编语言编写了这个简单的 fat(5) 计算器,它有 65 条指令(在我的机器上,当然)。
 .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

要进行组装、链接、运行并查看结果:

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

所以,它可以计算5的阶乘。如果我的数学没错的话,65条指令将在12.5Hz的CPU上运行65/12.5秒,对吗?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

手册参考


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接