diff --git a/src/client/connect/pack_config.c b/src/client/connect/pack_config.c index f7cadfe6f41e07788510e46c6eeb71d8a650aa11..86cce9a804231dd1ce53096b7fdc04f4bdc47451 100644 --- a/src/client/connect/pack_config.c +++ b/src/client/connect/pack_config.c @@ -598,6 +598,11 @@ static void pack_cgroup_resources_cpu(host_config *dstconfig, const isula_host_c dstconfig->blkio_weight = srcconfig->cr->blkio_weight; } + /* cpus */ + if (srcconfig->cr->nano_cpus != 0) { + dstconfig->nano_cpus = srcconfig->cr->nano_cpus; + } + /* cpu shares */ if (srcconfig->cr->cpu_shares) { dstconfig->cpu_shares = srcconfig->cr->cpu_shares; diff --git a/src/client/libisula.h b/src/client/libisula.h index 92470ad89a3cb23e221f9683529f4531ba011f7f..54286c9b9982387013664972e20c32a087f1b986 100644 --- a/src/client/libisula.h +++ b/src/client/libisula.h @@ -112,6 +112,7 @@ typedef struct container_cgroup_resources { int64_t files_limit; int64_t oom_score_adj; int64_t swappiness; + int64_t nano_cpus; } container_cgroup_resources_t; typedef struct isula_host_config { diff --git a/src/cmd/command_parser.c b/src/cmd/command_parser.c index 33a1f37c0d7477d2bf5f52b12ff01c06c098793e..cc93b66b8c1d32174b62a1cc03c5f66b1cb659a9 100644 --- a/src/cmd/command_parser.c +++ b/src/cmd/command_parser.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "constants.h" #include "utils.h" @@ -551,3 +552,34 @@ int command_convert_swappiness(command_option_t *option, const char *arg) } return 0; } + +int command_convert_nanocpus(command_option_t *option, const char *arg) +{ + int ret = 0; + char *dup = NULL; + + if (option == NULL) { + return -1; + } + + if (!isdigit(arg[0])) { + COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); + return EINVALIDARGS; + } + + dup = util_strdup_s(arg); + if (dup == NULL) { + COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); + return EINVALIDARGS; + } + + if (util_parse_size_int_and_float(arg, 1e9, option->data)) { + COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large); + ret = EINVALIDARGS; + goto out; + } + +out: + free(dup); + return ret; +} diff --git a/src/cmd/command_parser.h b/src/cmd/command_parser.h index cdf3e1e75898b02ea7f4e23a1d51b3462ba06ac4..2df0570512dc72fb39c1bbfa61a58763aaa12cd3 100644 --- a/src/cmd/command_parser.h +++ b/src/cmd/command_parser.h @@ -104,6 +104,8 @@ int check_default_ulimit_type(const char *type); int command_convert_swappiness(command_option_t *option, const char *arg); +int command_convert_nanocpus(command_option_t *option, const char *arg); + #ifdef __cplusplus } #endif diff --git a/src/cmd/isula/base/create.c b/src/cmd/isula/base/create.c index 4ca307e88ae40ac6393016b302cc69b712f3c2c4..d33a1c32c670dce6a78e55c02ffd3042280d38ef 100644 --- a/src/cmd/isula/base/create.c +++ b/src/cmd/isula/base/create.c @@ -145,6 +145,9 @@ static int request_pack_host_config_cgroup(const struct client_arguments *args, /* blkio weight */ hostconfig->cr->blkio_weight = args->cr.blkio_weight; + /* nano cpus */ + hostconfig->cr->nano_cpus = args->cr.nano_cpus; + /* cpu shares */ hostconfig->cr->cpu_shares = args->cr.cpu_shares; diff --git a/src/cmd/isula/base/create.h b/src/cmd/isula/base/create.h index 7b962aca21d8725f9a8f78ce3029d7f068655bb2..4fb5000f213666da5da8ef1d7148cca46af242a1 100644 --- a/src/cmd/isula/base/create.h +++ b/src/cmd/isula/base/create.h @@ -457,7 +457,9 @@ extern "C" { 0, \ &((cmdargs).cr).cpu_rt_runtime, \ "Limit CPU real-time runtime in microseconds.", \ - command_convert_llong }, + command_convert_llong }, \ + { CMD_OPT_TYPE_CALLBACK, false, "cpus", 0, &((cmdargs).cr).nano_cpus, "Number of CPUs.", \ + command_convert_nanocpus }, #define CREATE_EXTEND_OPTIONS(cmdargs) \ { CMD_OPT_TYPE_BOOL, \ diff --git a/src/cmd/isula/client_arguments.h b/src/cmd/isula/client_arguments.h index d4bf0350291501931ad7cd0278779a7b56cf6734..0c42bb4842b287cc992a117c1fe2560c99683dc9 100644 --- a/src/cmd/isula/client_arguments.h +++ b/src/cmd/isula/client_arguments.h @@ -220,6 +220,7 @@ struct args_cgroup_resources { int64_t memory_reservation; int64_t kernel_memory_limit; int64_t swappiness; + int64_t nano_cpus; }; struct client_arguments { diff --git a/src/cmd/isula/extend/update.c b/src/cmd/isula/extend/update.c index a51e074c8abaf376fabac8c602734b128cf21d4b..57be139f114191c73cb505765c159e55eb874d5a 100644 --- a/src/cmd/isula/extend/update.c +++ b/src/cmd/isula/extend/update.c @@ -39,6 +39,8 @@ static int pack_update_request(const struct client_arguments *args, struct isula request->updateconfig->cr->blkio_weight = args->cr.blkio_weight; + request->updateconfig->cr->nano_cpus = args->cr.nano_cpus; + request->updateconfig->cr->cpu_shares = args->cr.cpu_shares; request->updateconfig->cr->cpu_period = args->cr.cpu_period; diff --git a/src/cmd/isula/extend/update.h b/src/cmd/isula/extend/update.h index 4d688bf9574201edffd49dadd480a87942a0b9e2..a527b46abb7f2c337d3ed5325a4ed73905264be4 100644 --- a/src/cmd/isula/extend/update.h +++ b/src/cmd/isula/extend/update.h @@ -106,7 +106,9 @@ extern "C" { 0, \ &((cmdargs).cr).cpu_rt_runtime, \ "Limit CPU real-time runtime in microseconds.", \ - command_convert_llong }, + command_convert_llong }, \ + { CMD_OPT_TYPE_CALLBACK, false, "cpus", 0, &((cmdargs).cr).nano_cpus, "Number of CPUs.", \ + command_convert_nanocpus }, extern const char g_cmd_update_desc[]; extern const char g_cmd_update_usage[]; diff --git a/src/daemon/common/sysinfo.c b/src/daemon/common/sysinfo.c index f147aee5253219047842ddb28698bb313aac4ccc..4f08c7be5aa39ca76889adaaa4302b88ac7edff8 100644 --- a/src/daemon/common/sysinfo.c +++ b/src/daemon/common/sysinfo.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "err_msg.h" #include "sysinfo.h" @@ -1170,6 +1171,8 @@ sysinfo_t *get_sys_info(bool quiet) goto out; } + sysinfo->ncpus = get_nprocs(); + check_cgroup_mem(layers, quiet, &sysinfo->cgmeminfo); check_cgroup_cpu(layers, quiet, &sysinfo->cgcpuinfo); check_cgroup_hugetlb(layers, quiet, &sysinfo->hugetlbinfo); diff --git a/src/daemon/common/sysinfo.h b/src/daemon/common/sysinfo.h index 7089c4e4782a3692a36c31b08e787dc6aa5a9df4..8468e00a2428dffcb4779469b6a64bae3432c007 100644 --- a/src/daemon/common/sysinfo.h +++ b/src/daemon/common/sysinfo.h @@ -71,6 +71,7 @@ typedef struct { } cgroup_files_info_t; typedef struct { + int ncpus; cgroup_mem_info_t cgmeminfo; cgroup_cpu_info_t cgcpuinfo; cgroup_hugetlb_info_t hugetlbinfo; @@ -143,4 +144,3 @@ void free_mounts_info(mountinfo_t **minfos); #endif #endif // DAEMON_COMMON_SYSINFO_H - diff --git a/src/daemon/executor/container_cb/execution_extend.c b/src/daemon/executor/container_cb/execution_extend.c index 725cb56dd38b9c2752485e3ed72eaac5e0c3c89a..e63ec54bb4066f1b0cc08d699a42150af36a409a 100644 --- a/src/daemon/executor/container_cb/execution_extend.c +++ b/src/daemon/executor/container_cb/execution_extend.c @@ -834,8 +834,41 @@ static void host_config_restore_unlocking(container_t *cont, host_config *backup } } -static void update_container_cpu(const host_config *hostconfig, host_config *chostconfig) +static int update_container_cpu(const host_config *hostconfig, host_config *chostconfig) { + int ret = 0; + + if (hostconfig->nano_cpus > 0 && chostconfig->cpu_period > 0) { + ERROR("Conflicting options: Nano CPUs cannot be updated as CPU Period has already been set"); + isulad_set_error_message("Conflicting options: Nano CPUs cannot be updated as CPU Period has already been set"); + ret = -1; + goto out; + } + + if (hostconfig->nano_cpus > 0 && chostconfig->cpu_quota > 0) { + ERROR("Conflicting options: Nano CPUs cannot be updated as CPU Quota has already been set"); + isulad_set_error_message("Conflicting options: Nano CPUs cannot be updated as CPU Quota has already been set"); + ret = -1; + goto out; + } + + if (hostconfig->cpu_period > 0 && chostconfig->nano_cpus > 0) { + ERROR("Conflicting options: CPU Period cannot be updated as NanoCPUs has already been set"); + isulad_set_error_message("Conflicting options: CPU Period cannot be updated as NanoCPUs has already been set"); + ret = -1; + goto out; + } + + if (hostconfig->cpu_quota > 0 && chostconfig->nano_cpus > 0) { + ERROR("Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set"); + isulad_set_error_message("Conflicting options: CPU Quota cannot be updated as NanoCPUs has already been set"); + ret = -1; + goto out; + } + + if (hostconfig->nano_cpus != 0) { + chostconfig->nano_cpus = hostconfig->nano_cpus; + } if (hostconfig->cpu_shares != 0) { chostconfig->cpu_shares = hostconfig->cpu_shares; } @@ -859,6 +892,9 @@ static void update_container_cpu(const host_config *hostconfig, host_config *cho if (hostconfig->cpu_realtime_runtime != 0) { chostconfig->cpu_realtime_runtime = hostconfig->cpu_realtime_runtime; } + +out: + return ret; } static int update_container_memory(const char *id, const host_config *hostconfig, host_config *chostconfig) @@ -932,7 +968,11 @@ static int update_container(const container_t *cont, const host_config *hostconf chostconfig->blkio_weight = hostconfig->blkio_weight; } - update_container_cpu(hostconfig, chostconfig); + ret = update_container_cpu(hostconfig, chostconfig); + if (ret != 0) { + ret = -1; + goto out; + } ret = update_container_memory(id, hostconfig, chostconfig); if (ret != 0) { diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c index 5fb8b90446b3b77ea7614f2789ccf62601702e92..f2df4f8f955cccf56f3263c18499eaf793f3c282 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c @@ -8,8 +8,8 @@ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR * PURPOSE. * See the Mulan PSL v2 for more details. - * Author: tanyifeng - * Create: 2017-11-22 + * Author: lifeng + * Create: 2020-04-22 * Description: provide image functions ******************************************************************************/ diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h index 58eae320ab6a0fb0643a45af3e03dac59688dd0a..dfa53ce3dac717bb236d17a844db25fdac2bb17e 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.h @@ -8,8 +8,8 @@ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR * PURPOSE. * See the Mulan PSL v2 for more details. - * Author: tanyifeng - * Create: 2019-04-02 + * Author: lifeng + * Create: 2020-04-22 * Description: provide graphdriver function definition ******************************************************************************/ #ifndef DAEMON_MODULES_IMAGE_OCI_STORAGE_LAYER_STORE_GRAPHDRIVER_DRIVER_H diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c index c81c4bcad0782415063376b614bb20ae6894d1bb..e9b1a7b2505efd0ffba89119721a9b6e670a1c96 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c @@ -8,8 +8,8 @@ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR * PURPOSE. * See the Mulan PSL v2 for more details. - * Author: tanyifeng - * Create: 2019-04-02 + * Author: lifeng + * Create: 2020-04-02 * Description: provide overlay2 function definition ******************************************************************************/ #include "driver_overlay2.h" diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h index 8e2c30b4ec133a3b1e4b83171896ac5dddd3ddcd..5f3228f0539a2eff122bb644bd43c614c153c5b4 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h @@ -8,7 +8,7 @@ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR * PURPOSE. * See the Mulan PSL v2 for more details. - * Author: tanyifeng + * Author: lifeng * Create: 2019-04-02 * Description: provide overlay2 function definition ******************************************************************************/ diff --git a/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c b/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c index 77a6a3d08644fcd358237b753aac500d574b9107..27c6a63197239f8038ff6c8a51c3192b9b8da491 100644 --- a/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c +++ b/src/daemon/modules/runtime/engines/lcr/lcr_rt_ops.c @@ -504,6 +504,9 @@ out: static void to_engine_resources(const host_config *hostconfig, struct engine_cgroup_resources *cr) { + uint64_t period = 0; + int64_t quota = 0; + if (hostconfig == NULL || cr == NULL) { return; } @@ -520,6 +523,13 @@ static void to_engine_resources(const host_config *hostconfig, struct engine_cgr cr->kernel_memory_limit = (uint64_t)hostconfig->kernel_memory; cr->cpurt_period = hostconfig->cpu_realtime_period; cr->cpurt_runtime = hostconfig->cpu_realtime_runtime; + + if (hostconfig->nano_cpus > 0) { + period = (uint64_t)(100 * Time_Milli / Time_Micro); + quota = hostconfig->nano_cpus * (int64_t)period / 1e9; + cr->cpu_period = period; + cr->cpu_quota = (uint64_t)quota; + } } int rt_lcr_update(const char *id, const char *runtime, const rt_update_params_t *params) diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c index 56ccce9c9faa71073774d51300f6bc3884c9ef35..b6dec5298e57a529ee565861fc4fb1b6e0375c8a 100644 --- a/src/daemon/modules/spec/specs.c +++ b/src/daemon/modules/spec/specs.c @@ -901,10 +901,39 @@ static int merge_hostname(oci_runtime_spec *oci_spec, const host_config *host_sp return 0; } +static int merge_nanocpus(oci_runtime_spec *oci_spec, int64_t nanocpus) +{ + int ret = 0; + uint64_t period = 0; + int64_t quota = 0; + + ret = make_sure_oci_spec_linux_resources_cpu(oci_spec); + if (ret < 0) { + goto out; + } + + period = (uint64_t)(100 * Time_Milli / Time_Micro); + quota = nanocpus * (int64_t)period / 1e9; + + oci_spec->linux->resources->cpu->quota = quota; + oci_spec->linux->resources->cpu->period = period; + +out: + return ret; +} + static int merge_conf_cgroup_cpu_int64(oci_runtime_spec *oci_spec, const host_config *host_spec) { int ret = 0; + if (host_spec->nano_cpus > 0) { + ret = merge_nanocpus(oci_spec, host_spec->nano_cpus); + if (ret != 0) { + ERROR("Failed to merge cgroup nano cpus"); + goto out; + } + } + /* cpu shares */ if (host_spec->cpu_shares != 0) { ret = merge_cpu_shares(oci_spec, host_spec->cpu_shares); diff --git a/src/daemon/modules/spec/verify.c b/src/daemon/modules/spec/verify.c index 04ac607513971676930a05d0e2313fd3c21b5fb3..8bd7e7e6cc034996708ae06c5522cef2b083b020 100644 --- a/src/daemon/modules/spec/verify.c +++ b/src/daemon/modules/spec/verify.c @@ -1724,10 +1724,58 @@ out: return ret; } +static int verify_nano_cpus(const sysinfo_t *sysinfo, const host_config *hostconfig) +{ + int ret = 0; + + if (hostconfig->nano_cpus == 0) { + return 0; + } + + if (hostconfig->nano_cpus > 0 && hostconfig->cpu_period > 0) { + ERROR("Conflicting options: Nano CPUs and CPU Period cannot both be set."); + isulad_set_error_message("Conflicting options: Nano CPUs and CPU Period cannot both be set."); + ret = -1; + goto out; + } + + if (hostconfig->nano_cpus > 0 && hostconfig->cpu_quota > 0) { + ERROR("Conflicting options: Nano CPUs and CPU Quota cannot both be set."); + isulad_set_error_message("Conflicting options: Nano CPUs and CPU Quota cannot both be set."); + ret = -1; + goto out; + } + + if (hostconfig->nano_cpus > 0 && (!(sysinfo->cgcpuinfo.cpu_cfs_quota) || !(sysinfo->cgcpuinfo.cpu_cfs_period))) { + ERROR("NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted."); + isulad_set_error_message( + "NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted."); + ret = -1; + goto out; + } + + if (hostconfig->nano_cpus < 0 || (hostconfig->nano_cpus > (sysinfo->ncpus * 1e9))) { + ERROR("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo->ncpus, + sysinfo->ncpus); + isulad_set_error_message("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", + sysinfo->ncpus, sysinfo->ncpus); + ret = -1; + goto out; + } + +out: + return ret; +} + static int host_config_settings_cpu(const sysinfo_t *sysinfo, const host_config *hostconfig) { int ret = 0; + ret = verify_nano_cpus(sysinfo, hostconfig); + if (ret != 0) { + goto out; + } + ret = verify_cpu_realtime(sysinfo, hostconfig->cpu_realtime_period, hostconfig->cpu_realtime_runtime); if (ret != 0) { goto out; diff --git a/src/utils/cutils/utils_string.c b/src/utils/cutils/utils_string.c index 6543021101ad2de937c86dbf4b85ac257d0e943b..bb116cccfefc380ada87f580ba03d2e6e1d10f4d 100644 --- a/src/utils/cutils/utils_string.c +++ b/src/utils/cutils/utils_string.c @@ -182,7 +182,7 @@ static int parse_unit_multiple(const char *unit, int64_t *mltpl) return -EINVAL; } -static int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted) +int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted) { long long int_size = 0; double float_size = 0; @@ -824,8 +824,7 @@ bool util_has_suffix(const char *str, const char *suffix) return true; } -int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, - size_t *unique_elements_len) +int util_string_array_unique(const char **elements, size_t length, char ***unique_elements, size_t *unique_elements_len) { int ret = 0; size_t i; diff --git a/src/utils/cutils/utils_string.h b/src/utils/cutils/utils_string.h index 4d48f72c60c16a525d48f8f6b47422793ec6c84e..95dd8e988b1568cb3a00aaef570ee9d389132183 100644 --- a/src/utils/cutils/utils_string.h +++ b/src/utils/cutils/utils_string.h @@ -81,9 +81,9 @@ int util_string_array_unique(const char **elements, size_t length, char ***uniqu int util_parse_bool_string(const char *str, bool *converted); +int util_parse_size_int_and_float(const char *numstr, int64_t mlt, int64_t *converted); #ifdef __cplusplus } #endif #endif // UTILS_CUTILS_UTILS_STRING_H -