【问题标题】:Problems setting CPU affinity in C在 C 中设置 CPU 亲和性的问题
【发布时间】:2014-04-21 18:22:18
【问题描述】:

我正在尝试计算 CPUID 指令运行所需的时间。

来源:

#include <stdio.h>
#include <sched.h>

cpu_set_t mask;

CPU_ZERO(&mask);
CPU_SET(0, &mask);
sched_setaffinity(0, sizeof(mask), &mask);

static inline unsigned long long tick()
{
    unsigned long long d;
    asm volatile ("rdtsc" : "=A" (d));
    return d;
}

void cpuid(void)
{
    int i;

    for(i=0; i != 5; i++)
    {
         asm volatile ("cpuid");
    }
}

int main()
{
    long long bef;
    long long aft;
    long long dif;

    bef=tick();
    cpuid();
    aft=tick();
    dif=aft-bef;

    printf("%d\n", bef);
    printf("%d\n", aft);
    printF("%d\n", dif);

    return 0;
}

现在我正在使用以下代码进行编译

gcc -D_GNU_SOURCE -o test test.c

我在不是文件的代码上遇到错误! 例如:

test.c:6:1: error: expected identifier or '(' before 'do'
test.c:6:1: error: expected identifier or '(' before 'while'
test.c:7:1: error: expected identifier or '(' before '__extension__'
test.c:8:1: warning: data definition has no type or storage class [enable by def...
test.c:8:1: error: intializer element is not constant

“def...”实际上不是输出,因为我的终端窗口很小。我在 ESXi 工作。

任何帮助都会很棒!!!

面向未来的读者

用户@Iwillnotexist Idonotexist 说使用以下函数获得完整的x86 和x64 支持是正确的。

static __inline__ unsigned long long rdtsc(void)
{
  unsigned hi, lo;
  __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
  return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}

【问题讨论】:

  • 你将犯同样的错误,太多人在你之前犯过rdtsc=A asm约束...stackoverflow.com/questions/19941588/…
  • 我理解这一点,但我是否正确地说 RDTSC 返回周期或实际时间并不重要。因为任何一种方式的差异都表明时间已经过去,所以只是您测量的是实际时间还是指定时间内的周期数。我可能是错的。如果我是,你能解释一下吗?
  • 问题不在于,问题在于 RDTSC 返回一个 64 位值,但它在寄存器 edxeax。在 32 位模式下,=A 约束正确选择了一对寄存器edx:eax;在 64 位模式下,它不会。相反,您将只阅读rax,其上半部分在rdtsc 之后为零。因此,当您减去时,有时您会得到不应该的负值,并且您将无法测量超过几秒钟的时间差,因为您只使用 TSC 计数器的低 32 位.
  • 如果您将代码更改为在此处使用#elif defined(__x86_64__) (mcs.anl.gov/~kazutomo/rdtsc.html) 下面的rdtsc() 函数版本,而不是您自己的tick(),它将在 32 位和 64 位上工作无处不在的操作系统。
  • 我有一个新问题。将此代码移植到 Windows :( 有什么想法吗?

标签: c linux compiler-errors cpu compiler-warnings


【解决方案1】:

您有函数之外的代码。这是不允许的。将以下内容移至main

CPU_ZERO(&mask);
CPU_SET(0, &mask);
sched_setaffinity(0, sizeof(mask), &mask);

【讨论】:

    【解决方案2】:

    这些指令应该在 main() 中:

    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    sched_setaffinity(0, sizeof(mask), &mask);
    

    这应该可以修复编译错误。

    那么,cpuid() 的五次迭代太少,无法给出有意义的结果。

    您可以检查这个answer,但使用两个不同长度的序列,仅使用 CPUID 指令。您需要更长的周期,但不会太长以至于内存获取开始发挥作用。

    我已经运行了一些测试,TEST 定义在 5 到 1000 之间; CPU 亲和力似乎不会影响四核上的结果:

    #include <stdio.h>
    #include <sched.h>
    
    static inline unsigned long long tick() {
        unsigned long long d;
        asm volatile ("rdtsc" : "=A" (d));
        return d;
    }
    
    static inline void cpuid(void) {
        int i;
        for(i=0; i != TEST; i++) {
             asm volatile ("cpuid");
        }
    }
    
    int main()
    {
        long long bef, aft, dif;
    
        bef=tick();
        cpuid();
        aft=tick();
        dif=(aft-bef)/TEST;
    
        printf("%lld\n", dif);
    
        return 0;
    }
    
    gcc -o0 -DTEST=100 -D_GNU_SOURCE -W -Wall -o time time.c && ./time
    

    【讨论】:

    • 好的,所以将亲和力内容移到主要作品中。我想要做的是测量执行 CPUID 所需的时间。因为这是离开虚拟环境的指令。因此,我希望在从 VM 中执行指令时看到时间增加。我希望它们会是激烈的,因为我的研究旨在从 VM 中的可执行文件中识别虚拟环境。
    • 我还看到从 RDTSC 返回的负值不一致!这就是为什么我决定设置 CPU 亲和性,以防指令通过内核传递,否则会发生错误。
    • 我看到了大约 80000 的差异。这非常大吗?
    • @user3078629 你看到我上面的评论了吗?在asm volatile ("rdtsc" : "=A" (d)); 中使用asm 约束=A,为什么它是错误的?确保你改变它。例如,这里的 x86_64 解决方案 (mcs.anl.gov/~kazutomo/rdtsc.html) 是一种方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 2010-11-27
    • 2022-12-05
    相关资源
    最近更新 更多