<div><div># HG changeset patch</div><div># User Agile6v <agile6v@agile6v.com></div><div># Date 1524585905 -28800</div><div>#      Wed Apr 25 00:05:05 2018 +0800</div><div># Node ID 89793df28d1bcf2baf00e389e6806d32d7435886</div><div># Parent  7c614ef3c6ea330c62630d5065f961a27d0f82cd</div><div>The auto parameter of the worker_processes supports to detect the container environment.</div><div><br></div><div>Docker mounts cgroup information into container starting with version 1.8,</div><div>so it is possible to determine the appropriate number of CPUs based on the </div><div>cgroup information in the container. Refer to JDK related implementation:</div><div>https://bugs.openjdk.java.net/browse/JDK-8146115</div><div><br></div><div>diff -r 7c614ef3c6ea -r 89793df28d1b auto/sources</div><div>--- a/auto/sources<span style="white-space:pre">  </span>Wed Apr 18 16:11:41 2018 +0300</div><div>+++ b/auto/sources<span style="white-space:pre">      </span>Wed Apr 25 00:05:05 2018 +0800</div><div>@@ -192,8 +192,8 @@</div><div> FREEBSD_SRCS=src/os/unix/ngx_freebsd_init.c</div><div> FREEBSD_SENDFILE_SRCS=src/os/unix/ngx_freebsd_sendfile_chain.c</div><div> </div><div>-LINUX_DEPS="src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux.h"</div><div>-LINUX_SRCS=src/os/unix/ngx_linux_init.c</div><div>+LINUX_DEPS="src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux.h src/os/unix/ngx_container.h"</div><div>+LINUX_SRCS="src/os/unix/ngx_linux_init.c src/os/unix/ngx_container.c"</div><div> LINUX_SENDFILE_SRCS=src/os/unix/ngx_linux_sendfile_chain.c</div><div> </div><div> </div><div>diff -r 7c614ef3c6ea -r 89793df28d1b src/os/unix/ngx_container.c</div><div>--- /dev/null<span style="white-space:pre">     </span>Thu Jan 01 00:00:00 1970 +0000</div><div>+++ b/src/os/unix/ngx_container.c<span style="white-space:pre">       </span>Wed Apr 25 00:05:05 2018 +0800</div><div>@@ -0,0 +1,418 @@</div><div>+</div><div>+/*</div><div>+ * Copyright (C) agile6v</div><div>+ * Copyright (C) Xiaomi, Inc.</div><div>+ */</div><div>+</div><div>+#include <ngx_config.h></div><div>+#include <ngx_core.h></div><div>+</div><div>+#define NGX_BUFFER_SIZE     8192</div><div>+#define PER_CPU_SHARES      1024</div><div>+</div><div>+typedef struct {</div><div>+    ngx_str_t root;</div><div>+    ngx_str_t path;</div><div>+    ngx_str_t mount_point;</div><div>+} cgroup_subsystem_info;</div><div>+</div><div>+static cgroup_subsystem_info cpu_subsystem;</div><div>+</div><div>+static ngx_str_t proc_cgroup_file   = ngx_string("/proc/self/cgroup");</div><div>+static ngx_str_t proc_mount_file    = ngx_string("/proc/self/mountinfo");</div><div>+static ngx_str_t cpu_cfs_period     = ngx_string("/cpu.cfs_period_us");</div><div>+static ngx_str_t cpu_cfs_quota      = ngx_string("/cpu.cfs_quota_us");</div><div>+static ngx_str_t cpu_cfs_shares     = ngx_string("/cpu.shares");</div><div>+</div><div>+static float ngx_ceilf(float x)</div><div>+{</div><div>+    long r = x;</div><div>+</div><div>+    if (r < 0) {</div><div>+        return r;</div><div>+    } else {</div><div>+        return (r + ((r < x) ? 1 : 0));</div><div>+    }</div><div>+}</div><div>+</div><div>+</div><div>+static ngx_int_t</div><div>+ngx_set_subsystem_path(cgroup_subsystem_info *subsystem_info,</div><div>+                       ngx_str_t *cgroup_path, ngx_pool_t *pool)</div><div>+{</div><div>+    u_char     *p;</div><div>+    ngx_uint_t  len;</div><div>+</div><div>+    if (subsystem_info->root.len != 0 && cgroup_path->data != NULL) {</div><div>+        if (ngx_strcmp(subsystem_info->root.data, "/") == 0) {</div><div>+            len = subsystem_info->mount_point.len;</div><div>+            if (ngx_strcmp(cgroup_path->data, "/") != 0) {</div><div>+                len += cgroup_path->len;</div><div>+            }</div><div>+</div><div>+            if (len > NGX_MAX_PATH) {</div><div>+                ngx_log_error(NGX_LOG_WARN, pool->log, 0,</div><div>+                    "the length of the cgroup path exceeds the maximum " \</div><div>+                    "length of the path (%d) ", NGX_MAX_PATH);</div><div>+                return NGX_ERROR;</div><div>+            }</div><div>+</div><div>+            p = ngx_palloc(pool, len + 1);</div><div>+            if (p == NULL) {</div><div>+                return NGX_ERROR;</div><div>+            }</div><div>+</div><div>+            subsystem_info->path.data = p;</div><div>+            subsystem_info->path.len = len;</div><div>+</div><div>+            if (ngx_strcmp(cgroup_path->data, "/") != 0) {</div><div>+                p = ngx_sprintf(p, "%V%V",</div><div>+                                &subsystem_info->mount_point,</div><div>+                                cgroup_path);</div><div>+            } else {</div><div>+                p = ngx_sprintf(p, "%V", &subsystem_info->mount_point);</div><div>+            }</div><div>+</div><div>+            *p = '\0';</div><div>+        } else if (ngx_strcmp(subsystem_info->root.data,</div><div>+                              cgroup_path->data) == 0)</div><div>+        {</div><div>+            subsystem_info->path = subsystem_info->mount_point;</div><div>+        }</div><div>+    }</div><div>+</div><div>+    return NGX_OK;</div><div>+}</div><div>+</div><div>+</div><div>+static ngx_int_t</div><div>+ngx_read_proc_file(ngx_str_t *filename, ngx_str_t *buf, ngx_pool_t *pool)</div><div>+{</div><div>+    ngx_int_t   ret;</div><div>+    ngx_uint_t  i;</div><div>+    size_t      size;</div><div>+    ssize_t     n;</div><div>+    ngx_file_t  file;</div><div>+</div><div>+    ngx_memzero(&file, sizeof(ngx_file_t));</div><div>+</div><div>+    file.name = *filename;</div><div>+    file.log = pool->log;</div><div>+    file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);</div><div>+    if (file.fd == NGX_INVALID_FILE) {</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    ret = NGX_OK;</div><div>+</div><div>+    //  Typically this file will not be too big, then try to read all data</div><div>+    for (i = 1; i <= 5; i++) {</div><div>+        size = NGX_BUFFER_SIZE * i;</div><div>+        buf->data = ngx_palloc(pool, size);</div><div>+        if (buf->data == NULL) {</div><div>+            ret = NGX_ERROR;</div><div>+            break;</div><div>+        }</div><div>+</div><div>+        n = ngx_read_file(&file, buf->data, size, 0);</div><div>+        if (n == NGX_ERROR) {</div><div>+            ret = NGX_ERROR;</div><div>+            break;</div><div>+        }</div><div>+</div><div>+        buf->len = n;</div><div>+</div><div>+        if (buf->len < size) {</div><div>+            break;</div><div>+        }</div><div>+    }</div><div>+</div><div>+    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {</div><div>+        ngx_log_error(NGX_LOG_ALERT, file.log, ngx_errno,</div><div>+                      ngx_close_file_n " \"%s\" failed", file.name);</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+</div><div>+/*</div><div>+ * refers to http://man7.org/linux/man-pages/man7/cgroups.7.html</div><div>+ */</div><div>+ngx_int_t</div><div>+ngx_parse_cgroup_file(ngx_pool_t *pool)</div><div>+{</div><div>+    ngx_int_t   ret;</div><div>+    ngx_str_t   buf;</div><div>+    ngx_str_t   fields[3];</div><div>+    ngx_uint_t  i, index;</div><div>+    u_char     *start, *end, end_of_line;</div><div>+</div><div>+    ret = ngx_read_proc_file(&proc_cgroup_file, &buf, pool);</div><div>+    if (ret == NGX_ERROR) {</div><div>+        return ret;</div><div>+    }</div><div>+</div><div>+    index = 0;</div><div>+    start = end = buf.data;</div><div>+</div><div>+    for (i = 0; i < buf.len; i++) {</div><div>+        if (*end == ':' || *end == '\n') {</div><div>+            end_of_line = (*end == '\n') ? 1 : 0;</div><div>+            *end = '\0';</div><div>+</div><div>+            fields[index].data = start;</div><div>+            fields[index].len = end - start;</div><div>+</div><div>+            if (end_of_line) {</div><div>+                index = 0;</div><div>+                if (ngx_strstr(fields[1].data, "cpu,cpuacct") != NULL) {</div><div>+                    ret = ngx_set_subsystem_path(&cpu_subsystem, &fields[2], pool);</div><div>+                    if (ret == NGX_ERROR) {</div><div>+                        return ret;</div><div>+                    }</div><div>+                }</div><div>+            } else {</div><div>+                index++;</div><div>+            }</div><div>+</div><div>+            start = end + 1;</div><div>+        }</div><div>+</div><div>+        end++;</div><div>+    }</div><div>+</div><div>+    return NGX_OK;</div><div>+}</div><div>+</div><div>+</div><div>+/*</div><div>+ * refers to http://man7.org/linux/man-pages/man5/proc.5.html</div><div>+ */</div><div>+ngx_int_t</div><div>+ngx_parse_mount_info_file(ngx_pool_t *pool)</div><div>+{</div><div>+    ngx_str_t   buf;</div><div>+    ngx_str_t   fields[11];</div><div>+    ngx_int_t   ret;</div><div>+    ngx_uint_t  i, index, fs_type_index;</div><div>+    u_char     *start, *end, end_of_line;</div><div>+</div><div>+    ret = ngx_read_proc_file(&proc_mount_file, &buf, pool);</div><div>+    if (ret == NGX_ERROR) {</div><div>+        return ret;</div><div>+    }</div><div>+</div><div>+    fs_type_index = index = 0;</div><div>+    start = end = buf.data;</div><div>+</div><div>+    for (i = 0; i < buf.len; i++) {</div><div>+        if (*end == ' ' || *end == '\n') {</div><div>+            end_of_line = (*end == '\n') ? 1 : 0;</div><div>+            *end = '\0';</div><div>+</div><div>+            fields[index].data = start;</div><div>+            fields[index].len = end - start;</div><div>+</div><div>+            if (fields[index].len == 1 && *fields[index].data == '-') {</div><div>+                fs_type_index = index + 1;</div><div>+            }</div><div>+</div><div>+            if (end_of_line) {</div><div>+                index = 0;</div><div>+                if (fields[fs_type_index].len == 6</div><div>+                    && ngx_strcmp(fields[fs_type_index].data, "cgroup") == 0</div><div>+                    && ngx_strstr(fields[4].data, "cpu,cpuacct") != NULL)</div><div>+                {</div><div>+                    cpu_subsystem.root = fields[3];</div><div>+                    cpu_subsystem.mount_point = fields[4];</div><div>+                }</div><div>+            } else {</div><div>+                index++;</div><div>+            }</div><div>+</div><div>+            start = end + 1;</div><div>+        }</div><div>+</div><div>+        end++;</div><div>+    }</div><div>+</div><div>+    return NGX_OK;</div><div>+}</div><div>+</div><div>+</div><div>+static ngx_int_t</div><div>+ngx_read_subsystem_info(cgroup_subsystem_info *subsystem,</div><div>+                       ngx_str_t *filename, ngx_log_t *log, ngx_int_t *value)</div><div>+{</div><div>+    ngx_file_t file;</div><div>+    ngx_int_t ret;</div><div>+    ngx_str_t full_path;</div><div>+    ssize_t   n;</div><div>+    u_char   *p;</div><div>+    u_char    sign = 0;</div><div>+    u_char    buf[NGX_MAX_PATH + 1];</div><div>+</div><div>+    if (subsystem->path.data == NULL || subsystem->path.len == 0) {</div><div>+        return NGX_DONE;</div><div>+    }</div><div>+</div><div>+    if ((subsystem->path.len + filename->len) > NGX_MAX_PATH) {</div><div>+        return NGX_DONE;</div><div>+    }</div><div>+</div><div>+    full_path.data = buf;</div><div>+    full_path.len = NGX_MAX_PATH;</div><div>+</div><div>+    ngx_memzero(&file, sizeof(ngx_file_t));</div><div>+</div><div>+    p = ngx_sprintf(full_path.data, "%V%V", &subsystem->path, filename);</div><div>+    *p = '\0';</div><div>+    full_path.len = p - full_path.data;</div><div>+</div><div>+    file.name = full_path;</div><div>+    file.log = log;</div><div>+    file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);</div><div>+    if (file.fd == NGX_INVALID_FILE) {</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    n = ngx_read_file(&file, buf, NGX_BUFFER_SIZE, 0);</div><div>+    if (n == NGX_ERROR) {</div><div>+        return n;</div><div>+    }</div><div>+</div><div>+    if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {</div><div>+        ngx_log_error(NGX_LOG_ALERT, file.log, ngx_errno,</div><div>+                      ngx_close_file_n " \"%s\" failed", file.name);</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    n = (n > 0) ? n - 1 : n;    // remove linefeed</div><div>+    if (n == 0) {</div><div>+        return NGX_DONE;</div><div>+    }</div><div>+</div><div>+    p = buf;</div><div>+    if (*p == '-') {</div><div>+        sign = 1;</div><div>+        p++;</div><div>+        n--;</div><div>+    }</div><div>+</div><div>+    ret = ngx_atoi(p, n);</div><div>+    if (ret == NGX_ERROR) {</div><div>+        return NGX_DONE;</div><div>+    }</div><div>+</div><div>+    if (sign) {</div><div>+        *value = -ret;</div><div>+    } else {</div><div>+        *value = ret;</div><div>+    }</div><div>+</div><div>+    return NGX_OK;</div><div>+}</div><div>+</div><div>+</div><div>+static ngx_int_t</div><div>+ngx_get_active_processor_count(ngx_log_t *log) {</div><div>+    ngx_int_t       quota_count = 0, share_count = 0;</div><div>+    ngx_int_t       cpu_count, limit_count;</div><div>+    ngx_int_t       ret, quota, period, shares;</div><div>+    ngx_cpuset_t    cpu_affinity;</div><div>+</div><div>+    ret = ngx_getaffinity(&cpu_affinity, log);</div><div>+    if (ret == NGX_ERROR) {</div><div>+        return ret;</div><div>+    }</div><div>+</div><div>+    cpu_count = limit_count = ret;</div><div>+</div><div>+    ngx_log_error(NGX_LOG_INFO, log, 0,</div><div>+                  "active processor count: %d", cpu_count);</div><div>+</div><div>+    ret = ngx_read_subsystem_info(&cpu_subsystem,</div><div>+                                     &cpu_cfs_shares, log, &shares);</div><div>+    if (ret == NGX_DONE || ret == NGX_ERROR) {</div><div>+        return ret;</div><div>+    }</div><div>+</div><div>+    ret = ngx_read_subsystem_info(&cpu_subsystem,</div><div>+                                  &cpu_cfs_quota, log, &quota);</div><div>+    if (ret == NGX_DONE || ret == NGX_ERROR) {</div><div>+        return ret;</div><div>+    }</div><div>+</div><div>+    ret = ngx_read_subsystem_info(&cpu_subsystem,</div><div>+                                  &cpu_cfs_period, log, &period);</div><div>+    if (ret == NGX_DONE || ret == NGX_ERROR) {</div><div>+        return ret;</div><div>+    }</div><div>+</div><div>+    ngx_log_error(NGX_LOG_INFO, log, 0,</div><div>+        "cgroup cpu subsystem: quota=%d, period=%d, shares=%d",</div><div>+        quota, period, shares);</div><div>+</div><div>+    if (shares == PER_CPU_SHARES) {</div><div>+        shares = -1;</div><div>+    }</div><div>+</div><div>+    if (quota > -1 && period > 0) {</div><div>+        quota_count = ngx_ceilf((float) quota / (float) period);</div><div>+    }</div><div>+</div><div>+    if (shares > -1) {</div><div>+        share_count = ngx_ceilf((float) shares / (float) PER_CPU_SHARES);</div><div>+    }</div><div>+</div><div>+    if (quota_count != 0 && share_count != 0) {</div><div>+        limit_count = ngx_min(quota_count, share_count);</div><div>+    } else if (quota_count != 0) {</div><div>+        limit_count = quota_count;</div><div>+    } else if (share_count != 0) {</div><div>+        limit_count = share_count;</div><div>+    }</div><div>+</div><div>+    return ngx_min(cpu_count, limit_count);</div><div>+}</div><div>+</div><div>+</div><div>+ngx_int_t</div><div>+ngx_container_init(ngx_log_t *log)</div><div>+{</div><div>+    ngx_pool_t      *pool;</div><div>+    ngx_int_t        ret;</div><div>+</div><div>+    pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, log);</div><div>+    if (pool == NULL) {</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    pool->log = log;</div><div>+</div><div>+    do {</div><div>+        ret = ngx_parse_mount_info_file(pool);</div><div>+        if (ret != NGX_OK) {</div><div>+            break;</div><div>+        }</div><div>+</div><div>+        ret = ngx_parse_cgroup_file(pool);</div><div>+        if (ret != NGX_OK) {</div><div>+            break;</div><div>+        }</div><div>+</div><div>+        if (cpu_subsystem.path.data == NULL || cpu_subsystem.path.len == 0) {</div><div>+            ret = NGX_DONE;</div><div>+            break;</div><div>+        }</div><div>+</div><div>+        ret = ngx_get_active_processor_count(log);</div><div>+</div><div>+    } while (0);</div><div>+</div><div>+    ngx_destroy_pool(pool);</div><div>+</div><div>+    return ret;</div><div>+}</div><div>diff -r 7c614ef3c6ea -r 89793df28d1b src/os/unix/ngx_container.h</div><div>--- /dev/null<span style="white-space:pre">  </span>Thu Jan 01 00:00:00 1970 +0000</div><div>+++ b/src/os/unix/ngx_container.h<span style="white-space:pre">       </span>Wed Apr 25 00:05:05 2018 +0800</div><div>@@ -0,0 +1,12 @@</div><div>+</div><div>+/*</div><div>+ * Copyright (C) agile6v</div><div>+ * Copyright (C) Xiaomi, Inc.</div><div>+ */</div><div>+</div><div>+#ifndef _NGX_CONTAINER_H_INCLUDED_</div><div>+#define _NGX_CONTAINER_H_INCLUDED_</div><div>+</div><div>+ngx_int_t ngx_container_init(ngx_log_t *log);</div><div>+</div><div>+#endif /* _NGX_CONTAINER_H_INCLUDED_ */</div><div>diff -r 7c614ef3c6ea -r 89793df28d1b src/os/unix/ngx_linux_init.c</div><div>--- a/src/os/unix/ngx_linux_init.c<span style="white-space:pre">     </span>Wed Apr 18 16:11:41 2018 +0300</div><div>+++ b/src/os/unix/ngx_linux_init.c<span style="white-space:pre">      </span>Wed Apr 25 00:05:05 2018 +0800</div><div>@@ -7,12 +7,12 @@</div><div> </div><div> #include <ngx_config.h></div><div> #include <ngx_core.h></div><div>+#include <ngx_container.h></div><div> </div><div> </div><div> u_char  ngx_linux_kern_ostype[50];</div><div> u_char  ngx_linux_kern_osrelease[50];</div><div> </div><div>-</div><div> static ngx_os_io_t ngx_linux_io = {</div><div>     ngx_unix_recv,</div><div>     ngx_readv_chain,</div><div>@@ -33,6 +33,7 @@</div><div> ngx_int_t</div><div> ngx_os_specific_init(ngx_log_t *log)</div><div> {</div><div>+    ngx_int_t       ret;</div><div>     struct utsname  u;</div><div> </div><div>     if (uname(&u) == -1) {</div><div>@@ -48,6 +49,13 @@</div><div> </div><div>     ngx_os_io = ngx_linux_io;</div><div> </div><div>+    ret = ngx_container_init(log);</div><div>+    if (ret == NGX_ERROR) {</div><div>+        return ret;</div><div>+    } else if (ret > NGX_OK) {</div><div>+        ngx_ncpu = ret;</div><div>+    }</div><div>+</div><div>     return NGX_OK;</div><div> }</div><div> </div><div>diff -r 7c614ef3c6ea -r 89793df28d1b src/os/unix/ngx_setaffinity.c</div><div>--- a/src/os/unix/ngx_setaffinity.c<span style="white-space:pre">        </span>Wed Apr 18 16:11:41 2018 +0300</div><div>+++ b/src/os/unix/ngx_setaffinity.c<span style="white-space:pre">     </span>Wed Apr 25 00:05:05 2018 +0800</div><div>@@ -30,6 +30,12 @@</div><div>     }</div><div> }</div><div> </div><div>+ngx_int_t</div><div>+ngx_getaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log)</div><div>+{</div><div>+    return 0;</div><div>+}</div><div>+</div><div> #elif (NGX_HAVE_SCHED_SETAFFINITY)</div><div> </div><div> void</div><div>@@ -50,4 +56,16 @@</div><div>     }</div><div> }</div><div> </div><div>+ngx_int_t</div><div>+ngx_getaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log)</div><div>+{</div><div>+    if (sched_getaffinity(0, sizeof(ngx_cpuset_t), cpu_affinity) == -1) {</div><div>+        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,</div><div>+                      "sched_getaffinity() failed");</div><div>+        return NGX_ERROR;</div><div>+    }</div><div>+</div><div>+    return CPU_COUNT(cpu_affinity);</div><div>+}</div><div>+</div><div> #endif</div><div>diff -r 7c614ef3c6ea -r 89793df28d1b src/os/unix/ngx_setaffinity.h</div><div>--- a/src/os/unix/ngx_setaffinity.h<span style="white-space:pre">        </span>Wed Apr 18 16:11:41 2018 +0300</div><div>+++ b/src/os/unix/ngx_setaffinity.h<span style="white-space:pre">     </span>Wed Apr 25 00:05:05 2018 +0800</div><div>@@ -23,12 +23,15 @@</div><div> </div><div> #endif</div><div> </div><div>+ngx_int_t ngx_getaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log);</div><div> void ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log);</div><div> </div><div> #else</div><div> </div><div> #define ngx_setaffinity(cpu_affinity, log)</div><div> </div><div>+#define ngx_getaffinity(cpu_affinity, log)</div><div>+</div><div> typedef uint64_t  ngx_cpuset_t;</div><div> </div><div> #endif</div></div><div><br></div>