* statistics subsystem
* virtio reset cleanups * build system cleanups * fix Cirrus CI -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmKpooQUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroNlFwf+OugLGRZl3KVc7akQwUJe9gg2T31h VkC+7Tei8FAwe8vDppVd+CYEIi0M3acxD2amRrv2etCCGSuySN1PbkfRcSfPBX01 pRWpasdhfqnZR8Iidi7YW1Ou5CcGqKH49nunBhW10+osb/mu5sVscMuOJgTDj/lK CpsmDyk6572yGmczjNLlmhYcTU36clHpAZgazZHwk1PU+B3fCKlYYyvUpT3ItJvd cK92aIUWrfofl3yTy0k4IwvZwNjTBirlstOIomZ333xzSA+mm5TR+mTvGRTZ69+a v+snpMp4ILDMoB5kxQ42kK5WpdiN//LnriA9CBFDtOidsDDn8kx7gJe2RA== =Dxwa -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * statistics subsystem * virtio reset cleanups * build system cleanups * fix Cirrus CI # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmKpooQUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroNlFwf+OugLGRZl3KVc7akQwUJe9gg2T31h # VkC+7Tei8FAwe8vDppVd+CYEIi0M3acxD2amRrv2etCCGSuySN1PbkfRcSfPBX01 # pRWpasdhfqnZR8Iidi7YW1Ou5CcGqKH49nunBhW10+osb/mu5sVscMuOJgTDj/lK # CpsmDyk6572yGmczjNLlmhYcTU36clHpAZgazZHwk1PU+B3fCKlYYyvUpT3ItJvd # cK92aIUWrfofl3yTy0k4IwvZwNjTBirlstOIomZ333xzSA+mm5TR+mTvGRTZ69+a # v+snpMp4ILDMoB5kxQ42kK5WpdiN//LnriA9CBFDtOidsDDn8kx7gJe2RA== # =Dxwa # -----END PGP SIGNATURE----- # gpg: Signature made Wed 15 Jun 2022 02:12:36 AM PDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [undefined] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (21 commits) build: include pc-bios/ part in the ROMS variable meson: put cross compiler info in a separate section q35:Enable TSEG only when G_SMRAME and TSEG_EN both enabled build: fix check for -fsanitize-coverage-allowlist tests/vm: allow running tests in an unconfigured source tree configure: cleanup -fno-pie detection configure: update list of preserved environment variables virtio-mmio: cleanup reset virtio: stop ioeventfd on reset virtio-mmio: stop ioeventfd on legacy reset s390x: simplify virtio_ccw_reset_virtio block: add more commands to preconfig mode hmp: add filtering of statistics by name qmp: add filtering of statistics by name hmp: add filtering of statistics by provider qmp: add filtering of statistics by provider hmp: add basic "info stats" implementation cutils: add functions for IEC and SI prefixes qmp: add filtering of statistics by target vCPU kvm: Support for querying fd-based stats ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
def6fd6c9c
12
Makefile
12
Makefile
@ -186,16 +186,14 @@ include $(SRC_PATH)/tests/Makefile.include
|
||||
|
||||
all: recurse-all
|
||||
|
||||
ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
|
||||
ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS)))
|
||||
# Only keep -O and -g cflags
|
||||
.PHONY: $(ROM_DIRS_RULES)
|
||||
$(ROM_DIRS_RULES):
|
||||
ROMS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROMS)))
|
||||
.PHONY: $(ROMS_RULES)
|
||||
$(ROMS_RULES):
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
|
||||
|
||||
.PHONY: recurse-all recurse-clean
|
||||
recurse-all: $(addsuffix /all, $(ROM_DIRS))
|
||||
recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
|
||||
recurse-all: $(addsuffix /all, $(ROMS))
|
||||
recurse-clean: $(addsuffix /clean, $(ROMS))
|
||||
|
||||
######################################################################
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "kvm-cpus.h"
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "monitor/stats.h"
|
||||
|
||||
/* This check must be after config-host.h is included */
|
||||
#ifdef CONFIG_EVENTFD
|
||||
@ -2310,6 +2311,10 @@ bool kvm_dirty_ring_enabled(void)
|
||||
return kvm_state->kvm_dirty_ring_size ? true : false;
|
||||
}
|
||||
|
||||
static void query_stats_cb(StatsResultList **result, StatsTarget target,
|
||||
strList *names, strList *targets, Error **errp);
|
||||
static void query_stats_schemas_cb(StatsSchemaList **result, Error **errp);
|
||||
|
||||
static int kvm_init(MachineState *ms)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
@ -2638,6 +2643,11 @@ static int kvm_init(MachineState *ms)
|
||||
}
|
||||
}
|
||||
|
||||
if (kvm_check_extension(kvm_state, KVM_CAP_BINARY_STATS_FD)) {
|
||||
add_stats_callbacks(STATS_PROVIDER_KVM, query_stats_cb,
|
||||
query_stats_schemas_cb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -3697,3 +3707,396 @@ static void kvm_type_init(void)
|
||||
}
|
||||
|
||||
type_init(kvm_type_init);
|
||||
|
||||
typedef struct StatsArgs {
|
||||
union StatsResultsType {
|
||||
StatsResultList **stats;
|
||||
StatsSchemaList **schema;
|
||||
} result;
|
||||
strList *names;
|
||||
Error **errp;
|
||||
} StatsArgs;
|
||||
|
||||
static StatsList *add_kvmstat_entry(struct kvm_stats_desc *pdesc,
|
||||
uint64_t *stats_data,
|
||||
StatsList *stats_list,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
Stats *stats;
|
||||
uint64List *val_list = NULL;
|
||||
|
||||
/* Only add stats that we understand. */
|
||||
switch (pdesc->flags & KVM_STATS_TYPE_MASK) {
|
||||
case KVM_STATS_TYPE_CUMULATIVE:
|
||||
case KVM_STATS_TYPE_INSTANT:
|
||||
case KVM_STATS_TYPE_PEAK:
|
||||
case KVM_STATS_TYPE_LINEAR_HIST:
|
||||
case KVM_STATS_TYPE_LOG_HIST:
|
||||
break;
|
||||
default:
|
||||
return stats_list;
|
||||
}
|
||||
|
||||
switch (pdesc->flags & KVM_STATS_UNIT_MASK) {
|
||||
case KVM_STATS_UNIT_NONE:
|
||||
case KVM_STATS_UNIT_BYTES:
|
||||
case KVM_STATS_UNIT_CYCLES:
|
||||
case KVM_STATS_UNIT_SECONDS:
|
||||
break;
|
||||
default:
|
||||
return stats_list;
|
||||
}
|
||||
|
||||
switch (pdesc->flags & KVM_STATS_BASE_MASK) {
|
||||
case KVM_STATS_BASE_POW10:
|
||||
case KVM_STATS_BASE_POW2:
|
||||
break;
|
||||
default:
|
||||
return stats_list;
|
||||
}
|
||||
|
||||
/* Alloc and populate data list */
|
||||
stats = g_new0(Stats, 1);
|
||||
stats->name = g_strdup(pdesc->name);
|
||||
stats->value = g_new0(StatsValue, 1);;
|
||||
|
||||
if (pdesc->size == 1) {
|
||||
stats->value->u.scalar = *stats_data;
|
||||
stats->value->type = QTYPE_QNUM;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < pdesc->size; i++) {
|
||||
QAPI_LIST_PREPEND(val_list, stats_data[i]);
|
||||
}
|
||||
stats->value->u.list = val_list;
|
||||
stats->value->type = QTYPE_QLIST;
|
||||
}
|
||||
|
||||
QAPI_LIST_PREPEND(stats_list, stats);
|
||||
return stats_list;
|
||||
}
|
||||
|
||||
static StatsSchemaValueList *add_kvmschema_entry(struct kvm_stats_desc *pdesc,
|
||||
StatsSchemaValueList *list,
|
||||
Error **errp)
|
||||
{
|
||||
StatsSchemaValueList *schema_entry = g_new0(StatsSchemaValueList, 1);
|
||||
schema_entry->value = g_new0(StatsSchemaValue, 1);
|
||||
|
||||
switch (pdesc->flags & KVM_STATS_TYPE_MASK) {
|
||||
case KVM_STATS_TYPE_CUMULATIVE:
|
||||
schema_entry->value->type = STATS_TYPE_CUMULATIVE;
|
||||
break;
|
||||
case KVM_STATS_TYPE_INSTANT:
|
||||
schema_entry->value->type = STATS_TYPE_INSTANT;
|
||||
break;
|
||||
case KVM_STATS_TYPE_PEAK:
|
||||
schema_entry->value->type = STATS_TYPE_PEAK;
|
||||
break;
|
||||
case KVM_STATS_TYPE_LINEAR_HIST:
|
||||
schema_entry->value->type = STATS_TYPE_LINEAR_HISTOGRAM;
|
||||
schema_entry->value->bucket_size = pdesc->bucket_size;
|
||||
schema_entry->value->has_bucket_size = true;
|
||||
break;
|
||||
case KVM_STATS_TYPE_LOG_HIST:
|
||||
schema_entry->value->type = STATS_TYPE_LOG2_HISTOGRAM;
|
||||
break;
|
||||
default:
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch (pdesc->flags & KVM_STATS_UNIT_MASK) {
|
||||
case KVM_STATS_UNIT_NONE:
|
||||
break;
|
||||
case KVM_STATS_UNIT_BYTES:
|
||||
schema_entry->value->has_unit = true;
|
||||
schema_entry->value->unit = STATS_UNIT_BYTES;
|
||||
break;
|
||||
case KVM_STATS_UNIT_CYCLES:
|
||||
schema_entry->value->has_unit = true;
|
||||
schema_entry->value->unit = STATS_UNIT_CYCLES;
|
||||
break;
|
||||
case KVM_STATS_UNIT_SECONDS:
|
||||
schema_entry->value->has_unit = true;
|
||||
schema_entry->value->unit = STATS_UNIT_SECONDS;
|
||||
break;
|
||||
default:
|
||||
goto exit;
|
||||
}
|
||||
|
||||
schema_entry->value->exponent = pdesc->exponent;
|
||||
if (pdesc->exponent) {
|
||||
switch (pdesc->flags & KVM_STATS_BASE_MASK) {
|
||||
case KVM_STATS_BASE_POW10:
|
||||
schema_entry->value->has_base = true;
|
||||
schema_entry->value->base = 10;
|
||||
break;
|
||||
case KVM_STATS_BASE_POW2:
|
||||
schema_entry->value->has_base = true;
|
||||
schema_entry->value->base = 2;
|
||||
break;
|
||||
default:
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
schema_entry->value->name = g_strdup(pdesc->name);
|
||||
schema_entry->next = list;
|
||||
return schema_entry;
|
||||
exit:
|
||||
g_free(schema_entry->value);
|
||||
g_free(schema_entry);
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Cached stats descriptors */
|
||||
typedef struct StatsDescriptors {
|
||||
const char *ident; /* cache key, currently the StatsTarget */
|
||||
struct kvm_stats_desc *kvm_stats_desc;
|
||||
struct kvm_stats_header *kvm_stats_header;
|
||||
QTAILQ_ENTRY(StatsDescriptors) next;
|
||||
} StatsDescriptors;
|
||||
|
||||
static QTAILQ_HEAD(, StatsDescriptors) stats_descriptors =
|
||||
QTAILQ_HEAD_INITIALIZER(stats_descriptors);
|
||||
|
||||
/*
|
||||
* Return the descriptors for 'target', that either have already been read
|
||||
* or are retrieved from 'stats_fd'.
|
||||
*/
|
||||
static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd,
|
||||
Error **errp)
|
||||
{
|
||||
StatsDescriptors *descriptors;
|
||||
const char *ident;
|
||||
struct kvm_stats_desc *kvm_stats_desc;
|
||||
struct kvm_stats_header *kvm_stats_header;
|
||||
size_t size_desc;
|
||||
ssize_t ret;
|
||||
|
||||
ident = StatsTarget_str(target);
|
||||
QTAILQ_FOREACH(descriptors, &stats_descriptors, next) {
|
||||
if (g_str_equal(descriptors->ident, ident)) {
|
||||
return descriptors;
|
||||
}
|
||||
}
|
||||
|
||||
descriptors = g_new0(StatsDescriptors, 1);
|
||||
|
||||
/* Read stats header */
|
||||
kvm_stats_header = g_malloc(sizeof(*kvm_stats_header));
|
||||
ret = read(stats_fd, kvm_stats_header, sizeof(*kvm_stats_header));
|
||||
if (ret != sizeof(*kvm_stats_header)) {
|
||||
error_setg(errp, "KVM stats: failed to read stats header: "
|
||||
"expected %zu actual %zu",
|
||||
sizeof(*kvm_stats_header), ret);
|
||||
return NULL;
|
||||
}
|
||||
size_desc = sizeof(*kvm_stats_desc) + kvm_stats_header->name_size;
|
||||
|
||||
/* Read stats descriptors */
|
||||
kvm_stats_desc = g_malloc0_n(kvm_stats_header->num_desc, size_desc);
|
||||
ret = pread(stats_fd, kvm_stats_desc,
|
||||
size_desc * kvm_stats_header->num_desc,
|
||||
kvm_stats_header->desc_offset);
|
||||
|
||||
if (ret != size_desc * kvm_stats_header->num_desc) {
|
||||
error_setg(errp, "KVM stats: failed to read stats descriptors: "
|
||||
"expected %zu actual %zu",
|
||||
size_desc * kvm_stats_header->num_desc, ret);
|
||||
g_free(descriptors);
|
||||
g_free(kvm_stats_desc);
|
||||
return NULL;
|
||||
}
|
||||
descriptors->kvm_stats_header = kvm_stats_header;
|
||||
descriptors->kvm_stats_desc = kvm_stats_desc;
|
||||
descriptors->ident = ident;
|
||||
QTAILQ_INSERT_TAIL(&stats_descriptors, descriptors, next);
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
static void query_stats(StatsResultList **result, StatsTarget target,
|
||||
strList *names, int stats_fd, Error **errp)
|
||||
{
|
||||
struct kvm_stats_desc *kvm_stats_desc;
|
||||
struct kvm_stats_header *kvm_stats_header;
|
||||
StatsDescriptors *descriptors;
|
||||
g_autofree uint64_t *stats_data = NULL;
|
||||
struct kvm_stats_desc *pdesc;
|
||||
StatsList *stats_list = NULL;
|
||||
size_t size_desc, size_data = 0;
|
||||
ssize_t ret;
|
||||
int i;
|
||||
|
||||
descriptors = find_stats_descriptors(target, stats_fd, errp);
|
||||
if (!descriptors) {
|
||||
return;
|
||||
}
|
||||
|
||||
kvm_stats_header = descriptors->kvm_stats_header;
|
||||
kvm_stats_desc = descriptors->kvm_stats_desc;
|
||||
size_desc = sizeof(*kvm_stats_desc) + kvm_stats_header->name_size;
|
||||
|
||||
/* Tally the total data size; read schema data */
|
||||
for (i = 0; i < kvm_stats_header->num_desc; ++i) {
|
||||
pdesc = (void *)kvm_stats_desc + i * size_desc;
|
||||
size_data += pdesc->size * sizeof(*stats_data);
|
||||
}
|
||||
|
||||
stats_data = g_malloc0(size_data);
|
||||
ret = pread(stats_fd, stats_data, size_data, kvm_stats_header->data_offset);
|
||||
|
||||
if (ret != size_data) {
|
||||
error_setg(errp, "KVM stats: failed to read data: "
|
||||
"expected %zu actual %zu", size_data, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < kvm_stats_header->num_desc; ++i) {
|
||||
uint64_t *stats;
|
||||
pdesc = (void *)kvm_stats_desc + i * size_desc;
|
||||
|
||||
/* Add entry to the list */
|
||||
stats = (void *)stats_data + pdesc->offset;
|
||||
if (!apply_str_list_filter(pdesc->name, names)) {
|
||||
continue;
|
||||
}
|
||||
stats_list = add_kvmstat_entry(pdesc, stats, stats_list, errp);
|
||||
}
|
||||
|
||||
if (!stats_list) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (target) {
|
||||
case STATS_TARGET_VM:
|
||||
add_stats_entry(result, STATS_PROVIDER_KVM, NULL, stats_list);
|
||||
break;
|
||||
case STATS_TARGET_VCPU:
|
||||
add_stats_entry(result, STATS_PROVIDER_KVM,
|
||||
current_cpu->parent_obj.canonical_path,
|
||||
stats_list);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void query_stats_schema(StatsSchemaList **result, StatsTarget target,
|
||||
int stats_fd, Error **errp)
|
||||
{
|
||||
struct kvm_stats_desc *kvm_stats_desc;
|
||||
struct kvm_stats_header *kvm_stats_header;
|
||||
StatsDescriptors *descriptors;
|
||||
struct kvm_stats_desc *pdesc;
|
||||
StatsSchemaValueList *stats_list = NULL;
|
||||
size_t size_desc;
|
||||
int i;
|
||||
|
||||
descriptors = find_stats_descriptors(target, stats_fd, errp);
|
||||
if (!descriptors) {
|
||||
return;
|
||||
}
|
||||
|
||||
kvm_stats_header = descriptors->kvm_stats_header;
|
||||
kvm_stats_desc = descriptors->kvm_stats_desc;
|
||||
size_desc = sizeof(*kvm_stats_desc) + kvm_stats_header->name_size;
|
||||
|
||||
/* Tally the total data size; read schema data */
|
||||
for (i = 0; i < kvm_stats_header->num_desc; ++i) {
|
||||
pdesc = (void *)kvm_stats_desc + i * size_desc;
|
||||
stats_list = add_kvmschema_entry(pdesc, stats_list, errp);
|
||||
}
|
||||
|
||||
add_stats_schema(result, STATS_PROVIDER_KVM, target, stats_list);
|
||||
}
|
||||
|
||||
static void query_stats_vcpu(CPUState *cpu, run_on_cpu_data data)
|
||||
{
|
||||
StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr;
|
||||
int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (stats_fd == -1) {
|
||||
error_setg_errno(&local_err, errno, "KVM stats: ioctl failed");
|
||||
error_propagate(kvm_stats_args->errp, local_err);
|
||||
return;
|
||||
}
|
||||
query_stats(kvm_stats_args->result.stats, STATS_TARGET_VCPU,
|
||||
kvm_stats_args->names, stats_fd, kvm_stats_args->errp);
|
||||
close(stats_fd);
|
||||
}
|
||||
|
||||
static void query_stats_schema_vcpu(CPUState *cpu, run_on_cpu_data data)
|
||||
{
|
||||
StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr;
|
||||
int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (stats_fd == -1) {
|
||||
error_setg_errno(&local_err, errno, "KVM stats: ioctl failed");
|
||||
error_propagate(kvm_stats_args->errp, local_err);
|
||||
return;
|
||||
}
|
||||
query_stats_schema(kvm_stats_args->result.schema, STATS_TARGET_VCPU, stats_fd,
|
||||
kvm_stats_args->errp);
|
||||
close(stats_fd);
|
||||
}
|
||||
|
||||
static void query_stats_cb(StatsResultList **result, StatsTarget target,
|
||||
strList *names, strList *targets, Error **errp)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
CPUState *cpu;
|
||||
int stats_fd;
|
||||
|
||||
switch (target) {
|
||||
case STATS_TARGET_VM:
|
||||
{
|
||||
stats_fd = kvm_vm_ioctl(s, KVM_GET_STATS_FD, NULL);
|
||||
if (stats_fd == -1) {
|
||||
error_setg_errno(errp, errno, "KVM stats: ioctl failed");
|
||||
return;
|
||||
}
|
||||
query_stats(result, target, names, stats_fd, errp);
|
||||
close(stats_fd);
|
||||
break;
|
||||
}
|
||||
case STATS_TARGET_VCPU:
|
||||
{
|
||||
StatsArgs stats_args;
|
||||
stats_args.result.stats = result;
|
||||
stats_args.names = names;
|
||||
stats_args.errp = errp;
|
||||
CPU_FOREACH(cpu) {
|
||||
if (!apply_str_list_filter(cpu->parent_obj.canonical_path, targets)) {
|
||||
continue;
|
||||
}
|
||||
run_on_cpu(cpu, query_stats_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void query_stats_schemas_cb(StatsSchemaList **result, Error **errp)
|
||||
{
|
||||
StatsArgs stats_args;
|
||||
KVMState *s = kvm_state;
|
||||
int stats_fd;
|
||||
|
||||
stats_fd = kvm_vm_ioctl(s, KVM_GET_STATS_FD, NULL);
|
||||
if (stats_fd == -1) {
|
||||
error_setg_errno(errp, errno, "KVM stats: ioctl failed");
|
||||
return;
|
||||
}
|
||||
query_stats_schema(result, STATS_TARGET_VM, stats_fd, errp);
|
||||
close(stats_fd);
|
||||
|
||||
stats_args.result.schema = result;
|
||||
stats_args.errp = errp;
|
||||
run_on_cpu(first_cpu, query_stats_schema_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args));
|
||||
}
|
||||
|
22
configure
vendored
22
configure
vendored
@ -1351,13 +1351,6 @@ static THREAD int tls_var;
|
||||
int main(void) { return tls_var; }
|
||||
EOF
|
||||
|
||||
# Check we support -fno-pie and -no-pie first; we will need the former for
|
||||
# building ROMs, and both for everything if --disable-pie is passed.
|
||||
if compile_prog "-Werror -fno-pie" "-no-pie"; then
|
||||
CFLAGS_NOPIE="-fno-pie"
|
||||
LDFLAGS_NOPIE="-no-pie"
|
||||
fi
|
||||
|
||||
if test "$static" = "yes"; then
|
||||
if test "$pie" != "no" && compile_prog "-Werror -fPIE -DPIE" "-static-pie"; then
|
||||
CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS"
|
||||
@ -1370,8 +1363,10 @@ if test "$static" = "yes"; then
|
||||
pie="no"
|
||||
fi
|
||||
elif test "$pie" = "no"; then
|
||||
CONFIGURE_CFLAGS="$CFLAGS_NOPIE $CONFIGURE_CFLAGS"
|
||||
CONFIGURE_LDFLAGS="$LDFLAGS_NOPIE $CONFIGURE_LDFLAGS"
|
||||
if compile_prog "-Werror -fno-pie" "-no-pie"; then
|
||||
CONFIGURE_CFLAGS="-fno-pie $CONFIGURE_CFLAGS"
|
||||
CONFIGURE_LDFLAGS="-no-pie $CONFIGURE_LDFLAGS"
|
||||
fi
|
||||
elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then
|
||||
CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS"
|
||||
CONFIGURE_LDFLAGS="-pie $CONFIGURE_LDFLAGS"
|
||||
@ -2257,7 +2252,7 @@ if test -n "$target_cc" &&
|
||||
fi
|
||||
done
|
||||
if test -n "$ld_i386_emulation"; then
|
||||
roms="optionrom"
|
||||
roms="pc-bios/optionrom"
|
||||
config_mak=pc-bios/optionrom/config.mak
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "TOPSRC_DIR=$source_path" >> $config_mak
|
||||
@ -2268,7 +2263,7 @@ fi
|
||||
|
||||
probe_target_compilers ppc ppc64
|
||||
if test -n "$target_cc" && test "$softmmu" = yes; then
|
||||
roms="$roms vof"
|
||||
roms="$roms pc-bios/vof"
|
||||
config_mak=pc-bios/vof/config.mak
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "SRC_DIR=$source_path/pc-bios/vof" >> $config_mak
|
||||
@ -2287,7 +2282,7 @@ if test -n "$target_cc" && test "$softmmu" = yes; then
|
||||
echo "WARNING: Your compiler does not support the z900!"
|
||||
echo " The s390-ccw bios will only work with guest CPUs >= z10."
|
||||
fi
|
||||
roms="$roms s390-ccw"
|
||||
roms="$roms pc-bios/s390-ccw"
|
||||
config_mak=pc-bios/s390-ccw/config-host.mak
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
echo "SRC_PATH=$source_path/pc-bios/s390-ccw" >> $config_mak
|
||||
@ -2739,13 +2734,12 @@ preserve_env CC
|
||||
preserve_env CFLAGS
|
||||
preserve_env CXX
|
||||
preserve_env CXXFLAGS
|
||||
preserve_env INSTALL
|
||||
preserve_env LD
|
||||
preserve_env LDFLAGS
|
||||
preserve_env LD_LIBRARY_PATH
|
||||
preserve_env LIBTOOL
|
||||
preserve_env MAKE
|
||||
preserve_env NM
|
||||
preserve_env OBJCFLAGS
|
||||
preserve_env OBJCOPY
|
||||
preserve_env PATH
|
||||
preserve_env PKG_CONFIG
|
||||
|
@ -894,3 +894,17 @@ SRST
|
||||
``info via``
|
||||
Show guest mos6522 VIA devices.
|
||||
ERST
|
||||
|
||||
{
|
||||
.name = "stats",
|
||||
.args_type = "target:s,names:s?,provider:s?",
|
||||
.params = "target [names] [provider]",
|
||||
.help = "show statistics for the given target (vm or vcpu); optionally filter by"
|
||||
"name (comma-separated list, or * for all) and provider",
|
||||
.cmd = hmp_info_stats,
|
||||
},
|
||||
|
||||
SRST
|
||||
``stats``
|
||||
Show runtime-collected statistics
|
||||
ERST
|
||||
|
@ -78,6 +78,7 @@ ERST
|
||||
.help = "resize a block image",
|
||||
.cmd = hmp_block_resize,
|
||||
.coroutine = true,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -94,6 +95,7 @@ ERST
|
||||
.params = "device [speed [base]]",
|
||||
.help = "copy data from a backing file into a block device",
|
||||
.cmd = hmp_block_stream,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -107,6 +109,7 @@ ERST
|
||||
.params = "device speed",
|
||||
.help = "set maximum speed for a background block operation",
|
||||
.cmd = hmp_block_job_set_speed,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -122,6 +125,7 @@ ERST
|
||||
"\n\t\t\t if you want to abort the operation immediately"
|
||||
"\n\t\t\t instead of keep running until data is in sync)",
|
||||
.cmd = hmp_block_job_cancel,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -135,6 +139,7 @@ ERST
|
||||
.params = "device",
|
||||
.help = "stop an active background block operation",
|
||||
.cmd = hmp_block_job_complete,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -149,6 +154,7 @@ ERST
|
||||
.params = "device",
|
||||
.help = "pause an active background block operation",
|
||||
.cmd = hmp_block_job_pause,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -162,6 +168,7 @@ ERST
|
||||
.params = "device",
|
||||
.help = "resume a paused background block operation",
|
||||
.cmd = hmp_block_job_resume,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -1406,6 +1413,7 @@ ERST
|
||||
.params = "nbd_server_start [-a] [-w] host:port",
|
||||
.help = "serve block devices on the given host and port",
|
||||
.cmd = hmp_nbd_server_start,
|
||||
.flags = "p",
|
||||
},
|
||||
SRST
|
||||
``nbd_server_start`` *host*:*port*
|
||||
@ -1421,6 +1429,7 @@ ERST
|
||||
.params = "nbd_server_add [-w] device [name]",
|
||||
.help = "export a block device via NBD",
|
||||
.cmd = hmp_nbd_server_add,
|
||||
.flags = "p",
|
||||
},
|
||||
SRST
|
||||
``nbd_server_add`` *device* [ *name* ]
|
||||
@ -1436,6 +1445,7 @@ ERST
|
||||
.params = "nbd_server_remove [-f] name",
|
||||
.help = "remove an export previously exposed via NBD",
|
||||
.cmd = hmp_nbd_server_remove,
|
||||
.flags = "p",
|
||||
},
|
||||
SRST
|
||||
``nbd_server_remove [-f]`` *name*
|
||||
@ -1452,6 +1462,7 @@ ERST
|
||||
.params = "nbd_server_stop",
|
||||
.help = "stop serving block devices using the NBD protocol",
|
||||
.cmd = hmp_nbd_server_stop,
|
||||
.flags = "p",
|
||||
},
|
||||
SRST
|
||||
``nbd_server_stop``
|
||||
@ -1481,6 +1492,7 @@ ERST
|
||||
.params = "getfd name",
|
||||
.help = "receive a file descriptor via SCM rights and assign it a name",
|
||||
.cmd = hmp_getfd,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -1496,6 +1508,7 @@ ERST
|
||||
.params = "closefd name",
|
||||
.help = "close a file descriptor previously passed via SCM rights",
|
||||
.cmd = hmp_closefd,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
@ -1511,6 +1524,7 @@ ERST
|
||||
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
|
||||
.help = "change I/O throttle limits for a block drive",
|
||||
.cmd = hmp_block_set_io_throttle,
|
||||
.flags = "p",
|
||||
},
|
||||
|
||||
SRST
|
||||
|
@ -379,7 +379,8 @@ static void mch_update_smram(MCHPCIState *mch)
|
||||
memory_region_set_enabled(&mch->high_smram, false);
|
||||
}
|
||||
|
||||
if (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_T_EN) {
|
||||
if ((pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_T_EN) &&
|
||||
(pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_G_SMRAME)) {
|
||||
switch (pd->config[MCH_HOST_BRIDGE_ESMRAMC] &
|
||||
MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
|
||||
case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB:
|
||||
|
@ -249,12 +249,11 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||
static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev)
|
||||
{
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(dev);
|
||||
|
||||
virtio_ccw_stop_ioeventfd(dev);
|
||||
virtio_reset(vdev);
|
||||
virtio_bus_reset(&dev->bus);
|
||||
if (dev->indicators) {
|
||||
release_indicator(&dev->routes.adapter, dev->indicators);
|
||||
dev->indicators = NULL;
|
||||
@ -359,7 +358,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);
|
||||
break;
|
||||
case CCW_CMD_VDEV_RESET:
|
||||
virtio_ccw_reset_virtio(dev, vdev);
|
||||
virtio_ccw_reset_virtio(dev);
|
||||
ret = 0;
|
||||
break;
|
||||
case CCW_CMD_READ_FEAT:
|
||||
@ -536,7 +535,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||
}
|
||||
if (virtio_set_status(vdev, status) == 0) {
|
||||
if (vdev->status == 0) {
|
||||
virtio_ccw_reset_virtio(dev, vdev);
|
||||
virtio_ccw_reset_virtio(dev);
|
||||
}
|
||||
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
||||
virtio_ccw_start_ioeventfd(dev);
|
||||
@ -921,10 +920,9 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
|
||||
static void virtio_ccw_reset(DeviceState *d)
|
||||
{
|
||||
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
|
||||
|
||||
virtio_ccw_reset_virtio(dev, vdev);
|
||||
virtio_ccw_reset_virtio(dev);
|
||||
if (vdc->parent_reset) {
|
||||
vdc->parent_reset(d);
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ void virtio_bus_reset(VirtioBusState *bus)
|
||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||
|
||||
DPRINTF("%s: reset device.\n", BUS(bus)->name);
|
||||
virtio_bus_stop_ioeventfd(bus);
|
||||
if (vdev != NULL) {
|
||||
virtio_reset(vdev);
|
||||
}
|
||||
|
@ -72,12 +72,12 @@ static void virtio_mmio_soft_reset(VirtIOMMIOProxy *proxy)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (proxy->legacy) {
|
||||
return;
|
||||
}
|
||||
virtio_bus_reset(&proxy->bus);
|
||||
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
proxy->vqs[i].enabled = 0;
|
||||
if (!proxy->legacy) {
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
proxy->vqs[i].enabled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,7 +376,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
return;
|
||||
}
|
||||
if (value == 0) {
|
||||
virtio_reset(vdev);
|
||||
virtio_mmio_soft_reset(proxy);
|
||||
} else {
|
||||
virtio_queue_set_addr(vdev, vdev->queue_sel,
|
||||
value << proxy->guest_page_shift);
|
||||
@ -432,7 +432,6 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
}
|
||||
|
||||
if (vdev->status == 0) {
|
||||
virtio_reset(vdev);
|
||||
virtio_mmio_soft_reset(proxy);
|
||||
}
|
||||
break;
|
||||
@ -627,8 +626,8 @@ static void virtio_mmio_reset(DeviceState *d)
|
||||
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
|
||||
int i;
|
||||
|
||||
virtio_mmio_stop_ioeventfd(proxy);
|
||||
virtio_bus_reset(&proxy->bus);
|
||||
virtio_mmio_soft_reset(proxy);
|
||||
|
||||
proxy->host_features_sel = 0;
|
||||
proxy->guest_features_sel = 0;
|
||||
proxy->guest_page_shift = 0;
|
||||
@ -637,7 +636,6 @@ static void virtio_mmio_reset(DeviceState *d)
|
||||
proxy->guest_features[0] = proxy->guest_features[1] = 0;
|
||||
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
proxy->vqs[i].enabled = 0;
|
||||
proxy->vqs[i].num = 0;
|
||||
proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
|
||||
proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
|
||||
|
@ -1945,7 +1945,6 @@ static void virtio_pci_reset(DeviceState *qdev)
|
||||
PCIDevice *dev = PCI_DEVICE(qdev);
|
||||
int i;
|
||||
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_bus_reset(bus);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
|
||||
|
@ -133,5 +133,6 @@ void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict);
|
||||
void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict);
|
||||
void hmp_human_readable_text_helper(Monitor *mon,
|
||||
HumanReadableText *(*qmp_handler)(Error **));
|
||||
void hmp_info_stats(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif
|
||||
|
45
include/monitor/stats.h
Normal file
45
include/monitor/stats.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Oracle and/or its affiliates.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef STATS_H
|
||||
#define STATS_H
|
||||
|
||||
#include "qapi/qapi-types-stats.h"
|
||||
|
||||
typedef void StatRetrieveFunc(StatsResultList **result, StatsTarget target,
|
||||
strList *names, strList *targets, Error **errp);
|
||||
typedef void SchemaRetrieveFunc(StatsSchemaList **result, Error **errp);
|
||||
|
||||
/*
|
||||
* Register callbacks for the QMP query-stats command.
|
||||
*
|
||||
* @provider: stats provider checked against QMP command arguments
|
||||
* @stats_fn: routine to query stats:
|
||||
* @schema_fn: routine to query stat schemas:
|
||||
*/
|
||||
void add_stats_callbacks(StatsProvider provider,
|
||||
StatRetrieveFunc *stats_fn,
|
||||
SchemaRetrieveFunc *schemas_fn);
|
||||
|
||||
/*
|
||||
* Helper routines for adding stats entries to the results lists.
|
||||
*/
|
||||
void add_stats_entry(StatsResultList **, StatsProvider, const char *id,
|
||||
StatsList *stats_list);
|
||||
void add_stats_schema(StatsSchemaList **, StatsProvider, StatsTarget,
|
||||
StatsSchemaValueList *);
|
||||
|
||||
/*
|
||||
* True if a string matches the filter passed to the stats_fn callabck,
|
||||
* false otherwise.
|
||||
*
|
||||
* Note that an empty list means no filtering, i.e. all strings will
|
||||
* return true.
|
||||
*/
|
||||
bool apply_str_list_filter(const char *string, strList *list);
|
||||
|
||||
#endif /* STATS_H */
|
@ -1,6 +1,24 @@
|
||||
#ifndef QEMU_CUTILS_H
|
||||
#define QEMU_CUTILS_H
|
||||
|
||||
/*
|
||||
* si_prefix:
|
||||
* @exp10: exponent of 10, a multiple of 3 between -18 and 18 inclusive.
|
||||
*
|
||||
* Return a SI prefix (n, u, m, K, M, etc.) corresponding
|
||||
* to the given exponent of 10.
|
||||
*/
|
||||
const char *si_prefix(unsigned int exp10);
|
||||
|
||||
/*
|
||||
* iec_binary_prefix:
|
||||
* @exp2: exponent of 2, a multiple of 10 between 0 and 60 inclusive.
|
||||
*
|
||||
* Return an IEC binary prefix (Ki, Mi, etc.) corresponding
|
||||
* to the given exponent of 2.
|
||||
*/
|
||||
const char *iec_binary_prefix(unsigned int exp2);
|
||||
|
||||
/**
|
||||
* pstrcpy:
|
||||
* @buf: buffer to copy string into
|
||||
|
25
meson.build
25
meson.build
@ -209,9 +209,13 @@ if get_option('fuzzing')
|
||||
configure_file(output: 'instrumentation-filter',
|
||||
input: 'scripts/oss-fuzz/instrumentation-filter-template',
|
||||
copy: true)
|
||||
add_global_arguments(
|
||||
cc.get_supported_arguments('-fsanitize-coverage-allowlist=instrumentation-filter'),
|
||||
native: false, language: ['c', 'cpp', 'objc'])
|
||||
|
||||
if cc.compiles('int main () { return 0; }',
|
||||
name: '-fsanitize-coverage-allowlist=/dev/null',
|
||||
args: ['-fsanitize-coverage-allowlist=/dev/null'] )
|
||||
add_global_arguments('-fsanitize-coverage-allowlist=instrumentation-filter',
|
||||
native: false, language: ['c', 'cpp', 'objc'])
|
||||
endif
|
||||
|
||||
if get_option('fuzzing_engine') == ''
|
||||
# Add CFLAGS to tell clang to add fuzzer-related instrumentation to all the
|
||||
@ -3767,21 +3771,24 @@ endif
|
||||
summary_info += {'strip binaries': get_option('strip')}
|
||||
summary_info += {'sparse': sparse}
|
||||
summary_info += {'mingw32 support': targetos == 'windows'}
|
||||
summary(summary_info, bool_yn: true, section: 'Compilation')
|
||||
|
||||
# snarf the cross-compilation information for tests
|
||||
summary_info = {}
|
||||
have_cross = false
|
||||
foreach target: target_dirs
|
||||
tcg_mak = meson.current_build_dir() / 'tests/tcg' / 'config-' + target + '.mak'
|
||||
if fs.exists(tcg_mak)
|
||||
config_cross_tcg = keyval.load(tcg_mak)
|
||||
target = config_cross_tcg['TARGET_NAME']
|
||||
compiler = ''
|
||||
if 'CC' in config_cross_tcg
|
||||
summary_info += {target + ' tests': config_cross_tcg['CC']}
|
||||
summary_info += {config_cross_tcg['TARGET_NAME']: config_cross_tcg['CC']}
|
||||
have_cross = true
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endforeach
|
||||
|
||||
summary(summary_info, bool_yn: true, section: 'Compilation')
|
||||
if have_cross
|
||||
summary(summary_info, bool_yn: true, section: 'Cross compilers')
|
||||
endif
|
||||
|
||||
# Targets and accelerators
|
||||
summary_info = {}
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "qapi/qapi-commands-pci.h"
|
||||
#include "qapi/qapi-commands-rocker.h"
|
||||
#include "qapi/qapi-commands-run-state.h"
|
||||
#include "qapi/qapi-commands-stats.h"
|
||||
#include "qapi/qapi-commands-tpm.h"
|
||||
#include "qapi/qapi-commands-ui.h"
|
||||
#include "qapi/qapi-visit-net.h"
|
||||
@ -52,6 +53,7 @@
|
||||
#include "ui/console.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "hw/intc/intc.h"
|
||||
#include "migration/snapshot.h"
|
||||
#include "migration/misc.h"
|
||||
@ -2239,3 +2241,233 @@ void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict)
|
||||
}
|
||||
hmp_handle_error(mon, err);
|
||||
}
|
||||
|
||||
static void print_stats_schema_value(Monitor *mon, StatsSchemaValue *value)
|
||||
{
|
||||
const char *unit = NULL;
|
||||
monitor_printf(mon, " %s (%s%s", value->name, StatsType_str(value->type),
|
||||
value->has_unit || value->exponent ? ", " : "");
|
||||
|
||||
if (value->has_unit) {
|
||||
if (value->unit == STATS_UNIT_SECONDS) {
|
||||
unit = "s";
|
||||
} else if (value->unit == STATS_UNIT_BYTES) {
|
||||
unit = "B";
|
||||
}
|
||||
}
|
||||
|
||||
if (unit && value->base == 10 &&
|
||||
value->exponent >= -18 && value->exponent <= 18 &&
|
||||
value->exponent % 3 == 0) {
|
||||
monitor_printf(mon, "%s", si_prefix(value->exponent));
|
||||
} else if (unit && value->base == 2 &&
|
||||
value->exponent >= 0 && value->exponent <= 60 &&
|
||||
value->exponent % 10 == 0) {
|
||||
|
||||
monitor_printf(mon, "%s", iec_binary_prefix(value->exponent));
|
||||
} else if (value->exponent) {
|
||||
/* Use exponential notation and write the unit's English name */
|
||||
monitor_printf(mon, "* %d^%d%s",
|
||||
value->base, value->exponent,
|
||||
value->has_unit ? " " : "");
|
||||
unit = NULL;
|
||||
}
|
||||
|
||||
if (value->has_unit) {
|
||||
monitor_printf(mon, "%s", unit ? unit : StatsUnit_str(value->unit));
|
||||
}
|
||||
|
||||
/* Print bucket size for linear histograms */
|
||||
if (value->type == STATS_TYPE_LINEAR_HISTOGRAM && value->has_bucket_size) {
|
||||
monitor_printf(mon, ", bucket size=%d", value->bucket_size);
|
||||
}
|
||||
monitor_printf(mon, ")");
|
||||
}
|
||||
|
||||
static StatsSchemaValueList *find_schema_value_list(
|
||||
StatsSchemaList *list, StatsProvider provider,
|
||||
StatsTarget target)
|
||||
{
|
||||
StatsSchemaList *node;
|
||||
|
||||
for (node = list; node; node = node->next) {
|
||||
if (node->value->provider == provider &&
|
||||
node->value->target == target) {
|
||||
return node->value->stats;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void print_stats_results(Monitor *mon, StatsTarget target,
|
||||
bool show_provider,
|
||||
StatsResult *result,
|
||||
StatsSchemaList *schema)
|
||||
{
|
||||
/* Find provider schema */
|
||||
StatsSchemaValueList *schema_value_list =
|
||||
find_schema_value_list(schema, result->provider, target);
|
||||
StatsList *stats_list;
|
||||
|
||||
if (!schema_value_list) {
|
||||
monitor_printf(mon, "failed to find schema list for %s\n",
|
||||
StatsProvider_str(result->provider));
|
||||
return;
|
||||
}
|
||||
|
||||
if (show_provider) {
|
||||
monitor_printf(mon, "provider: %s\n",
|
||||
StatsProvider_str(result->provider));
|
||||
}
|
||||
|
||||
for (stats_list = result->stats; stats_list;
|
||||
stats_list = stats_list->next,
|
||||
schema_value_list = schema_value_list->next) {
|
||||
|
||||
Stats *stats = stats_list->value;
|
||||
StatsValue *stats_value = stats->value;
|
||||
StatsSchemaValue *schema_value = schema_value_list->value;
|
||||
|
||||
/* Find schema entry */
|
||||
while (!g_str_equal(stats->name, schema_value->name)) {
|
||||
if (!schema_value_list->next) {
|
||||
monitor_printf(mon, "failed to find schema entry for %s\n",
|
||||
stats->name);
|
||||
return;
|
||||
}
|
||||
schema_value_list = schema_value_list->next;
|
||||
schema_value = schema_value_list->value;
|
||||
}
|
||||
|
||||
print_stats_schema_value(mon, schema_value);
|
||||
|
||||
if (stats_value->type == QTYPE_QNUM) {
|
||||
monitor_printf(mon, ": %" PRId64 "\n", stats_value->u.scalar);
|
||||
} else if (stats_value->type == QTYPE_QLIST) {
|
||||
uint64List *list;
|
||||
int i;
|
||||
|
||||
monitor_printf(mon, ": ");
|
||||
for (list = stats_value->u.list, i = 1;
|
||||
list;
|
||||
list = list->next, i++) {
|
||||
monitor_printf(mon, "[%d]=%" PRId64 " ", i, list->value);
|
||||
}
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the StatsFilter that is needed for an "info stats" invocation. */
|
||||
static StatsFilter *stats_filter(StatsTarget target, const char *names,
|
||||
int cpu_index, StatsProvider provider)
|
||||
{
|
||||
StatsFilter *filter = g_malloc0(sizeof(*filter));
|
||||
StatsProvider provider_idx;
|
||||
StatsRequestList *request_list = NULL;
|
||||
|
||||
filter->target = target;
|
||||
switch (target) {
|
||||
case STATS_TARGET_VM:
|
||||
break;
|
||||
case STATS_TARGET_VCPU:
|
||||
{
|
||||
strList *vcpu_list = NULL;
|
||||
CPUState *cpu = qemu_get_cpu(cpu_index);
|
||||
char *canonical_path = object_get_canonical_path(OBJECT(cpu));
|
||||
|
||||
QAPI_LIST_PREPEND(vcpu_list, canonical_path);
|
||||
filter->u.vcpu.has_vcpus = true;
|
||||
filter->u.vcpu.vcpus = vcpu_list;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!names && provider == STATS_PROVIDER__MAX) {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/*
|
||||
* "info stats" can only query either one or all the providers. Querying
|
||||
* by name, but not by provider, requires the creation of one filter per
|
||||
* provider.
|
||||
*/
|
||||
for (provider_idx = 0; provider_idx < STATS_PROVIDER__MAX; provider_idx++) {
|
||||
if (provider == STATS_PROVIDER__MAX || provider == provider_idx) {
|
||||
StatsRequest *request = g_new0(StatsRequest, 1);
|
||||
request->provider = provider_idx;
|
||||
if (names && !g_str_equal(names, "*")) {
|
||||
request->has_names = true;
|
||||
request->names = strList_from_comma_list(names);
|
||||
}
|
||||
QAPI_LIST_PREPEND(request_list, request);
|
||||
}
|
||||
}
|
||||
|
||||
filter->has_providers = true;
|
||||
filter->providers = request_list;
|
||||
return filter;
|
||||
}
|
||||
|
||||
void hmp_info_stats(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *target_str = qdict_get_str(qdict, "target");
|
||||
const char *provider_str = qdict_get_try_str(qdict, "provider");
|
||||
const char *names = qdict_get_try_str(qdict, "names");
|
||||
|
||||
StatsProvider provider = STATS_PROVIDER__MAX;
|
||||
StatsTarget target;
|
||||
Error *err = NULL;
|
||||
g_autoptr(StatsSchemaList) schema = NULL;
|
||||
g_autoptr(StatsResultList) stats = NULL;
|
||||
g_autoptr(StatsFilter) filter = NULL;
|
||||
StatsResultList *entry;
|
||||
|
||||
target = qapi_enum_parse(&StatsTarget_lookup, target_str, -1, &err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "invalid stats target %s\n", target_str);
|
||||
goto exit_no_print;
|
||||
}
|
||||
if (provider_str) {
|
||||
provider = qapi_enum_parse(&StatsProvider_lookup, provider_str, -1, &err);
|
||||
if (err) {
|
||||
monitor_printf(mon, "invalid stats provider %s\n", provider_str);
|
||||
goto exit_no_print;
|
||||
}
|
||||
}
|
||||
|
||||
schema = qmp_query_stats_schemas(provider_str ? true : false,
|
||||
provider, &err);
|
||||
if (err) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch (target) {
|
||||
case STATS_TARGET_VM:
|
||||
filter = stats_filter(target, names, -1, provider);
|
||||
break;
|
||||
case STATS_TARGET_VCPU: {}
|
||||
int cpu_index = monitor_get_cpu_index(mon);
|
||||
filter = stats_filter(target, names, cpu_index, provider);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
stats = qmp_query_stats(filter, &err);
|
||||
if (err) {
|
||||
goto exit;
|
||||
}
|
||||
for (entry = stats; entry; entry = entry->next) {
|
||||
print_stats_results(mon, target, provider_str == NULL, entry->value, schema);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (err) {
|
||||
monitor_printf(mon, "%s\n", error_get_pretty(err));
|
||||
}
|
||||
exit_no_print:
|
||||
error_free(err);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "qapi/qapi-commands-control.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qapi-commands-stats.h"
|
||||
#include "qapi/qapi-commands-ui.h"
|
||||
#include "qapi/type-helpers.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
@ -43,6 +44,7 @@
|
||||
#include "hw/acpi/acpi_dev_interface.h"
|
||||
#include "hw/intc/intc.h"
|
||||
#include "hw/rdma/rdma.h"
|
||||
#include "monitor/stats.h"
|
||||
|
||||
NameInfo *qmp_query_name(Error **errp)
|
||||
{
|
||||
@ -441,3 +443,156 @@ HumanReadableText *qmp_x_query_irq(Error **errp)
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
typedef struct StatsCallbacks {
|
||||
StatsProvider provider;
|
||||
StatRetrieveFunc *stats_cb;
|
||||
SchemaRetrieveFunc *schemas_cb;
|
||||
QTAILQ_ENTRY(StatsCallbacks) next;
|
||||
} StatsCallbacks;
|
||||
|
||||
static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
|
||||
QTAILQ_HEAD_INITIALIZER(stats_callbacks);
|
||||
|
||||
void add_stats_callbacks(StatsProvider provider,
|
||||
StatRetrieveFunc *stats_fn,
|
||||
SchemaRetrieveFunc *schemas_fn)
|
||||
{
|
||||
StatsCallbacks *entry = g_new(StatsCallbacks, 1);
|
||||
entry->provider = provider;
|
||||
entry->stats_cb = stats_fn;
|
||||
entry->schemas_cb = schemas_fn;
|
||||
|
||||
QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next);
|
||||
}
|
||||
|
||||
static bool invoke_stats_cb(StatsCallbacks *entry,
|
||||
StatsResultList **stats_results,
|
||||
StatsFilter *filter, StatsRequest *request,
|
||||
Error **errp)
|
||||
{
|
||||
strList *targets = NULL;
|
||||
strList *names = NULL;
|
||||
ERRP_GUARD();
|
||||
|
||||
if (request) {
|
||||
if (request->provider != entry->provider) {
|
||||
return true;
|
||||
}
|
||||
if (request->has_names && !request->names) {
|
||||
return true;
|
||||
}
|
||||
names = request->has_names ? request->names : NULL;
|
||||
}
|
||||
|
||||
switch (filter->target) {
|
||||
case STATS_TARGET_VM:
|
||||
break;
|
||||
case STATS_TARGET_VCPU:
|
||||
if (filter->u.vcpu.has_vcpus) {
|
||||
if (!filter->u.vcpu.vcpus) {
|
||||
/* No targets allowed? Return no statistics. */
|
||||
return true;
|
||||
}
|
||||
targets = filter->u.vcpu.vcpus;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
entry->stats_cb(stats_results, filter->target, names, targets, errp);
|
||||
if (*errp) {
|
||||
qapi_free_StatsResultList(*stats_results);
|
||||
*stats_results = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
|
||||
{
|
||||
StatsResultList *stats_results = NULL;
|
||||
StatsCallbacks *entry;
|
||||
StatsRequestList *request;
|
||||
|
||||
QTAILQ_FOREACH(entry, &stats_callbacks, next) {
|
||||
if (filter->has_providers) {
|
||||
for (request = filter->providers; request; request = request->next) {
|
||||
if (!invoke_stats_cb(entry, &stats_results, filter,
|
||||
request->value, errp)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stats_results;
|
||||
}
|
||||
|
||||
StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
|
||||
StatsProvider provider,
|
||||
Error **errp)
|
||||
{
|
||||
StatsSchemaList *stats_results = NULL;
|
||||
StatsCallbacks *entry;
|
||||
ERRP_GUARD();
|
||||
|
||||
QTAILQ_FOREACH(entry, &stats_callbacks, next) {
|
||||
if (!has_provider || provider == entry->provider) {
|
||||
entry->schemas_cb(&stats_results, errp);
|
||||
if (*errp) {
|
||||
qapi_free_StatsSchemaList(stats_results);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stats_results;
|
||||
}
|
||||
|
||||
void add_stats_entry(StatsResultList **stats_results, StatsProvider provider,
|
||||
const char *qom_path, StatsList *stats_list)
|
||||
{
|
||||
StatsResult *entry = g_new0(StatsResult, 1);
|
||||
|
||||
entry->provider = provider;
|
||||
if (qom_path) {
|
||||
entry->has_qom_path = true;
|
||||
entry->qom_path = g_strdup(qom_path);
|
||||
}
|
||||
entry->stats = stats_list;
|
||||
|
||||
QAPI_LIST_PREPEND(*stats_results, entry);
|
||||
}
|
||||
|
||||
void add_stats_schema(StatsSchemaList **schema_results,
|
||||
StatsProvider provider, StatsTarget target,
|
||||
StatsSchemaValueList *stats_list)
|
||||
{
|
||||
StatsSchema *entry = g_new0(StatsSchema, 1);
|
||||
|
||||
entry->provider = provider;
|
||||
entry->target = target;
|
||||
entry->stats = stats_list;
|
||||
QAPI_LIST_PREPEND(*schema_results, entry);
|
||||
}
|
||||
|
||||
bool apply_str_list_filter(const char *string, strList *list)
|
||||
{
|
||||
strList *str_list = NULL;
|
||||
|
||||
if (!list) {
|
||||
return true;
|
||||
}
|
||||
for (str_list = list; str_list; str_list = str_list->next) {
|
||||
if (g_str_equal(string, str_list->value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -737,7 +737,8 @@
|
||||
# }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-block', 'returns': ['BlockInfo'] }
|
||||
{ 'command': 'query-block', 'returns': ['BlockInfo'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockDeviceTimedStats:
|
||||
@ -1113,7 +1114,8 @@
|
||||
##
|
||||
{ 'command': 'query-blockstats',
|
||||
'data': { '*query-nodes': 'bool' },
|
||||
'returns': ['BlockStats'] }
|
||||
'returns': ['BlockStats'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockdevOnError:
|
||||
@ -1262,7 +1264,8 @@
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] }
|
||||
{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block_resize:
|
||||
@ -1293,7 +1296,8 @@
|
||||
'data': { '*device': 'str',
|
||||
'*node-name': 'str',
|
||||
'size': 'int' },
|
||||
'coroutine': true }
|
||||
'coroutine': true,
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @NewImageMode:
|
||||
@ -1509,7 +1513,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'blockdev-snapshot-sync',
|
||||
'data': 'BlockdevSnapshotSync' }
|
||||
'data': 'BlockdevSnapshotSync',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @blockdev-snapshot:
|
||||
@ -1550,7 +1555,8 @@
|
||||
##
|
||||
{ 'command': 'blockdev-snapshot',
|
||||
'data': 'BlockdevSnapshot',
|
||||
'features': [ 'allow-write-only-overlay' ] }
|
||||
'features': [ 'allow-write-only-overlay' ],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @change-backing-file:
|
||||
@ -1582,7 +1588,8 @@
|
||||
##
|
||||
{ 'command': 'change-backing-file',
|
||||
'data': { 'device': 'str', 'image-node-name': 'str',
|
||||
'backing-file': 'str' } }
|
||||
'backing-file': 'str' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-commit:
|
||||
@ -1692,7 +1699,8 @@
|
||||
'*backing-file': 'str', '*speed': 'int',
|
||||
'*on-error': 'BlockdevOnError',
|
||||
'*filter-node-name': 'str',
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @drive-backup:
|
||||
@ -1721,7 +1729,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'drive-backup', 'boxed': true,
|
||||
'data': 'DriveBackup', 'features': ['deprecated'] }
|
||||
'data': 'DriveBackup', 'features': ['deprecated'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @blockdev-backup:
|
||||
@ -1747,7 +1756,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'blockdev-backup', 'boxed': true,
|
||||
'data': 'BlockdevBackup' }
|
||||
'data': 'BlockdevBackup',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @query-named-block-nodes:
|
||||
@ -1813,7 +1823,8 @@
|
||||
##
|
||||
{ 'command': 'query-named-block-nodes',
|
||||
'returns': [ 'BlockDeviceInfo' ],
|
||||
'data': { '*flat': 'bool' } }
|
||||
'data': { '*flat': 'bool' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @XDbgBlockGraphNodeType:
|
||||
@ -1922,7 +1933,8 @@
|
||||
# Since: 4.0
|
||||
##
|
||||
{ 'command': 'x-debug-query-block-graph', 'returns': 'XDbgBlockGraph',
|
||||
'features': [ 'unstable' ] }
|
||||
'features': [ 'unstable' ],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @drive-mirror:
|
||||
@ -1950,7 +1962,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'drive-mirror', 'boxed': true,
|
||||
'data': 'DriveMirror' }
|
||||
'data': 'DriveMirror',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @DriveMirror:
|
||||
@ -2123,7 +2136,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'block-dirty-bitmap-add',
|
||||
'data': 'BlockDirtyBitmapAdd' }
|
||||
'data': 'BlockDirtyBitmapAdd',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-dirty-bitmap-remove:
|
||||
@ -2147,7 +2161,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'block-dirty-bitmap-remove',
|
||||
'data': 'BlockDirtyBitmap' }
|
||||
'data': 'BlockDirtyBitmap',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-dirty-bitmap-clear:
|
||||
@ -2170,7 +2185,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'block-dirty-bitmap-clear',
|
||||
'data': 'BlockDirtyBitmap' }
|
||||
'data': 'BlockDirtyBitmap',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-dirty-bitmap-enable:
|
||||
@ -2191,7 +2207,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'block-dirty-bitmap-enable',
|
||||
'data': 'BlockDirtyBitmap' }
|
||||
'data': 'BlockDirtyBitmap',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-dirty-bitmap-disable:
|
||||
@ -2212,7 +2229,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'block-dirty-bitmap-disable',
|
||||
'data': 'BlockDirtyBitmap' }
|
||||
'data': 'BlockDirtyBitmap',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-dirty-bitmap-merge:
|
||||
@ -2244,7 +2262,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'block-dirty-bitmap-merge',
|
||||
'data': 'BlockDirtyBitmapMerge' }
|
||||
'data': 'BlockDirtyBitmapMerge',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockDirtyBitmapSha256:
|
||||
@ -2275,7 +2294,8 @@
|
||||
##
|
||||
{ 'command': 'x-debug-block-dirty-bitmap-sha256',
|
||||
'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256',
|
||||
'features': [ 'unstable' ] }
|
||||
'features': [ 'unstable' ],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @blockdev-mirror:
|
||||
@ -2361,7 +2381,8 @@
|
||||
'*on-target-error': 'BlockdevOnError',
|
||||
'*filter-node-name': 'str',
|
||||
'*copy-mode': 'MirrorCopyMode',
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockIOThrottle:
|
||||
@ -2663,7 +2684,8 @@
|
||||
'*base-node': 'str', '*backing-file': 'str', '*bottom': 'str',
|
||||
'*speed': 'int', '*on-error': 'BlockdevOnError',
|
||||
'*filter-node-name': 'str',
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-job-set-speed:
|
||||
@ -2687,7 +2709,8 @@
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'block-job-set-speed',
|
||||
'data': { 'device': 'str', 'speed': 'int' } }
|
||||
'data': { 'device': 'str', 'speed': 'int' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-job-cancel:
|
||||
@ -2726,7 +2749,8 @@
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'block-job-cancel', 'data': { 'device': 'str', '*force': 'bool' } }
|
||||
{ 'command': 'block-job-cancel', 'data': { 'device': 'str', '*force': 'bool' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-job-pause:
|
||||
@ -2750,7 +2774,8 @@
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'command': 'block-job-pause', 'data': { 'device': 'str' } }
|
||||
{ 'command': 'block-job-pause', 'data': { 'device': 'str' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-job-resume:
|
||||
@ -2772,7 +2797,8 @@
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'command': 'block-job-resume', 'data': { 'device': 'str' } }
|
||||
{ 'command': 'block-job-resume', 'data': { 'device': 'str' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-job-complete:
|
||||
@ -2800,7 +2826,8 @@
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'command': 'block-job-complete', 'data': { 'device': 'str' } }
|
||||
{ 'command': 'block-job-complete', 'data': { 'device': 'str' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-job-dismiss:
|
||||
@ -2820,7 +2847,8 @@
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' } }
|
||||
{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-job-finalize:
|
||||
@ -2838,7 +2866,8 @@
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'command': 'block-job-finalize', 'data': { 'id': 'str' } }
|
||||
{ 'command': 'block-job-finalize', 'data': { 'id': 'str' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockdevDiscardOptions:
|
||||
@ -4354,7 +4383,8 @@
|
||||
# <- { "return": {} }
|
||||
#
|
||||
##
|
||||
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true }
|
||||
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true,
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @blockdev-reopen:
|
||||
@ -4398,7 +4428,8 @@
|
||||
# Since: 6.1
|
||||
##
|
||||
{ 'command': 'blockdev-reopen',
|
||||
'data': { 'options': ['BlockdevOptions'] } }
|
||||
'data': { 'options': ['BlockdevOptions'] },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @blockdev-del:
|
||||
@ -4431,7 +4462,8 @@
|
||||
# <- { "return": {} }
|
||||
#
|
||||
##
|
||||
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
|
||||
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockdevCreateOptionsFile:
|
||||
@ -4872,7 +4904,8 @@
|
||||
##
|
||||
{ 'command': 'blockdev-create',
|
||||
'data': { 'job-id': 'str',
|
||||
'options': 'BlockdevCreateOptions' } }
|
||||
'options': 'BlockdevCreateOptions' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockdevAmendOptionsLUKS:
|
||||
@ -4944,7 +4977,8 @@
|
||||
'node-name': 'str',
|
||||
'options': 'BlockdevAmendOptions',
|
||||
'*force': 'bool' },
|
||||
'features': [ 'unstable' ] }
|
||||
'features': [ 'unstable' ],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockErrorAction:
|
||||
@ -5294,7 +5328,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'block-set-write-threshold',
|
||||
'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
|
||||
'data': { 'node-name': 'str', 'write-threshold': 'uint64' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @x-blockdev-change:
|
||||
@ -5355,7 +5390,8 @@
|
||||
'data' : { 'parent': 'str',
|
||||
'*child': 'str',
|
||||
'*node': 'str' },
|
||||
'features': [ 'unstable' ] }
|
||||
'features': [ 'unstable' ],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @x-blockdev-set-iothread:
|
||||
@ -5397,7 +5433,8 @@
|
||||
'data' : { 'node-name': 'str',
|
||||
'iothread': 'StrOrNull',
|
||||
'*force': 'bool' },
|
||||
'features': [ 'unstable' ] }
|
||||
'features': [ 'unstable' ],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @QuorumOpType:
|
||||
@ -5529,7 +5566,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'blockdev-snapshot-internal-sync',
|
||||
'data': 'BlockdevSnapshotInternal' }
|
||||
'data': 'BlockdevSnapshotInternal',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @blockdev-snapshot-delete-internal-sync:
|
||||
@ -5576,4 +5614,5 @@
|
||||
##
|
||||
{ 'command': 'blockdev-snapshot-delete-internal-sync',
|
||||
'data': { 'device': 'str', '*id': 'str', '*name': 'str'},
|
||||
'returns': 'SnapshotInfo' }
|
||||
'returns': 'SnapshotInfo',
|
||||
'allow-preconfig': true }
|
||||
|
@ -65,7 +65,8 @@
|
||||
'data': { 'addr': 'SocketAddressLegacy',
|
||||
'*tls-creds': 'str',
|
||||
'*tls-authz': 'str',
|
||||
'*max-connections': 'uint32' } }
|
||||
'*max-connections': 'uint32' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockExportOptionsNbdBase:
|
||||
@ -215,7 +216,8 @@
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'command': 'nbd-server-add',
|
||||
'data': 'NbdServerAddOptions', 'boxed': true, 'features': ['deprecated'] }
|
||||
'data': 'NbdServerAddOptions', 'boxed': true, 'features': ['deprecated'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockExportRemoveMode:
|
||||
@ -260,7 +262,8 @@
|
||||
##
|
||||
{ 'command': 'nbd-server-remove',
|
||||
'data': {'name': 'str', '*mode': 'BlockExportRemoveMode'},
|
||||
'features': ['deprecated'] }
|
||||
'features': ['deprecated'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @nbd-server-stop:
|
||||
@ -270,7 +273,8 @@
|
||||
#
|
||||
# Since: 1.3
|
||||
##
|
||||
{ 'command': 'nbd-server-stop' }
|
||||
{ 'command': 'nbd-server-stop',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BlockExportType:
|
||||
@ -342,7 +346,8 @@
|
||||
# Since: 5.2
|
||||
##
|
||||
{ 'command': 'block-export-add',
|
||||
'data': 'BlockExportOptions', 'boxed': true }
|
||||
'data': 'BlockExportOptions', 'boxed': true,
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-export-del:
|
||||
@ -362,7 +367,8 @@
|
||||
# Since: 5.2
|
||||
##
|
||||
{ 'command': 'block-export-del',
|
||||
'data': { 'id': 'str', '*mode': 'BlockExportRemoveMode' } }
|
||||
'data': { 'id': 'str', '*mode': 'BlockExportRemoveMode' },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @BLOCK_EXPORT_DELETED:
|
||||
@ -406,4 +412,5 @@
|
||||
#
|
||||
# Since: 5.2
|
||||
##
|
||||
{ 'command': 'query-block-exports', 'returns': ['BlockExportInfo'] }
|
||||
{ 'command': 'query-block-exports', 'returns': ['BlockExportInfo'],
|
||||
'allow-preconfig': true }
|
||||
|
@ -496,7 +496,8 @@
|
||||
# <- { "return": {} }
|
||||
##
|
||||
{ 'command': 'block_set_io_throttle', 'boxed': true,
|
||||
'data': 'BlockIOThrottle' }
|
||||
'data': 'BlockIOThrottle',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @block-latency-histogram-set:
|
||||
@ -572,4 +573,5 @@
|
||||
'*boundaries': ['uint64'],
|
||||
'*boundaries-read': ['uint64'],
|
||||
'*boundaries-write': ['uint64'],
|
||||
'*boundaries-flush': ['uint64'] } }
|
||||
'*boundaries-flush': ['uint64'] },
|
||||
'allow-preconfig': true }
|
||||
|
@ -46,6 +46,7 @@ qapi_all_modules = [
|
||||
'replay',
|
||||
'run-state',
|
||||
'sockets',
|
||||
'stats',
|
||||
'trace',
|
||||
'transaction',
|
||||
'yank',
|
||||
|
@ -93,3 +93,4 @@
|
||||
{ 'include': 'audio.json' }
|
||||
{ 'include': 'acpi.json' }
|
||||
{ 'include': 'pci.json' }
|
||||
{ 'include': 'stats.json' }
|
||||
|
249
qapi/stats.json
Normal file
249
qapi/stats.json
Normal file
@ -0,0 +1,249 @@
|
||||
# -*- Mode: Python -*-
|
||||
# vim: filetype=python
|
||||
#
|
||||
# Copyright (c) 2022 Oracle and/or its affiliates.
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
##
|
||||
# = Statistics
|
||||
##
|
||||
|
||||
##
|
||||
# @StatsType:
|
||||
#
|
||||
# Enumeration of statistics types
|
||||
#
|
||||
# @cumulative: stat is cumulative; value can only increase.
|
||||
# @instant: stat is instantaneous; value can increase or decrease.
|
||||
# @peak: stat is the peak value; value can only increase.
|
||||
# @linear-histogram: stat is a linear histogram.
|
||||
# @log2-histogram: stat is a logarithmic histogram, with one bucket
|
||||
# for each power of two.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'enum' : 'StatsType',
|
||||
'data' : [ 'cumulative', 'instant', 'peak', 'linear-histogram',
|
||||
'log2-histogram' ] }
|
||||
|
||||
##
|
||||
# @StatsUnit:
|
||||
#
|
||||
# Enumeration of unit of measurement for statistics
|
||||
#
|
||||
# @bytes: stat reported in bytes.
|
||||
# @seconds: stat reported in seconds.
|
||||
# @cycles: stat reported in clock cycles.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'enum' : 'StatsUnit',
|
||||
'data' : [ 'bytes', 'seconds', 'cycles' ] }
|
||||
|
||||
##
|
||||
# @StatsProvider:
|
||||
#
|
||||
# Enumeration of statistics providers.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'enum': 'StatsProvider',
|
||||
'data': [ 'kvm' ] }
|
||||
|
||||
##
|
||||
# @StatsTarget:
|
||||
#
|
||||
# The kinds of objects on which one can request statistics.
|
||||
#
|
||||
# @vm: statistics that apply to the entire virtual machine or
|
||||
# the entire QEMU process.
|
||||
#
|
||||
# @vcpu: statistics that apply to a single virtual CPU.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'enum': 'StatsTarget',
|
||||
'data': [ 'vm', 'vcpu' ] }
|
||||
|
||||
##
|
||||
# @StatsRequest:
|
||||
#
|
||||
# Indicates a set of statistics that should be returned by query-stats.
|
||||
#
|
||||
# @provider: provider for which to return statistics.
|
||||
|
||||
# @names: statistics to be returned (all if omitted).
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'StatsRequest',
|
||||
'data': { 'provider': 'StatsProvider',
|
||||
'*names': [ 'str' ] } }
|
||||
|
||||
##
|
||||
# @StatsVCPUFilter:
|
||||
#
|
||||
# @vcpus: list of QOM paths for the desired vCPU objects.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'StatsVCPUFilter',
|
||||
'data': { '*vcpus': [ 'str' ] } }
|
||||
|
||||
##
|
||||
# @StatsFilter:
|
||||
#
|
||||
# The arguments to the query-stats command; specifies a target for which to
|
||||
# request statistics and optionally the required subset of information for
|
||||
# that target:
|
||||
# - which vCPUs to request statistics for
|
||||
# - which providers to request statistics from
|
||||
# - which named values to return within each provider
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'union': 'StatsFilter',
|
||||
'base': {
|
||||
'target': 'StatsTarget',
|
||||
'*providers': [ 'StatsRequest' ] },
|
||||
'discriminator': 'target',
|
||||
'data': { 'vcpu': 'StatsVCPUFilter' } }
|
||||
|
||||
##
|
||||
# @StatsValue:
|
||||
#
|
||||
# @scalar: single unsigned 64-bit integers.
|
||||
# @list: list of unsigned 64-bit integers (used for histograms).
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'alternate': 'StatsValue',
|
||||
'data': { 'scalar': 'uint64',
|
||||
'list': [ 'uint64' ] } }
|
||||
|
||||
##
|
||||
# @Stats:
|
||||
#
|
||||
# @name: name of stat.
|
||||
# @value: stat value.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'Stats',
|
||||
'data': { 'name': 'str',
|
||||
'value' : 'StatsValue' } }
|
||||
|
||||
##
|
||||
# @StatsResult:
|
||||
#
|
||||
# @provider: provider for this set of statistics.
|
||||
#
|
||||
# @qom-path: Path to the object for which the statistics are returned,
|
||||
# if the object is exposed in the QOM tree
|
||||
#
|
||||
# @stats: list of statistics.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'StatsResult',
|
||||
'data': { 'provider': 'StatsProvider',
|
||||
'*qom-path': 'str',
|
||||
'stats': [ 'Stats' ] } }
|
||||
|
||||
##
|
||||
# @query-stats:
|
||||
#
|
||||
# Return runtime-collected statistics for objects such as the
|
||||
# VM or its vCPUs.
|
||||
#
|
||||
# The arguments are a StatsFilter and specify the provider and objects
|
||||
# to return statistics about.
|
||||
#
|
||||
# Returns: a list of StatsResult, one for each provider and object
|
||||
# (e.g., for each vCPU).
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'command': 'query-stats',
|
||||
'data': 'StatsFilter',
|
||||
'boxed': true,
|
||||
'returns': [ 'StatsResult' ] }
|
||||
|
||||
##
|
||||
# @StatsSchemaValue:
|
||||
#
|
||||
# Schema for a single statistic.
|
||||
#
|
||||
# @name: name of the statistic; each element of the schema is uniquely
|
||||
# identified by a target, a provider (both available in @StatsSchema)
|
||||
# and the name.
|
||||
#
|
||||
# @type: kind of statistic.
|
||||
#
|
||||
# @unit: basic unit of measure for the statistic; if missing, the statistic
|
||||
# is a simple number or counter.
|
||||
#
|
||||
# @base: base for the multiple of @unit in which the statistic is measured.
|
||||
# Only present if @exponent is non-zero; @base and @exponent together
|
||||
# form a SI prefix (e.g., _nano-_ for ``base=10`` and ``exponent=-9``)
|
||||
# or IEC binary prefix (e.g. _kibi-_ for ``base=2`` and ``exponent=10``)
|
||||
#
|
||||
# @exponent: exponent for the multiple of @unit in which the statistic is
|
||||
# expressed, or 0 for the basic unit
|
||||
#
|
||||
# @bucket-size: Present when @type is "linear-histogram", contains the width
|
||||
# of each bucket of the histogram.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'StatsSchemaValue',
|
||||
'data': { 'name': 'str',
|
||||
'type': 'StatsType',
|
||||
'*unit': 'StatsUnit',
|
||||
'*base': 'int8',
|
||||
'exponent': 'int16',
|
||||
'*bucket-size': 'uint32' } }
|
||||
|
||||
##
|
||||
# @StatsSchema:
|
||||
#
|
||||
# Schema for all available statistics for a provider and target.
|
||||
#
|
||||
# @provider: provider for this set of statistics.
|
||||
#
|
||||
# @target: the kind of object that can be queried through the provider.
|
||||
#
|
||||
# @stats: list of statistics.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'StatsSchema',
|
||||
'data': { 'provider': 'StatsProvider',
|
||||
'target': 'StatsTarget',
|
||||
'stats': [ 'StatsSchemaValue' ] } }
|
||||
|
||||
##
|
||||
# @query-stats-schemas:
|
||||
#
|
||||
# Return the schema for all available runtime-collected statistics.
|
||||
#
|
||||
# Note: runtime-collected statistics and their names fall outside QEMU's usual
|
||||
# deprecation policies. QEMU will try to keep the set of available data
|
||||
# stable, together with their names, but will not guarantee stability
|
||||
# at all costs; the same is true of providers that source statistics
|
||||
# externally, e.g. from Linux. For example, if the same value is being
|
||||
# tracked with different names on different architectures or by different
|
||||
# providers, one of them might be renamed. A statistic might go away if
|
||||
# an algorithm is changed or some code is removed; changing a default
|
||||
# might cause previously useful statistics to always report 0. Such
|
||||
# changes, however, are expected to be rare.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'command': 'query-stats-schemas',
|
||||
'data': { '*provider': 'StatsProvider' },
|
||||
'returns': [ 'StatsSchema' ] }
|
@ -2450,6 +2450,50 @@ static void test_qemu_strtosz_metric(void)
|
||||
g_assert(endptr == str + 7);
|
||||
}
|
||||
|
||||
static void test_freq_to_str(void)
|
||||
{
|
||||
g_assert_cmpstr(freq_to_str(999), ==, "999 Hz");
|
||||
g_assert_cmpstr(freq_to_str(1000), ==, "1 KHz");
|
||||
g_assert_cmpstr(freq_to_str(1010), ==, "1.01 KHz");
|
||||
}
|
||||
|
||||
static void test_size_to_str(void)
|
||||
{
|
||||
g_assert_cmpstr(size_to_str(0), ==, "0 B");
|
||||
g_assert_cmpstr(size_to_str(1), ==, "1 B");
|
||||
g_assert_cmpstr(size_to_str(1016), ==, "0.992 KiB");
|
||||
g_assert_cmpstr(size_to_str(1024), ==, "1 KiB");
|
||||
g_assert_cmpstr(size_to_str(512ull << 20), ==, "512 MiB");
|
||||
}
|
||||
|
||||
static void test_iec_binary_prefix(void)
|
||||
{
|
||||
g_assert_cmpstr(iec_binary_prefix(0), ==, "");
|
||||
g_assert_cmpstr(iec_binary_prefix(10), ==, "Ki");
|
||||
g_assert_cmpstr(iec_binary_prefix(20), ==, "Mi");
|
||||
g_assert_cmpstr(iec_binary_prefix(30), ==, "Gi");
|
||||
g_assert_cmpstr(iec_binary_prefix(40), ==, "Ti");
|
||||
g_assert_cmpstr(iec_binary_prefix(50), ==, "Pi");
|
||||
g_assert_cmpstr(iec_binary_prefix(60), ==, "Ei");
|
||||
}
|
||||
|
||||
static void test_si_prefix(void)
|
||||
{
|
||||
g_assert_cmpstr(si_prefix(-18), ==, "a");
|
||||
g_assert_cmpstr(si_prefix(-15), ==, "f");
|
||||
g_assert_cmpstr(si_prefix(-12), ==, "p");
|
||||
g_assert_cmpstr(si_prefix(-9), ==, "n");
|
||||
g_assert_cmpstr(si_prefix(-6), ==, "u");
|
||||
g_assert_cmpstr(si_prefix(-3), ==, "m");
|
||||
g_assert_cmpstr(si_prefix(0), ==, "");
|
||||
g_assert_cmpstr(si_prefix(3), ==, "K");
|
||||
g_assert_cmpstr(si_prefix(6), ==, "M");
|
||||
g_assert_cmpstr(si_prefix(9), ==, "G");
|
||||
g_assert_cmpstr(si_prefix(12), ==, "T");
|
||||
g_assert_cmpstr(si_prefix(15), ==, "P");
|
||||
g_assert_cmpstr(si_prefix(18), ==, "E");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
@ -2729,5 +2773,13 @@ int main(int argc, char **argv)
|
||||
g_test_add_func("/cutils/strtosz/metric",
|
||||
test_qemu_strtosz_metric);
|
||||
|
||||
g_test_add_func("/cutils/size_to_str",
|
||||
test_size_to_str);
|
||||
g_test_add_func("/cutils/freq_to_str",
|
||||
test_freq_to_str);
|
||||
g_test_add_func("/cutils/iec_binary_prefix",
|
||||
test_iec_binary_prefix);
|
||||
g_test_add_func("/cutils/si_prefix",
|
||||
test_si_prefix);
|
||||
return g_test_run();
|
||||
}
|
||||
|
@ -1,8 +1,17 @@
|
||||
# Makefile for VM tests
|
||||
|
||||
.PHONY: vm-build-all vm-clean-all
|
||||
# Hack to allow running in an unconfigured build tree
|
||||
ifeq ($(wildcard $(SRC_PATH)/config-host.mak),)
|
||||
VM_PYTHON = PYTHONPATH=$(SRC_PATH)/python /usr/bin/env python3
|
||||
VM_VENV =
|
||||
HOST_ARCH := $(shell uname -m)
|
||||
else
|
||||
VM_PYTHON = $(TESTS_PYTHON)
|
||||
VM_VENV = check-venv
|
||||
HOST_ARCH = $(ARCH)
|
||||
endif
|
||||
|
||||
HOST_ARCH = $(if $(ARCH),$(ARCH),$(shell uname -m))
|
||||
.PHONY: vm-build-all vm-clean-all
|
||||
|
||||
EFI_AARCH64 = $(wildcard $(BUILD_DIR)/pc-bios/edk2-aarch64-code.fd)
|
||||
|
||||
@ -85,10 +94,10 @@ vm-clean-all:
|
||||
$(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \
|
||||
$(SRC_PATH)/tests/vm/basevm.py \
|
||||
$(SRC_PATH)/tests/vm/Makefile.include \
|
||||
check-venv
|
||||
$(VM_VENV)
|
||||
@mkdir -p $(IMAGES_DIR)
|
||||
$(call quiet-command, \
|
||||
$(TESTS_PYTHON) $< \
|
||||
$(VM_PYTHON) $< \
|
||||
$(if $(V)$(DEBUG), --debug) \
|
||||
$(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \
|
||||
$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
|
||||
@ -100,11 +109,10 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \
|
||||
--build-image $@, \
|
||||
" VM-IMAGE $*")
|
||||
|
||||
|
||||
# Build in VM $(IMAGE)
|
||||
vm-build-%: $(IMAGES_DIR)/%.img check-venv
|
||||
vm-build-%: $(IMAGES_DIR)/%.img $(VM_VENV)
|
||||
$(call quiet-command, \
|
||||
$(TESTS_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
||||
$(VM_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
||||
$(if $(V)$(DEBUG), --debug) \
|
||||
$(if $(DEBUG), --interactive) \
|
||||
$(if $(J),--jobs $(J)) \
|
||||
@ -128,9 +136,9 @@ vm-boot-serial-%: $(IMAGES_DIR)/%.img
|
||||
-device virtio-net-pci,netdev=vnet \
|
||||
|| true
|
||||
|
||||
vm-boot-ssh-%: $(IMAGES_DIR)/%.img check-venv
|
||||
vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(VM_VENV)
|
||||
$(call quiet-command, \
|
||||
$(TESTS_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
||||
$(VM_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
||||
$(if $(J),--jobs $(J)) \
|
||||
$(if $(V)$(DEBUG), --debug) \
|
||||
$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
|
||||
|
@ -872,6 +872,25 @@ int parse_debug_env(const char *name, int max, int initial)
|
||||
return debug;
|
||||
}
|
||||
|
||||
const char *si_prefix(unsigned int exp10)
|
||||
{
|
||||
static const char *prefixes[] = {
|
||||
"a", "f", "p", "n", "u", "m", "", "K", "M", "G", "T", "P", "E"
|
||||
};
|
||||
|
||||
exp10 += 18;
|
||||
assert(exp10 % 3 == 0 && exp10 / 3 < ARRAY_SIZE(prefixes));
|
||||
return prefixes[exp10 / 3];
|
||||
}
|
||||
|
||||
const char *iec_binary_prefix(unsigned int exp2)
|
||||
{
|
||||
static const char *prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
|
||||
|
||||
assert(exp2 % 10 == 0 && exp2 / 10 < ARRAY_SIZE(prefixes));
|
||||
return prefixes[exp2 / 10];
|
||||
}
|
||||
|
||||
/*
|
||||
* Return human readable string for size @val.
|
||||
* @val can be anything that uint64_t allows (no more than "16 EiB").
|
||||
@ -880,7 +899,6 @@ int parse_debug_env(const char *name, int max, int initial)
|
||||
*/
|
||||
char *size_to_str(uint64_t val)
|
||||
{
|
||||
static const char *suffixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
|
||||
uint64_t div;
|
||||
int i;
|
||||
|
||||
@ -891,25 +909,23 @@ char *size_to_str(uint64_t val)
|
||||
* (see e41b509d68afb1f for more info)
|
||||
*/
|
||||
frexp(val / (1000.0 / 1024.0), &i);
|
||||
i = (i - 1) / 10;
|
||||
div = 1ULL << (i * 10);
|
||||
i = (i - 1) / 10 * 10;
|
||||
div = 1ULL << i;
|
||||
|
||||
return g_strdup_printf("%0.3g %sB", (double)val / div, suffixes[i]);
|
||||
return g_strdup_printf("%0.3g %sB", (double)val / div, iec_binary_prefix(i));
|
||||
}
|
||||
|
||||
char *freq_to_str(uint64_t freq_hz)
|
||||
{
|
||||
static const char *const suffixes[] = { "", "K", "M", "G", "T", "P", "E" };
|
||||
double freq = freq_hz;
|
||||
size_t idx = 0;
|
||||
size_t exp10 = 0;
|
||||
|
||||
while (freq >= 1000.0) {
|
||||
freq /= 1000.0;
|
||||
idx++;
|
||||
exp10 += 3;
|
||||
}
|
||||
assert(idx < ARRAY_SIZE(suffixes));
|
||||
|
||||
return g_strdup_printf("%0.3g %sHz", freq, suffixes[idx]);
|
||||
return g_strdup_printf("%0.3g %sHz", freq, si_prefix(exp10));
|
||||
}
|
||||
|
||||
int qemu_pstrcmp0(const char **str1, const char **str2)
|
||||
|
Loading…
Reference in New Issue
Block a user