* Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
* etmem/memRouter licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
* Author: liruilin
* Create: 2021-02-26
* Description: function of threshold policy
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <numaif.h>
#include <numa.h>
#include <json-c/json.h>
#include <json-c/json_util.h>
#include <json-c/json_object.h>
#include "memdcd_log.h"
#include "memdcd_policy.h"
#include "memdcd_process.h"
#include "memdcd_policy_threshold.h"
struct threshold_policy {
uint64_t threshold;
};
int threshold_policy_init(struct mem_policy *policy, const char *path);
int threshold_policy_parse(const struct mem_policy *policy, int pid, struct migrate_page_list *page_list,
struct migrate_page_list **pages_to_numa, struct migrate_page_list **pages_to_swap);
int threshold_policy_destroy(struct mem_policy *policy);
struct memdcd_policy_opt threshold_policy_opt = {
.init = threshold_policy_init,
.parse = threshold_policy_parse,
.destroy = threshold_policy_destroy,
};
int threshold_policy_init(struct mem_policy *policy, const char *path)
{
int ret = 0;
json_object *root = NULL, *obj_policy = NULL, *unit = NULL, *threshold = NULL;
int th_val = -1;
const char *str = NULL;
struct threshold_policy *t = (struct threshold_policy *)malloc(sizeof(struct threshold_policy));
if (t == NULL)
return -1;
root = json_object_from_file(path);
if (root == NULL) {
ret = -1;
goto err_out;
}
obj_policy = json_object_object_get(root, "policy");
if (obj_policy == NULL) {
ret = -1;
goto err_out;
}
unit = json_object_object_get(obj_policy, "unit");
if (unit == NULL) {
ret = -1;
goto err_out;
}
threshold = json_object_object_get(obj_policy, "threshold");
if (threshold == NULL) {
ret = -1;
goto err_out;
}
th_val = json_object_get_int(threshold);
if (th_val == INT32_MAX || th_val < 0) {
memdcd_log(_LOG_ERROR, "Invalid threshold value, allowed range is [0, INT_MAX).");
ret = -1;
goto err_out;
}
str = json_object_get_string(unit);
if (str == NULL) {
ret = -1;
goto err_out;
}
memdcd_log(_LOG_INFO, "Threshold policy loaded.");
if (strcmp("B", str) == 0) {
t->threshold = th_val;
} else if (strcmp("KB", str) == 0) {
t->threshold = (uint64_t)th_val * 1024;
} else if (strcmp("MB", str) == 0) {
t->threshold = (uint64_t)th_val * 1024 * 1024;
} else if (strcmp("GB", str) == 0) {
t->threshold = (uint64_t)th_val * 1024 * 1024 * 1024;
} else {
memdcd_log(_LOG_ERROR, "Detected invalid threshold setting. Abort.");
ret = -1;
goto err_out;
}
policy->type = POL_TYPE_THRESHOLD;
policy->opt = &threshold_policy_opt;
policy->private = t;
return 0;
err_out:
free(t);
return ret;
}
static int addr_cmp_by_count(const void *a, const void *b)
{
return ((struct migrate_page *)a)->visit_count - ((struct migrate_page *)b)->visit_count;
}
int threshold_policy_parse(const struct mem_policy *policy, int pid, struct migrate_page_list *page_list,
struct migrate_page_list **pages_to_numa, struct migrate_page_list **pages_to_swap)
{
int ret = 0;
uint64_t swap_count = 0;
uint64_t sum_size = 0;
int *status = NULL;
uint64_t *move_addr = NULL;
uint64_t length = page_list->length;
(void)pages_to_numa;
qsort(page_list->pages, length, sizeof(struct migrate_page), addr_cmp_by_count);
status = malloc(sizeof(int) * length);
if (status == NULL)
return -1;
move_addr = malloc(sizeof(uint64_t) * length);
if (move_addr == NULL) {
free(status);
return -1;
}
for (uint64_t i = 0; i < length; i++)
move_addr[i] = page_list->pages[i].addr;
if (move_pages(pid, length, (void **)move_addr, NULL, status, MPOL_MF_MOVE) < 0) {
memdcd_log(_LOG_ERROR, "Error when locate node for src_addr by move_page.");
ret = -1;
goto tpp_err_out;
}
for (int64_t i = length - 1; i >= 0; i--) {
page_list->pages[i].numanode = status[i];
if (status[i] < 0) {
memdcd_log(_LOG_DEBUG, "memdcd_migrate: Error getting current node of page %lx: %d, %ld.",
move_addr[i], status[i], i);
continue;
}
if (sum_size + page_list->pages[i].length < sum_size) {
ret = -1;
goto tpp_err_out;
}
sum_size += page_list->pages[i].length;
if (sum_size < ((struct threshold_policy *)policy->private)->threshold)
continue;
swap_count++;
page_list->pages[length - swap_count] = page_list->pages[i];
}
*pages_to_swap = malloc(sizeof(struct migrate_page) * swap_count + sizeof(struct migrate_page_list));
if (*pages_to_swap == NULL) {
memdcd_log(_LOG_ERROR, "memdcd_migrate: error allocating space for pages_to_swap.");
ret = -1;
goto tpp_err_out;
}
memcpy((*pages_to_swap)->pages, page_list->pages + length - swap_count, sizeof(struct migrate_page) * swap_count);
(*pages_to_swap)->length = swap_count;
tpp_err_out:
free(status);
free(move_addr);
return ret;
}
int threshold_policy_destroy(struct mem_policy *policy)
{
if (policy == NULL) {
return -1;
}
if (policy->private == NULL) {
return -1;
}
free(policy->private);
policy->private = NULL;
return 0;
}
struct memdcd_policy_opt *get_threshold_policy(void)
{
return &threshold_policy_opt;
}