如何从C程序中正确禁用Linux的深度C状态?

huangapple go评论78阅读模式
英文:

How to properly disable Linux deep C-States from a C program?

问题

  1. Write the number 0.

    在Linux操作系统上,CPU运行在不同的节能状态,被称为C状态。它们从C0到Cn不等。C0是性能最高的状态,但会消耗更多电力。因此,为了最大化性能,可以禁用转换到更深层次的状态。这可以通过向**/dev/cpu_dma_latency**文件写入0来实现。

    参见:https://www.quora.com/What-is-the-purpose-of-dev-cpu_dma_latency-device-file-on-Linux-systems

    问题在于有两种写入文件的方法。

    方法一:

    FILE *fp;  
    
    void start_low_latency()
    {  
        char target = '0';  
    
        fp = fopen("/dev/cpu_dma_latency", "r+");  
        if (fp == NULL)
        {  
            fprintf(stderr, "Failed to open PM QOS file: %s", strerror(errno));  
            exit(errno);  
        }  
    
        fputc(target, fp);  
    }  
    
    void stop_low_latency()
    { 
        if (fp != NULL)//if (fp == NULL)
            fclose(fp);
    }
    

    参考链接:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/8/html/optimizing_rhel_8_for_real_time_for_low_latency_operation/assembly_controlling-power-management-transitions_optimizing-rhel8-for-real-time-for-low-latency-operation

  2. Binary write of the number 0.

    方法二:

    static int laptop = 0;
    static int latency_target_fd = -1;
    static int32_t latency_target_value = 0;  
    
    static void start_low_latency()//static void set_latency_target()
    {
        struct stat s;
        int err;  
    
        if (laptop) {
            warn("not setting cpu_dma_latency to save battery power\n");
            return;
        }  
    
        errno = 0;
        err = stat("/dev/cpu_dma_latency", &s);  
    
        if (err == -1) {
            err_msg_n(errno, "WARN: stat /dev/cpu_dma_latency failed");
            return;
        }
    
        errno = 0;
        latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR);  
    
        if (latency_target_fd == -1) {
            err_msg_n(errno, "WARN: open /dev/cpu_dma_latency");
            return;
        }  
    
        errno = 0;
        err = write(latency_target_fd, &latency_target_value, 4);  
    
        if (err < 1) {
            err_msg_n(errno, "# error setting cpu_dma_latency to %d!", latency_target_value);
            close(latency_target_fd);
            return;
        }
        printf("# /dev/cpu_dma_latency set to %dus\n", latency_target_value);
    }
    
    static void stop_low_latency()
    {
        if (latency_target_fd >= 0)
            close(latency_target_fd);
    }
    

    参考链接:https://kernel.googlesource.com/pub/scm/utils/rt-tests/rt-tests/+/stable/devel/v1.0.1/src/cyclictest/cyclictest.c

哪种方法是正确的?

英文:

On Linux OS CPUs run on different power-saving states called the C-states. They are ranging from C0 to Cn. C0 is the state with maximum performance, but consume more power. So to maximize performance one can disable transition to deeper states. This can be done by writing 0 to the /dev/cpu_dma_latency file.
See: https://www.quora.com/What-is-the-purpose-of-dev-cpu_dma_latency-device-file-on-Linux-systems

The problem is that there is two way of writing to the file.

  1. Write the number 0.

     FILE *fp;  
    
     void start_low_latency()
     {  
         char target = &#39;0&#39;;  
    
         fp= fopen(&quot;/dev/cpu_dma_latency&quot;, &quot;r+&quot;);  
         if (fp == NULL)
         {  
            fprintf(stderr, &quot;Failed to open PM QOS file: %s&quot;, strerror(errno));  
            exit(errno);  
         }  
    
         fputc(target, fp);  
       }  
    
     void stop_low_latency()
     { 
         if (fp != NULL)//if (fp == NULL)
           fclose(fp);
     }
    

Reference: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/8/html/optimizing_rhel_8_for_real_time_for_low_latency_operation/assembly_controlling-power-management-transitions_optimizing-rhel8-for-real-time-for-low-latency-operation

  1. Binary write of the number 0.

     static int laptop = 0;
     static int latency_target_fd = -1;
     static int32_t latency_target_value = 0;  
    
     static void start_low_latency()//static void set_latency_target()
     {
         struct stat s;
         int err;  
    
         if (laptop) {
             warn(&quot;not setting cpu_dma_latency to save battery power\n&quot;);
             return;
         }  
    
         errno = 0;
         err = stat(&quot;/dev/cpu_dma_latency&quot;, &amp;s);  
    
         if (err == -1) {
             err_msg_n(errno, &quot;WARN: stat /dev/cpu_dma_latency failed&quot;);
             return;
         }
    
         errno = 0;
         latency_target_fd = open(&quot;/dev/cpu_dma_latency&quot;, O_RDWR);  
    
         if (latency_target_fd == -1) {
             err_msg_n(errno, &quot;WARN: open /dev/cpu_dma_latency&quot;);
             return;
         }  
    
         errno = 0;
         err = write(latency_target_fd, &amp;latency_target_value, 4);  
    
         if (err &lt; 1) {
             err_msg_n(errno, &quot;# error setting cpu_dma_latency to %d!&quot;, latency_target_value);
             close(latency_target_fd);
             return;
         }
         printf(&quot;# /dev/cpu_dma_latency set to %dus\n&quot;, latency_target_value);
     }
    
     static void stop_low_latency()
     {
         if (latency_target_fd &gt;= 0)
             close(latency_target_fd);
     }
    

Reference: https://kernel.googlesource.com/pub/scm/utils/rt-tests/rt-tests/+/stable/devel/v1.0.1/src/cyclictest/cyclictest.c

Which method is the right one?

答案1

得分: 2

根据内核文档

要注册CPU延迟QoS的默认PM QoS目标,进程必须打开/dev/cpu_dma_latency。

只要设备节点保持打开状态,该进程就已经注册了参数的请求。

要更改所请求的目标值,进程需要向打开的设备节点写入一个s32值。或者,它可以使用10个字符长的十六进制字符串来写入值,例如“0x12345678”。
这相当于调用cpu_latency_qos_update_request()。

要删除用户模式对目标值的请求,只需关闭设备节点。

请注意,有两种方法可以表示所请求的C状态值:

  • 写入一个32位整数,或
  • 写入一个十六进制字符串

对于后一种情况,文档确实指定了一个10个字符的格式,但很可能实现也接受较短的十六进制字符串。在这种情况下,这两种替代方案分别涵盖了您的情况之一,这意味着两者都是可接受的。

英文:

According to the kernel documentation,

> To register the default PM QoS target for the CPU latency QoS, the
> process must open /dev/cpu_dma_latency.
>
> As long as the device node is held open that process has a registered
> request on the parameter.
>
> To change the requested target value, the process needs to write an
> s32 value to the open device node. Alternatively, it can write a hex
> string for the value using the 10 char long format e.g. "0x12345678".
> This translates to a cpu_latency_qos_update_request() call.
>
> To remove the user mode request for a target value simply close the
> device node.

Note well that there are two alternatives for how to express the requested C-state value:

  • write a 32-bit integer, OR
  • write a hex string

For the latter case, the docs do specify a 10-char format, but it is entirely plausible that the implementation also accepts shorter hex strings. In that case, these alternatives each cover one of your cases, meaning both are acceptable.

huangapple
  • 本文由 发表于 2023年7月11日 07:43:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657934.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定