Files
xen/tools/xl/xl_psr.c
T
Yi Sun 583906320b tools: implement new generic set value interface and MBA set value command
This patch implements new generic set value interfaces in libxc and libxl.
These interfaces are suitable for all allocation features. It also adds a
new MBA set value command in xl.

Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
2018-01-18 11:32:51 +00:00

797 lines
21 KiB
C

/*
* Copyright 2009-2017 Citrix Ltd and other contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
#include <ctype.h>
#include <inttypes.h>
#include <stdlib.h>
#include <unistd.h>
#include <libxl.h>
#include <libxl_utils.h>
#include <libxlutil.h>
#include "xl.h"
#include "xl_utils.h"
#include "xl_parse.h"
static int psr_cmt_hwinfo(void)
{
int rc;
int enabled;
uint32_t total_rmid;
printf("Cache Monitoring Technology (CMT):\n");
enabled = libxl_psr_cmt_enabled(ctx);
printf("%-16s: %s\n", "Enabled", enabled ? "1" : "0");
if (!enabled)
return 0;
rc = libxl_psr_cmt_get_total_rmid(ctx, &total_rmid);
if (rc) {
fprintf(stderr, "Failed to get max RMID value\n");
return rc;
}
printf("%-16s: %u\n", "Total RMID", total_rmid);
printf("Supported monitor types:\n");
if (libxl_psr_cmt_type_supported(ctx, LIBXL_PSR_CMT_TYPE_CACHE_OCCUPANCY))
printf("cache-occupancy\n");
if (libxl_psr_cmt_type_supported(ctx, LIBXL_PSR_CMT_TYPE_TOTAL_MEM_COUNT))
printf("total-mem-bandwidth\n");
if (libxl_psr_cmt_type_supported(ctx, LIBXL_PSR_CMT_TYPE_LOCAL_MEM_COUNT))
printf("local-mem-bandwidth\n");
return rc;
}
#define MBM_SAMPLE_RETRY_MAX 4
static int psr_cmt_get_mem_bandwidth(uint32_t domid,
libxl_psr_cmt_type type,
uint32_t socketid,
uint64_t *bandwidth_r)
{
uint64_t sample1, sample2;
uint64_t tsc1, tsc2;
int retry_attempts = 0;
int rc;
while (1) {
rc = libxl_psr_cmt_get_sample(ctx, domid, type, socketid,
&sample1, &tsc1);
if (rc < 0)
return rc;
usleep(10000);
rc = libxl_psr_cmt_get_sample(ctx, domid, type, socketid,
&sample2, &tsc2);
if (rc < 0)
return rc;
if (tsc2 <= tsc1)
return -1;
/*
* Hardware guarantees at most 1 overflow can happen if the duration
* between two samples is less than 1 second. Note that tsc returned
* from hypervisor is already-scaled time(ns).
*/
if (tsc2 - tsc1 < 1000000000 && sample2 >= sample1)
break;
if (retry_attempts < MBM_SAMPLE_RETRY_MAX) {
retry_attempts++;
} else {
fprintf(stderr, "event counter overflowed\n");
return -1;
}
}
*bandwidth_r = (sample2 - sample1) * 1000000000 / (tsc2 - tsc1) / 1024;
return 0;
}
static void psr_cmt_print_domain_info(libxl_dominfo *dominfo,
libxl_psr_cmt_type type,
libxl_bitmap *socketmap)
{
char *domain_name;
uint32_t socketid;
uint64_t monitor_data;
if (!libxl_psr_cmt_domain_attached(ctx, dominfo->domid))
return;
domain_name = libxl_domid_to_name(ctx, dominfo->domid);
printf("%-40s %5d", domain_name, dominfo->domid);
free(domain_name);
libxl_for_each_set_bit(socketid, *socketmap) {
switch (type) {
case LIBXL_PSR_CMT_TYPE_CACHE_OCCUPANCY:
if (!libxl_psr_cmt_get_sample(ctx, dominfo->domid, type, socketid,
&monitor_data, NULL))
printf("%13"PRIu64" KB", monitor_data / 1024);
break;
case LIBXL_PSR_CMT_TYPE_TOTAL_MEM_COUNT:
case LIBXL_PSR_CMT_TYPE_LOCAL_MEM_COUNT:
if (!psr_cmt_get_mem_bandwidth(dominfo->domid, type, socketid,
&monitor_data))
printf("%11"PRIu64" KB/s", monitor_data);
break;
default:
return;
}
}
printf("\n");
}
static int psr_cmt_show(libxl_psr_cmt_type type, uint32_t domid)
{
uint32_t i, socketid, total_rmid;
uint32_t l3_cache_size;
libxl_bitmap socketmap;
int rc, nr_domains;
if (!libxl_psr_cmt_enabled(ctx)) {
fprintf(stderr, "CMT is disabled in the system\n");
return -1;
}
if (!libxl_psr_cmt_type_supported(ctx, type)) {
fprintf(stderr, "Monitor type '%s' is not supported in the system\n",
libxl_psr_cmt_type_to_string(type));
return -1;
}
libxl_bitmap_init(&socketmap);
libxl_socket_bitmap_alloc(ctx, &socketmap, 0);
rc = libxl_get_online_socketmap(ctx, &socketmap);
if (rc < 0) {
fprintf(stderr, "Failed getting available sockets, rc: %d\n", rc);
goto out;
}
rc = libxl_psr_cmt_get_total_rmid(ctx, &total_rmid);
if (rc < 0) {
fprintf(stderr, "Failed to get max RMID value\n");
goto out;
}
printf("Total RMID: %d\n", total_rmid);
/* Header */
printf("%-40s %5s", "Name", "ID");
libxl_for_each_set_bit(socketid, socketmap)
printf("%14s %d", "Socket", socketid);
printf("\n");
if (type == LIBXL_PSR_CMT_TYPE_CACHE_OCCUPANCY) {
/* Total L3 cache size */
printf("%-46s", "Total L3 Cache Size");
libxl_for_each_set_bit(socketid, socketmap) {
rc = libxl_psr_cmt_get_l3_cache_size(ctx, socketid,
&l3_cache_size);
if (rc < 0) {
fprintf(stderr,
"Failed to get system l3 cache size for socket:%d\n",
socketid);
goto out;
}
printf("%13u KB", l3_cache_size);
}
printf("\n");
}
/* Each domain */
if (domid != INVALID_DOMID) {
libxl_dominfo dominfo;
libxl_dominfo_init(&dominfo);
if (libxl_domain_info(ctx, &dominfo, domid)) {
fprintf(stderr, "Failed to get domain info for %d\n", domid);
rc = -1;
goto out;
}
psr_cmt_print_domain_info(&dominfo, type, &socketmap);
libxl_dominfo_dispose(&dominfo);
}
else
{
libxl_dominfo *list;
if (!(list = libxl_list_domain(ctx, &nr_domains))) {
fprintf(stderr, "Failed to get domain info for domain list.\n");
rc = -1;
goto out;
}
for (i = 0; i < nr_domains; i++)
psr_cmt_print_domain_info(list + i, type, &socketmap);
libxl_dominfo_list_free(list, nr_domains);
}
out:
libxl_bitmap_dispose(&socketmap);
return rc;
}
int main_psr_cmt_attach(int argc, char **argv)
{
uint32_t domid;
int opt, ret = 0;
SWITCH_FOREACH_OPT(opt, "", NULL, "psr-cmt-attach", 1) {
/* No options */
}
domid = find_domain(argv[optind]);
ret = libxl_psr_cmt_attach(ctx, domid);
return ret;
}
int main_psr_cmt_detach(int argc, char **argv)
{
uint32_t domid;
int opt, ret = 0;
SWITCH_FOREACH_OPT(opt, "", NULL, "psr-cmt-detach", 1) {
/* No options */
}
domid = find_domain(argv[optind]);
ret = libxl_psr_cmt_detach(ctx, domid);
return ret;
}
int main_psr_cmt_show(int argc, char **argv)
{
int opt, ret = 0;
uint32_t domid;
libxl_psr_cmt_type type;
SWITCH_FOREACH_OPT(opt, "", NULL, "psr-cmt-show", 1) {
/* No options */
}
if (!strcmp(argv[optind], "cache-occupancy"))
type = LIBXL_PSR_CMT_TYPE_CACHE_OCCUPANCY;
else if (!strcmp(argv[optind], "total-mem-bandwidth"))
type = LIBXL_PSR_CMT_TYPE_TOTAL_MEM_COUNT;
else if (!strcmp(argv[optind], "local-mem-bandwidth"))
type = LIBXL_PSR_CMT_TYPE_LOCAL_MEM_COUNT;
else {
help("psr-cmt-show");
return 2;
}
if (optind + 1 >= argc)
domid = INVALID_DOMID;
else if (optind + 1 == argc - 1)
domid = find_domain(argv[optind + 1]);
else {
help("psr-cmt-show");
return 2;
}
ret = psr_cmt_show(type, domid);
return ret;
}
static int psr_l3_cat_hwinfo(void)
{
int rc;
unsigned int i, nr;
uint32_t l3_cache_size;
libxl_psr_cat_info *info;
rc = libxl_psr_cat_get_info(ctx, &info, &nr, 3);
if (rc)
return rc;
printf("Cache Allocation Technology (CAT):\n");
for (i = 0; i < nr; i++) {
rc = libxl_psr_cmt_get_l3_cache_size(ctx, info[i].id, &l3_cache_size);
if (rc) {
fprintf(stderr, "Failed to get l3 cache size for socket:%d\n",
info[i].id);
goto out;
}
printf("%-16s: %u\n", "Socket ID", info[i].id);
printf("%-16s: %uKB\n", "L3 Cache", l3_cache_size);
printf("%-16s: %s\n", "CDP Status",
info[i].cdp_enabled ? "Enabled" : "Disabled");
printf("%-16s: %u\n", "Maximum COS", info[i].cos_max);
printf("%-16s: %u\n", "CBM length", info[i].cbm_len);
printf("%-16s: %#llx\n", "Default CBM",
(1ull << info[i].cbm_len) - 1);
}
out:
libxl_psr_cat_info_list_free(info, nr);
return rc;
}
static void psr_print_one_domain_val_type(uint32_t domid,
libxl_psr_hw_info *info,
libxl_psr_type type)
{
uint64_t val;
if (!libxl_psr_get_val(ctx, domid, type, info->id, &val)) {
if (type == LIBXL_PSR_CBM_TYPE_MBA_THRTL && info->u.mba.linear)
printf("%16"PRIu64, val);
else
printf("%#16"PRIx64, val);
}
else
printf("%16s", "error");
}
static void psr_print_one_domain_val(uint32_t domid,
libxl_psr_hw_info *info,
libxl_psr_feat_type type,
unsigned int lvl)
{
char *domain_name;
domain_name = libxl_domid_to_name(ctx, domid);
printf("%5d%25s", domid, domain_name);
free(domain_name);
switch (type) {
case LIBXL_PSR_FEAT_TYPE_CAT:
switch (lvl) {
case 3:
if (!info->u.cat.cdp_enabled) {
psr_print_one_domain_val_type(domid, info,
LIBXL_PSR_CBM_TYPE_L3_CBM);
} else {
psr_print_one_domain_val_type(domid, info,
LIBXL_PSR_CBM_TYPE_L3_CBM_CODE);
psr_print_one_domain_val_type(domid, info,
LIBXL_PSR_CBM_TYPE_L3_CBM_DATA);
}
break;
case 2:
psr_print_one_domain_val_type(domid, info,
LIBXL_PSR_CBM_TYPE_L2_CBM);
break;
default:
printf("Input lvl %d is wrong!", lvl);
}
break;
case LIBXL_PSR_FEAT_TYPE_MBA:
psr_print_one_domain_val_type(domid, info,
LIBXL_PSR_CBM_TYPE_MBA_THRTL);
break;
}
printf("\n");
}
static int psr_print_domain_val(uint32_t domid,
libxl_psr_hw_info *info,
libxl_psr_feat_type type,
unsigned int lvl)
{
int i, nr_domains;
libxl_dominfo *list;
if (domid != INVALID_DOMID) {
psr_print_one_domain_val(domid, info, type, lvl);
return 0;
}
if (!(list = libxl_list_domain(ctx, &nr_domains))) {
fprintf(stderr, "Failed to get domain list for value display\n");
return EXIT_FAILURE;
}
for (i = 0; i < nr_domains; i++)
psr_print_one_domain_val(list[i].domid, info, type, lvl);
libxl_dominfo_list_free(list, nr_domains);
return 0;
}
static int psr_print_socket(uint32_t domid,
libxl_psr_hw_info *info,
libxl_psr_feat_type type,
unsigned int lvl)
{
printf("%-16s: %u\n", "Socket ID", info->id);
switch (type) {
case LIBXL_PSR_FEAT_TYPE_CAT:
{
int rc;
uint32_t l3_cache_size;
/* So far, CMT only supports L3 cache. */
if (lvl == 3) {
rc = libxl_psr_cmt_get_l3_cache_size(ctx, info->id, &l3_cache_size);
if (rc) {
fprintf(stderr, "Failed to get l3 cache size for socket:%d\n",
info->id);
return -1;
}
printf("%-16s: %uKB\n", "L3 Cache", l3_cache_size);
}
printf("%-16s: %#llx\n", "Default CBM",
(1ull << info->u.cat.cbm_len) - 1);
if (info->u.cat.cdp_enabled)
printf("%5s%25s%16s%16s\n", "ID", "NAME", "CBM (code)", "CBM (data)");
else
printf("%5s%25s%16s\n", "ID", "NAME", "CBM");
break;
}
case LIBXL_PSR_FEAT_TYPE_MBA:
printf("%-16s: %u\n", "Default THRTL", 0);
printf("%5s%25s%16s\n", "ID", "NAME", "THRTL");
break;
default:
fprintf(stderr, "Input feature type %d is wrong\n", type);
return EXIT_FAILURE;
}
return psr_print_domain_val(domid, info, type, lvl);
}
static int psr_val_show(uint32_t domid,
libxl_psr_feat_type type,
unsigned int lvl)
{
unsigned int i, nr;
int rc;
libxl_psr_hw_info *info;
switch (type) {
case LIBXL_PSR_FEAT_TYPE_CAT:
if (lvl != 2 && lvl != 3) {
fprintf(stderr, "Input lvl %d is wrong\n", lvl);
return EXIT_FAILURE;
}
break;
case LIBXL_PSR_FEAT_TYPE_MBA:
if (lvl) {
fprintf(stderr,
"Unexpected lvl parameter %d for MBA feature\n", lvl);
return EXIT_FAILURE;
}
break;
default:
fprintf(stderr, "Input feature type %d is wrong\n", type);
return EXIT_FAILURE;
}
rc = libxl_psr_get_hw_info(ctx, type, lvl, &nr, &info);
if (rc) {
fprintf(stderr, "Failed to get info\n");
return rc;
}
for (i = 0; i < nr; i++) {
rc = psr_print_socket(domid, info + i, type, lvl);
if (rc)
goto out;
}
out:
libxl_psr_hw_info_list_free(info, nr);
return rc;
}
static int psr_l2_cat_hwinfo(void)
{
int rc;
unsigned int i, nr;
libxl_psr_cat_info *info;
rc = libxl_psr_cat_get_info(ctx, &info, &nr, 2);
if (rc)
return rc;
printf("Cache Allocation Technology (CAT): L2\n");
for (i = 0; i < nr; i++) {
/* There is no CMT on L2 cache so far. */
printf("%-16s: %u\n", "Socket ID", info[i].id);
printf("%-16s: %u\n", "Maximum COS", info[i].cos_max);
printf("%-16s: %u\n", "CBM length", info[i].cbm_len);
printf("%-16s: %#llx\n", "Default CBM",
(1ull << info[i].cbm_len) - 1);
}
libxl_psr_cat_info_list_free(info, nr);
return rc;
}
int main_psr_mba_show(int argc, char **argv)
{
int opt;
uint32_t domid;
SWITCH_FOREACH_OPT(opt, "", NULL, "psr-mba-show", 0) {
/* No options */
}
if (optind >= argc)
domid = INVALID_DOMID;
else if (optind == argc - 1)
domid = find_domain(argv[optind]);
else {
help("psr-mba-show");
return 2;
}
return psr_val_show(domid, LIBXL_PSR_FEAT_TYPE_MBA, 0);
}
int main_psr_mba_set(int argc, char **argv)
{
uint32_t domid;
libxl_psr_type type;
uint64_t thrtl;
int ret, opt = 0;
libxl_bitmap target_map;
char *value;
libxl_string_list socket_list;
unsigned long start, end;
unsigned int i, j, len;
static const struct option opts[] = {
{"socket", 1, 0, 's'},
COMMON_LONG_OPTS
};
libxl_socket_bitmap_alloc(ctx, &target_map, 0);
libxl_bitmap_set_none(&target_map);
SWITCH_FOREACH_OPT(opt, "s:", opts, "psr-mba-set", 0) {
case 's':
trim(isspace, optarg, &value);
split_string_into_string_list(value, ",", &socket_list);
len = libxl_string_list_length(&socket_list);
for (i = 0; i < len; i++) {
parse_range(socket_list[i], &start, &end);
for (j = start; j <= end; j++)
libxl_bitmap_set(&target_map, j);
}
libxl_string_list_dispose(&socket_list);
free(value);
break;
}
type = LIBXL_PSR_CBM_TYPE_MBA_THRTL;
if (libxl_bitmap_is_empty(&target_map))
libxl_bitmap_set_any(&target_map);
if (argc != optind + 2) {
help("psr-mba-set");
return EXIT_FAILURE;
}
domid = find_domain(argv[optind]);
thrtl = strtoll(argv[optind + 1], NULL , 0);
ret = libxl_psr_set_val(ctx, domid, type, &target_map, thrtl);
libxl_bitmap_dispose(&target_map);
return ret;
}
static int psr_mba_hwinfo(void)
{
int rc;
unsigned int i, nr;
libxl_psr_hw_info *info;
rc = libxl_psr_get_hw_info(ctx, LIBXL_PSR_FEAT_TYPE_MBA, 0, &nr, &info);
if (rc)
return rc;
printf("Memory Bandwidth Allocation (MBA):\n");
for (i = 0; i < nr; i++) {
printf("Socket ID : %u\n", info[i].id);
printf("Linear Mode : %s\n",
info[i].u.mba.linear ? "Enabled" : "Disabled");
printf("Maximum COS : %u\n", info[i].u.mba.cos_max);
printf("Maximum Throttling Value: %u\n", info[i].u.mba.thrtl_max);
printf("Default Throttling Value: %u\n", 0);
}
libxl_psr_hw_info_list_free(info, nr);
return rc;
}
int main_psr_cat_cbm_set(int argc, char **argv)
{
uint32_t domid;
libxl_psr_cbm_type type;
uint64_t cbm;
int ret, opt = 0;
int opt_data = 0, opt_code = 0;
libxl_bitmap target_map;
char *value;
libxl_string_list socket_list;
unsigned long start, end;
unsigned int i, j, len;
unsigned int lvl = 3;
static struct option opts[] = {
{"socket", 1, 0, 's'},
{"data", 0, 0, 'd'},
{"code", 0, 0, 'c'},
{"level", 1, 0, 'l'},
COMMON_LONG_OPTS
};
libxl_socket_bitmap_alloc(ctx, &target_map, 0);
libxl_bitmap_set_none(&target_map);
SWITCH_FOREACH_OPT(opt, "s:l:cd", opts, "psr-cat-set", 2) {
case 's':
trim(isspace, optarg, &value);
split_string_into_string_list(value, ",", &socket_list);
len = libxl_string_list_length(&socket_list);
for (i = 0; i < len; i++) {
parse_range(socket_list[i], &start, &end);
for (j = start; j <= end; j++)
libxl_bitmap_set(&target_map, j);
}
libxl_string_list_dispose(&socket_list);
free(value);
break;
case 'd':
opt_data = 1;
break;
case 'c':
opt_code = 1;
break;
case 'l':
lvl = atoi(optarg);
break;
}
if (lvl == 2)
type = LIBXL_PSR_CBM_TYPE_L2_CBM;
else if (lvl == 3) {
if (opt_data && opt_code) {
fprintf(stderr, "Cannot handle -c and -d at the same time\n");
return EXIT_FAILURE;
} else if (opt_data) {
type = LIBXL_PSR_CBM_TYPE_L3_CBM_DATA;
} else if (opt_code) {
type = LIBXL_PSR_CBM_TYPE_L3_CBM_CODE;
} else {
type = LIBXL_PSR_CBM_TYPE_L3_CBM;
}
} else {
type = LIBXL_PSR_CBM_TYPE_L3_CBM;
fprintf(stderr, "Input lvl %d is wrong\n", lvl);
return EXIT_FAILURE;
}
if (libxl_bitmap_is_empty(&target_map))
libxl_bitmap_set_any(&target_map);
if (argc != optind + 2) {
help("psr-cat-set");
return 2;
}
domid = find_domain(argv[optind]);
cbm = strtoll(argv[optind + 1], NULL , 0);
ret = libxl_psr_cat_set_cbm(ctx, domid, type, &target_map, cbm);
libxl_bitmap_dispose(&target_map);
return ret;
}
int main_psr_cat_show(int argc, char **argv)
{
int opt = 0;
uint32_t domid;
unsigned int lvl = 3;
static struct option opts[] = {
{"level", 1, 0, 'l'},
COMMON_LONG_OPTS
};
SWITCH_FOREACH_OPT(opt, "l:", opts, "psr-cat-show", 0) {
case 'l':
lvl = atoi(optarg);
break;
}
if (optind >= argc)
domid = INVALID_DOMID;
else if (optind == argc - 1)
domid = find_domain(argv[optind]);
else {
help("psr-cat-show");
return 2;
}
return psr_val_show(domid, LIBXL_PSR_FEAT_TYPE_CAT, lvl);
}
int main_psr_hwinfo(int argc, char **argv)
{
int opt, ret = 0;
bool all = true, cmt = false, cat = false, mba = false;
static const struct option opts[] = {
{"cmt", 0, 0, 'm'},
{"cat", 0, 0, 'a'},
{"mba", 0, 0, 'b'},
COMMON_LONG_OPTS
};
SWITCH_FOREACH_OPT(opt, "mab", opts, "psr-hwinfo", 0) {
case 'm':
all = false; cmt = true;
break;
case 'a':
all = false; cat = true;
break;
case 'b':
all = false; mba = true;
break;
}
if (!ret && (all || cmt))
ret = psr_cmt_hwinfo();
if (!ret && (all || cat))
ret = psr_l3_cat_hwinfo();
/* L2 CAT is independent of CMT and L3 CAT */
if (all || cat)
ret = psr_l2_cat_hwinfo();
/* MBA is independent of CMT and CAT */
if (all || mba)
ret = psr_mba_hwinfo();
return ret;
}
/*
* Local variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/