现在的位置: 首页 > 综合 > 正文

一种控制进程CPU利用率的方法

2016年05月06日 ⁄ 综合 ⁄ 共 2417字 ⁄ 字号 评论关闭

在一个计算机系统中,CPU是一个有限的核心的资源,有时为了充分利用CPU的资源,我们会把业务混合部署到一台机器上,这些业务有可能包括核心业务和非核心业务,为了不影响核心业务,我们需要限制非核心业务CPU资源的利用率。

背后原理

如果一个进程的CPU利用率是40%,表示这个进程占用了40%的CPU时间。那么为了限制进程的CPU不超过40%,我们可以让这个进程运行40%的时间,然后停止60%的时间。通过给进程发送SIGCONT和SIGSTOP信号可以控制进程的启停。

代码示例

根据上面的原理,代码如下:

#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <vector>
#include <getopt.h>

static int g_process_count = 8;
static int g_cpu_usage = 80;
static std::vector<pid_t> g_child_processes;
static int g_show_usage = 0;

static void show_usage()
{
    fprintf(stdout, 
"Usage: cpu [--process-count=N] [--cpu-usage=N]\n"
"\n"
"  -c, --process-count=N  process count\n"
"  -u, --cpu-usage=N      cpu usage\n"
"\n"
"Examples:\n"
"  cpu --process-count=8 --cpu-usage=60\n");
}

int child_main()
{
    for (;;) {
    }

    return 0;
}

int main(int argc, char* argv[])
{
    int c;
    int digit_optind = 0;

    while (1) {
        int this_option_optind = optind ? optind : 1;
        int option_index = 0;
        static struct option long_options[] = {
            {"process-count", 1, 0, 'c' },
            {"cpu-usage",     1, 0, 'u' },
            {"help",          0, 0, 'h' },
            {0,               0, 0, 0   }
        };

        c = getopt_long(argc, argv, "c:u:?h", long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
            case 0:
                break;
            case 'c':
                g_process_count = atoi(optarg);
                break;
            case 'u':
                g_cpu_usage = atoi(optarg);
                break;
            case 'h':
                g_show_usage = 1;
                break;
            default:
                printf ("?? getopt returned character code 0%o ??\n", c);
        }
    }

    if (optind != argc) {
        show_usage();
        return -1;
    }

    if (g_show_usage) {
        show_usage();
        return 0;
    }

    fprintf(stdout, "process count %d cpu usage %d\n", g_process_count, g_cpu_usage);

    for (int i = 0; i < g_process_count; ++i) {
        pid_t pid = fork();
        if (pid == -1) {
            fprintf(stderr, "fork failed %d:%s\n", errno, strerror(errno));
            return -1;
        }

        if (pid == 0) { // child
            child_main();
            exit(0);
        }

        g_child_processes.push_back(pid);
    }

    for (;;) {
        for (std::vector<pid_t>::const_iterator iter = g_child_processes.begin(); iter != g_child_processes.end(); ++iter) {
            pid_t child_pid = *iter;
            kill(child_pid, SIGSTOP);
        }
        usleep((100 - g_cpu_usage) * 1000);
        for (std::vector<pid_t>::const_iterator iter = g_child_processes.begin(); iter != g_child_processes.end(); ++iter) {
            pid_t child_pid = *iter;
            kill(child_pid, SIGCONT);
        }
        usleep(g_cpu_usage * 1000);
    }

    return 0;
}

使用g++ -o ./cpu_limit_test ./cpu_limit_test.cpp编译,运行./cpu_limit_test --process-count=4 --cpu-usage=30的效果如下:


process-count参数指定创建的子进程的个数,cpu-usage参数表示cpu的上线。上面的代码,首先创建process-count个子进程,每个子进程都是一个死循环;父进程每隔一段时间给所有的子进程发送SIGCONT和SIGSTOP信号来控制子进程的运行,进而达到控制CPU资源利用率的目的。

总结

通过上面的示例,我们达到了控制CPU资源利用率的目的,细心的读者可能已经发现,上面示例的子进程的CPU利用率曲线实际上是一条直线。同样的原理,我们修改下代码就可以进而达到让子进程的CPU曲线成正弦或余弦函数,这里我就不展开了。开源项目cpulimit用的也是同样的原理,大家也可以参考I下它的实现。感谢您的阅读,欢迎评论。

抱歉!评论已关闭.