mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 16:53:55 -06:00
* 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
25 changed files with 1368 additions and 115 deletions
12
Makefile
12
Makefile
|
@ -186,16 +186,14 @@ include $(SRC_PATH)/tests/Makefile.include
|
||||||
|
|
||||||
all: recurse-all
|
all: recurse-all
|
||||||
|
|
||||||
ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
|
ROMS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROMS)))
|
||||||
ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS)))
|
.PHONY: $(ROMS_RULES)
|
||||||
# Only keep -O and -g cflags
|
$(ROMS_RULES):
|
||||||
.PHONY: $(ROM_DIRS_RULES)
|
|
||||||
$(ROM_DIRS_RULES):
|
|
||||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
|
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
|
||||||
|
|
||||||
.PHONY: recurse-all recurse-clean
|
.PHONY: recurse-all recurse-clean
|
||||||
recurse-all: $(addsuffix /all, $(ROM_DIRS))
|
recurse-all: $(addsuffix /all, $(ROMS))
|
||||||
recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
|
recurse-clean: $(addsuffix /clean, $(ROMS))
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "kvm-cpus.h"
|
#include "kvm-cpus.h"
|
||||||
|
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
|
#include "monitor/stats.h"
|
||||||
|
|
||||||
/* This check must be after config-host.h is included */
|
/* This check must be after config-host.h is included */
|
||||||
#ifdef CONFIG_EVENTFD
|
#ifdef CONFIG_EVENTFD
|
||||||
|
@ -2310,6 +2311,10 @@ bool kvm_dirty_ring_enabled(void)
|
||||||
return kvm_state->kvm_dirty_ring_size ? true : false;
|
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)
|
static int kvm_init(MachineState *ms)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(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;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -3697,3 +3707,396 @@ static void kvm_type_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(kvm_type_init);
|
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; }
|
int main(void) { return tls_var; }
|
||||||
EOF
|
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 "$static" = "yes"; then
|
||||||
if test "$pie" != "no" && compile_prog "-Werror -fPIE -DPIE" "-static-pie"; then
|
if test "$pie" != "no" && compile_prog "-Werror -fPIE -DPIE" "-static-pie"; then
|
||||||
CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS"
|
CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS"
|
||||||
|
@ -1370,8 +1363,10 @@ if test "$static" = "yes"; then
|
||||||
pie="no"
|
pie="no"
|
||||||
fi
|
fi
|
||||||
elif test "$pie" = "no"; then
|
elif test "$pie" = "no"; then
|
||||||
CONFIGURE_CFLAGS="$CFLAGS_NOPIE $CONFIGURE_CFLAGS"
|
if compile_prog "-Werror -fno-pie" "-no-pie"; then
|
||||||
CONFIGURE_LDFLAGS="$LDFLAGS_NOPIE $CONFIGURE_LDFLAGS"
|
CONFIGURE_CFLAGS="-fno-pie $CONFIGURE_CFLAGS"
|
||||||
|
CONFIGURE_LDFLAGS="-no-pie $CONFIGURE_LDFLAGS"
|
||||||
|
fi
|
||||||
elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then
|
elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then
|
||||||
CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS"
|
CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS"
|
||||||
CONFIGURE_LDFLAGS="-pie $CONFIGURE_LDFLAGS"
|
CONFIGURE_LDFLAGS="-pie $CONFIGURE_LDFLAGS"
|
||||||
|
@ -2257,7 +2252,7 @@ if test -n "$target_cc" &&
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if test -n "$ld_i386_emulation"; then
|
if test -n "$ld_i386_emulation"; then
|
||||||
roms="optionrom"
|
roms="pc-bios/optionrom"
|
||||||
config_mak=pc-bios/optionrom/config.mak
|
config_mak=pc-bios/optionrom/config.mak
|
||||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||||
echo "TOPSRC_DIR=$source_path" >> $config_mak
|
echo "TOPSRC_DIR=$source_path" >> $config_mak
|
||||||
|
@ -2268,7 +2263,7 @@ fi
|
||||||
|
|
||||||
probe_target_compilers ppc ppc64
|
probe_target_compilers ppc ppc64
|
||||||
if test -n "$target_cc" && test "$softmmu" = yes; then
|
if test -n "$target_cc" && test "$softmmu" = yes; then
|
||||||
roms="$roms vof"
|
roms="$roms pc-bios/vof"
|
||||||
config_mak=pc-bios/vof/config.mak
|
config_mak=pc-bios/vof/config.mak
|
||||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||||
echo "SRC_DIR=$source_path/pc-bios/vof" >> $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 "WARNING: Your compiler does not support the z900!"
|
||||||
echo " The s390-ccw bios will only work with guest CPUs >= z10."
|
echo " The s390-ccw bios will only work with guest CPUs >= z10."
|
||||||
fi
|
fi
|
||||||
roms="$roms s390-ccw"
|
roms="$roms pc-bios/s390-ccw"
|
||||||
config_mak=pc-bios/s390-ccw/config-host.mak
|
config_mak=pc-bios/s390-ccw/config-host.mak
|
||||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||||
echo "SRC_PATH=$source_path/pc-bios/s390-ccw" >> $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 CFLAGS
|
||||||
preserve_env CXX
|
preserve_env CXX
|
||||||
preserve_env CXXFLAGS
|
preserve_env CXXFLAGS
|
||||||
preserve_env INSTALL
|
|
||||||
preserve_env LD
|
preserve_env LD
|
||||||
preserve_env LDFLAGS
|
preserve_env LDFLAGS
|
||||||
preserve_env LD_LIBRARY_PATH
|
preserve_env LD_LIBRARY_PATH
|
||||||
preserve_env LIBTOOL
|
|
||||||
preserve_env MAKE
|
preserve_env MAKE
|
||||||
preserve_env NM
|
preserve_env NM
|
||||||
|
preserve_env OBJCFLAGS
|
||||||
preserve_env OBJCOPY
|
preserve_env OBJCOPY
|
||||||
preserve_env PATH
|
preserve_env PATH
|
||||||
preserve_env PKG_CONFIG
|
preserve_env PKG_CONFIG
|
||||||
|
|
|
@ -894,3 +894,17 @@ SRST
|
||||||
``info via``
|
``info via``
|
||||||
Show guest mos6522 VIA devices.
|
Show guest mos6522 VIA devices.
|
||||||
ERST
|
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",
|
.help = "resize a block image",
|
||||||
.cmd = hmp_block_resize,
|
.cmd = hmp_block_resize,
|
||||||
.coroutine = true,
|
.coroutine = true,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -94,6 +95,7 @@ ERST
|
||||||
.params = "device [speed [base]]",
|
.params = "device [speed [base]]",
|
||||||
.help = "copy data from a backing file into a block device",
|
.help = "copy data from a backing file into a block device",
|
||||||
.cmd = hmp_block_stream,
|
.cmd = hmp_block_stream,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -107,6 +109,7 @@ ERST
|
||||||
.params = "device speed",
|
.params = "device speed",
|
||||||
.help = "set maximum speed for a background block operation",
|
.help = "set maximum speed for a background block operation",
|
||||||
.cmd = hmp_block_job_set_speed,
|
.cmd = hmp_block_job_set_speed,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -122,6 +125,7 @@ ERST
|
||||||
"\n\t\t\t if you want to abort the operation immediately"
|
"\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)",
|
"\n\t\t\t instead of keep running until data is in sync)",
|
||||||
.cmd = hmp_block_job_cancel,
|
.cmd = hmp_block_job_cancel,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -135,6 +139,7 @@ ERST
|
||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "stop an active background block operation",
|
.help = "stop an active background block operation",
|
||||||
.cmd = hmp_block_job_complete,
|
.cmd = hmp_block_job_complete,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -149,6 +154,7 @@ ERST
|
||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "pause an active background block operation",
|
.help = "pause an active background block operation",
|
||||||
.cmd = hmp_block_job_pause,
|
.cmd = hmp_block_job_pause,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -162,6 +168,7 @@ ERST
|
||||||
.params = "device",
|
.params = "device",
|
||||||
.help = "resume a paused background block operation",
|
.help = "resume a paused background block operation",
|
||||||
.cmd = hmp_block_job_resume,
|
.cmd = hmp_block_job_resume,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -1406,6 +1413,7 @@ ERST
|
||||||
.params = "nbd_server_start [-a] [-w] host:port",
|
.params = "nbd_server_start [-a] [-w] host:port",
|
||||||
.help = "serve block devices on the given host and port",
|
.help = "serve block devices on the given host and port",
|
||||||
.cmd = hmp_nbd_server_start,
|
.cmd = hmp_nbd_server_start,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
SRST
|
SRST
|
||||||
``nbd_server_start`` *host*:*port*
|
``nbd_server_start`` *host*:*port*
|
||||||
|
@ -1421,6 +1429,7 @@ ERST
|
||||||
.params = "nbd_server_add [-w] device [name]",
|
.params = "nbd_server_add [-w] device [name]",
|
||||||
.help = "export a block device via NBD",
|
.help = "export a block device via NBD",
|
||||||
.cmd = hmp_nbd_server_add,
|
.cmd = hmp_nbd_server_add,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
SRST
|
SRST
|
||||||
``nbd_server_add`` *device* [ *name* ]
|
``nbd_server_add`` *device* [ *name* ]
|
||||||
|
@ -1436,6 +1445,7 @@ ERST
|
||||||
.params = "nbd_server_remove [-f] name",
|
.params = "nbd_server_remove [-f] name",
|
||||||
.help = "remove an export previously exposed via NBD",
|
.help = "remove an export previously exposed via NBD",
|
||||||
.cmd = hmp_nbd_server_remove,
|
.cmd = hmp_nbd_server_remove,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
SRST
|
SRST
|
||||||
``nbd_server_remove [-f]`` *name*
|
``nbd_server_remove [-f]`` *name*
|
||||||
|
@ -1452,6 +1462,7 @@ ERST
|
||||||
.params = "nbd_server_stop",
|
.params = "nbd_server_stop",
|
||||||
.help = "stop serving block devices using the NBD protocol",
|
.help = "stop serving block devices using the NBD protocol",
|
||||||
.cmd = hmp_nbd_server_stop,
|
.cmd = hmp_nbd_server_stop,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
SRST
|
SRST
|
||||||
``nbd_server_stop``
|
``nbd_server_stop``
|
||||||
|
@ -1481,6 +1492,7 @@ ERST
|
||||||
.params = "getfd name",
|
.params = "getfd name",
|
||||||
.help = "receive a file descriptor via SCM rights and assign it a name",
|
.help = "receive a file descriptor via SCM rights and assign it a name",
|
||||||
.cmd = hmp_getfd,
|
.cmd = hmp_getfd,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -1496,6 +1508,7 @@ ERST
|
||||||
.params = "closefd name",
|
.params = "closefd name",
|
||||||
.help = "close a file descriptor previously passed via SCM rights",
|
.help = "close a file descriptor previously passed via SCM rights",
|
||||||
.cmd = hmp_closefd,
|
.cmd = hmp_closefd,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
@ -1511,6 +1524,7 @@ ERST
|
||||||
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
|
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
|
||||||
.help = "change I/O throttle limits for a block drive",
|
.help = "change I/O throttle limits for a block drive",
|
||||||
.cmd = hmp_block_set_io_throttle,
|
.cmd = hmp_block_set_io_throttle,
|
||||||
|
.flags = "p",
|
||||||
},
|
},
|
||||||
|
|
||||||
SRST
|
SRST
|
||||||
|
|
|
@ -379,7 +379,8 @@ static void mch_update_smram(MCHPCIState *mch)
|
||||||
memory_region_set_enabled(&mch->high_smram, false);
|
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] &
|
switch (pd->config[MCH_HOST_BRIDGE_ESMRAMC] &
|
||||||
MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
|
MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
|
||||||
case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB:
|
case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB:
|
||||||
|
|
|
@ -249,12 +249,11 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
|
||||||
return 0;
|
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);
|
CcwDevice *ccw_dev = CCW_DEVICE(dev);
|
||||||
|
|
||||||
virtio_ccw_stop_ioeventfd(dev);
|
virtio_bus_reset(&dev->bus);
|
||||||
virtio_reset(vdev);
|
|
||||||
if (dev->indicators) {
|
if (dev->indicators) {
|
||||||
release_indicator(&dev->routes.adapter, dev->indicators);
|
release_indicator(&dev->routes.adapter, dev->indicators);
|
||||||
dev->indicators = NULL;
|
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);
|
ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);
|
||||||
break;
|
break;
|
||||||
case CCW_CMD_VDEV_RESET:
|
case CCW_CMD_VDEV_RESET:
|
||||||
virtio_ccw_reset_virtio(dev, vdev);
|
virtio_ccw_reset_virtio(dev);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case CCW_CMD_READ_FEAT:
|
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 (virtio_set_status(vdev, status) == 0) {
|
||||||
if (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) {
|
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
||||||
virtio_ccw_start_ioeventfd(dev);
|
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)
|
static void virtio_ccw_reset(DeviceState *d)
|
||||||
{
|
{
|
||||||
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
||||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
|
||||||
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
|
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
|
||||||
|
|
||||||
virtio_ccw_reset_virtio(dev, vdev);
|
virtio_ccw_reset_virtio(dev);
|
||||||
if (vdc->parent_reset) {
|
if (vdc->parent_reset) {
|
||||||
vdc->parent_reset(d);
|
vdc->parent_reset(d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ void virtio_bus_reset(VirtioBusState *bus)
|
||||||
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
VirtIODevice *vdev = virtio_bus_get_device(bus);
|
||||||
|
|
||||||
DPRINTF("%s: reset device.\n", BUS(bus)->name);
|
DPRINTF("%s: reset device.\n", BUS(bus)->name);
|
||||||
|
virtio_bus_stop_ioeventfd(bus);
|
||||||
if (vdev != NULL) {
|
if (vdev != NULL) {
|
||||||
virtio_reset(vdev);
|
virtio_reset(vdev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,12 +72,12 @@ static void virtio_mmio_soft_reset(VirtIOMMIOProxy *proxy)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (proxy->legacy) {
|
virtio_bus_reset(&proxy->bus);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
if (!proxy->legacy) {
|
||||||
proxy->vqs[i].enabled = 0;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
virtio_reset(vdev);
|
virtio_mmio_soft_reset(proxy);
|
||||||
} else {
|
} else {
|
||||||
virtio_queue_set_addr(vdev, vdev->queue_sel,
|
virtio_queue_set_addr(vdev, vdev->queue_sel,
|
||||||
value << proxy->guest_page_shift);
|
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) {
|
if (vdev->status == 0) {
|
||||||
virtio_reset(vdev);
|
|
||||||
virtio_mmio_soft_reset(proxy);
|
virtio_mmio_soft_reset(proxy);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -627,8 +626,8 @@ static void virtio_mmio_reset(DeviceState *d)
|
||||||
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
|
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
virtio_mmio_stop_ioeventfd(proxy);
|
virtio_mmio_soft_reset(proxy);
|
||||||
virtio_bus_reset(&proxy->bus);
|
|
||||||
proxy->host_features_sel = 0;
|
proxy->host_features_sel = 0;
|
||||||
proxy->guest_features_sel = 0;
|
proxy->guest_features_sel = 0;
|
||||||
proxy->guest_page_shift = 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;
|
proxy->guest_features[0] = proxy->guest_features[1] = 0;
|
||||||
|
|
||||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||||
proxy->vqs[i].enabled = 0;
|
|
||||||
proxy->vqs[i].num = 0;
|
proxy->vqs[i].num = 0;
|
||||||
proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
|
proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
|
||||||
proxy->vqs[i].avail[0] = proxy->vqs[i].avail[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);
|
PCIDevice *dev = PCI_DEVICE(qdev);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
virtio_pci_stop_ioeventfd(proxy);
|
|
||||||
virtio_bus_reset(bus);
|
virtio_bus_reset(bus);
|
||||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
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_calc_dirty_rate(Monitor *mon, const QDict *qdict);
|
||||||
void hmp_human_readable_text_helper(Monitor *mon,
|
void hmp_human_readable_text_helper(Monitor *mon,
|
||||||
HumanReadableText *(*qmp_handler)(Error **));
|
HumanReadableText *(*qmp_handler)(Error **));
|
||||||
|
void hmp_info_stats(Monitor *mon, const QDict *qdict);
|
||||||
|
|
||||||
#endif
|
#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
|
#ifndef QEMU_CUTILS_H
|
||||||
#define 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:
|
* pstrcpy:
|
||||||
* @buf: buffer to copy string into
|
* @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',
|
configure_file(output: 'instrumentation-filter',
|
||||||
input: 'scripts/oss-fuzz/instrumentation-filter-template',
|
input: 'scripts/oss-fuzz/instrumentation-filter-template',
|
||||||
copy: true)
|
copy: true)
|
||||||
add_global_arguments(
|
|
||||||
cc.get_supported_arguments('-fsanitize-coverage-allowlist=instrumentation-filter'),
|
if cc.compiles('int main () { return 0; }',
|
||||||
native: false, language: ['c', 'cpp', 'objc'])
|
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') == ''
|
if get_option('fuzzing_engine') == ''
|
||||||
# Add CFLAGS to tell clang to add fuzzer-related instrumentation to all the
|
# 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 += {'strip binaries': get_option('strip')}
|
||||||
summary_info += {'sparse': sparse}
|
summary_info += {'sparse': sparse}
|
||||||
summary_info += {'mingw32 support': targetos == 'windows'}
|
summary_info += {'mingw32 support': targetos == 'windows'}
|
||||||
|
summary(summary_info, bool_yn: true, section: 'Compilation')
|
||||||
|
|
||||||
# snarf the cross-compilation information for tests
|
# snarf the cross-compilation information for tests
|
||||||
|
summary_info = {}
|
||||||
|
have_cross = false
|
||||||
foreach target: target_dirs
|
foreach target: target_dirs
|
||||||
tcg_mak = meson.current_build_dir() / 'tests/tcg' / 'config-' + target + '.mak'
|
tcg_mak = meson.current_build_dir() / 'tests/tcg' / 'config-' + target + '.mak'
|
||||||
if fs.exists(tcg_mak)
|
if fs.exists(tcg_mak)
|
||||||
config_cross_tcg = keyval.load(tcg_mak)
|
config_cross_tcg = keyval.load(tcg_mak)
|
||||||
target = config_cross_tcg['TARGET_NAME']
|
|
||||||
compiler = ''
|
|
||||||
if 'CC' in config_cross_tcg
|
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
|
endif
|
||||||
endforeach
|
endforeach
|
||||||
|
if have_cross
|
||||||
summary(summary_info, bool_yn: true, section: 'Compilation')
|
summary(summary_info, bool_yn: true, section: 'Cross compilers')
|
||||||
|
endif
|
||||||
|
|
||||||
# Targets and accelerators
|
# Targets and accelerators
|
||||||
summary_info = {}
|
summary_info = {}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "qapi/qapi-commands-pci.h"
|
#include "qapi/qapi-commands-pci.h"
|
||||||
#include "qapi/qapi-commands-rocker.h"
|
#include "qapi/qapi-commands-rocker.h"
|
||||||
#include "qapi/qapi-commands-run-state.h"
|
#include "qapi/qapi-commands-run-state.h"
|
||||||
|
#include "qapi/qapi-commands-stats.h"
|
||||||
#include "qapi/qapi-commands-tpm.h"
|
#include "qapi/qapi-commands-tpm.h"
|
||||||
#include "qapi/qapi-commands-ui.h"
|
#include "qapi/qapi-commands-ui.h"
|
||||||
#include "qapi/qapi-visit-net.h"
|
#include "qapi/qapi-visit-net.h"
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/core/cpu.h"
|
||||||
#include "hw/intc/intc.h"
|
#include "hw/intc/intc.h"
|
||||||
#include "migration/snapshot.h"
|
#include "migration/snapshot.h"
|
||||||
#include "migration/misc.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);
|
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-control.h"
|
||||||
#include "qapi/qapi-commands-machine.h"
|
#include "qapi/qapi-commands-machine.h"
|
||||||
#include "qapi/qapi-commands-misc.h"
|
#include "qapi/qapi-commands-misc.h"
|
||||||
|
#include "qapi/qapi-commands-stats.h"
|
||||||
#include "qapi/qapi-commands-ui.h"
|
#include "qapi/qapi-commands-ui.h"
|
||||||
#include "qapi/type-helpers.h"
|
#include "qapi/type-helpers.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
|
@ -43,6 +44,7 @@
|
||||||
#include "hw/acpi/acpi_dev_interface.h"
|
#include "hw/acpi/acpi_dev_interface.h"
|
||||||
#include "hw/intc/intc.h"
|
#include "hw/intc/intc.h"
|
||||||
#include "hw/rdma/rdma.h"
|
#include "hw/rdma/rdma.h"
|
||||||
|
#include "monitor/stats.h"
|
||||||
|
|
||||||
NameInfo *qmp_query_name(Error **errp)
|
NameInfo *qmp_query_name(Error **errp)
|
||||||
{
|
{
|
||||||
|
@ -441,3 +443,156 @@ HumanReadableText *qmp_x_query_irq(Error **errp)
|
||||||
|
|
||||||
return human_readable_text_from_str(buf);
|
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:
|
# @BlockDeviceTimedStats:
|
||||||
|
@ -1113,7 +1114,8 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'query-blockstats',
|
{ 'command': 'query-blockstats',
|
||||||
'data': { '*query-nodes': 'bool' },
|
'data': { '*query-nodes': 'bool' },
|
||||||
'returns': ['BlockStats'] }
|
'returns': ['BlockStats'],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockdevOnError:
|
# @BlockdevOnError:
|
||||||
|
@ -1262,7 +1264,8 @@
|
||||||
#
|
#
|
||||||
# Since: 1.1
|
# Since: 1.1
|
||||||
##
|
##
|
||||||
{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] }
|
{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block_resize:
|
# @block_resize:
|
||||||
|
@ -1293,7 +1296,8 @@
|
||||||
'data': { '*device': 'str',
|
'data': { '*device': 'str',
|
||||||
'*node-name': 'str',
|
'*node-name': 'str',
|
||||||
'size': 'int' },
|
'size': 'int' },
|
||||||
'coroutine': true }
|
'coroutine': true,
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @NewImageMode:
|
# @NewImageMode:
|
||||||
|
@ -1509,7 +1513,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-snapshot-sync',
|
{ 'command': 'blockdev-snapshot-sync',
|
||||||
'data': 'BlockdevSnapshotSync' }
|
'data': 'BlockdevSnapshotSync',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @blockdev-snapshot:
|
# @blockdev-snapshot:
|
||||||
|
@ -1550,7 +1555,8 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-snapshot',
|
{ 'command': 'blockdev-snapshot',
|
||||||
'data': 'BlockdevSnapshot',
|
'data': 'BlockdevSnapshot',
|
||||||
'features': [ 'allow-write-only-overlay' ] }
|
'features': [ 'allow-write-only-overlay' ],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @change-backing-file:
|
# @change-backing-file:
|
||||||
|
@ -1582,7 +1588,8 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'change-backing-file',
|
{ 'command': 'change-backing-file',
|
||||||
'data': { 'device': 'str', 'image-node-name': 'str',
|
'data': { 'device': 'str', 'image-node-name': 'str',
|
||||||
'backing-file': 'str' } }
|
'backing-file': 'str' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-commit:
|
# @block-commit:
|
||||||
|
@ -1692,7 +1699,8 @@
|
||||||
'*backing-file': 'str', '*speed': 'int',
|
'*backing-file': 'str', '*speed': 'int',
|
||||||
'*on-error': 'BlockdevOnError',
|
'*on-error': 'BlockdevOnError',
|
||||||
'*filter-node-name': 'str',
|
'*filter-node-name': 'str',
|
||||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @drive-backup:
|
# @drive-backup:
|
||||||
|
@ -1721,7 +1729,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'drive-backup', 'boxed': true,
|
{ 'command': 'drive-backup', 'boxed': true,
|
||||||
'data': 'DriveBackup', 'features': ['deprecated'] }
|
'data': 'DriveBackup', 'features': ['deprecated'],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @blockdev-backup:
|
# @blockdev-backup:
|
||||||
|
@ -1747,7 +1756,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-backup', 'boxed': true,
|
{ 'command': 'blockdev-backup', 'boxed': true,
|
||||||
'data': 'BlockdevBackup' }
|
'data': 'BlockdevBackup',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @query-named-block-nodes:
|
# @query-named-block-nodes:
|
||||||
|
@ -1813,7 +1823,8 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'query-named-block-nodes',
|
{ 'command': 'query-named-block-nodes',
|
||||||
'returns': [ 'BlockDeviceInfo' ],
|
'returns': [ 'BlockDeviceInfo' ],
|
||||||
'data': { '*flat': 'bool' } }
|
'data': { '*flat': 'bool' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @XDbgBlockGraphNodeType:
|
# @XDbgBlockGraphNodeType:
|
||||||
|
@ -1922,7 +1933,8 @@
|
||||||
# Since: 4.0
|
# Since: 4.0
|
||||||
##
|
##
|
||||||
{ 'command': 'x-debug-query-block-graph', 'returns': 'XDbgBlockGraph',
|
{ 'command': 'x-debug-query-block-graph', 'returns': 'XDbgBlockGraph',
|
||||||
'features': [ 'unstable' ] }
|
'features': [ 'unstable' ],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @drive-mirror:
|
# @drive-mirror:
|
||||||
|
@ -1950,7 +1962,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'drive-mirror', 'boxed': true,
|
{ 'command': 'drive-mirror', 'boxed': true,
|
||||||
'data': 'DriveMirror' }
|
'data': 'DriveMirror',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @DriveMirror:
|
# @DriveMirror:
|
||||||
|
@ -2123,7 +2136,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'block-dirty-bitmap-add',
|
{ 'command': 'block-dirty-bitmap-add',
|
||||||
'data': 'BlockDirtyBitmapAdd' }
|
'data': 'BlockDirtyBitmapAdd',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-dirty-bitmap-remove:
|
# @block-dirty-bitmap-remove:
|
||||||
|
@ -2147,7 +2161,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'block-dirty-bitmap-remove',
|
{ 'command': 'block-dirty-bitmap-remove',
|
||||||
'data': 'BlockDirtyBitmap' }
|
'data': 'BlockDirtyBitmap',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-dirty-bitmap-clear:
|
# @block-dirty-bitmap-clear:
|
||||||
|
@ -2170,7 +2185,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'block-dirty-bitmap-clear',
|
{ 'command': 'block-dirty-bitmap-clear',
|
||||||
'data': 'BlockDirtyBitmap' }
|
'data': 'BlockDirtyBitmap',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-dirty-bitmap-enable:
|
# @block-dirty-bitmap-enable:
|
||||||
|
@ -2191,7 +2207,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'block-dirty-bitmap-enable',
|
{ 'command': 'block-dirty-bitmap-enable',
|
||||||
'data': 'BlockDirtyBitmap' }
|
'data': 'BlockDirtyBitmap',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-dirty-bitmap-disable:
|
# @block-dirty-bitmap-disable:
|
||||||
|
@ -2212,7 +2229,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'block-dirty-bitmap-disable',
|
{ 'command': 'block-dirty-bitmap-disable',
|
||||||
'data': 'BlockDirtyBitmap' }
|
'data': 'BlockDirtyBitmap',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-dirty-bitmap-merge:
|
# @block-dirty-bitmap-merge:
|
||||||
|
@ -2244,7 +2262,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'block-dirty-bitmap-merge',
|
{ 'command': 'block-dirty-bitmap-merge',
|
||||||
'data': 'BlockDirtyBitmapMerge' }
|
'data': 'BlockDirtyBitmapMerge',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockDirtyBitmapSha256:
|
# @BlockDirtyBitmapSha256:
|
||||||
|
@ -2275,7 +2294,8 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'x-debug-block-dirty-bitmap-sha256',
|
{ 'command': 'x-debug-block-dirty-bitmap-sha256',
|
||||||
'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256',
|
'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256',
|
||||||
'features': [ 'unstable' ] }
|
'features': [ 'unstable' ],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @blockdev-mirror:
|
# @blockdev-mirror:
|
||||||
|
@ -2361,7 +2381,8 @@
|
||||||
'*on-target-error': 'BlockdevOnError',
|
'*on-target-error': 'BlockdevOnError',
|
||||||
'*filter-node-name': 'str',
|
'*filter-node-name': 'str',
|
||||||
'*copy-mode': 'MirrorCopyMode',
|
'*copy-mode': 'MirrorCopyMode',
|
||||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockIOThrottle:
|
# @BlockIOThrottle:
|
||||||
|
@ -2663,7 +2684,8 @@
|
||||||
'*base-node': 'str', '*backing-file': 'str', '*bottom': 'str',
|
'*base-node': 'str', '*backing-file': 'str', '*bottom': 'str',
|
||||||
'*speed': 'int', '*on-error': 'BlockdevOnError',
|
'*speed': 'int', '*on-error': 'BlockdevOnError',
|
||||||
'*filter-node-name': 'str',
|
'*filter-node-name': 'str',
|
||||||
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
|
'*auto-finalize': 'bool', '*auto-dismiss': 'bool' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-job-set-speed:
|
# @block-job-set-speed:
|
||||||
|
@ -2687,7 +2709,8 @@
|
||||||
# Since: 1.1
|
# Since: 1.1
|
||||||
##
|
##
|
||||||
{ 'command': 'block-job-set-speed',
|
{ 'command': 'block-job-set-speed',
|
||||||
'data': { 'device': 'str', 'speed': 'int' } }
|
'data': { 'device': 'str', 'speed': 'int' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-job-cancel:
|
# @block-job-cancel:
|
||||||
|
@ -2726,7 +2749,8 @@
|
||||||
#
|
#
|
||||||
# Since: 1.1
|
# 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:
|
# @block-job-pause:
|
||||||
|
@ -2750,7 +2774,8 @@
|
||||||
#
|
#
|
||||||
# Since: 1.3
|
# Since: 1.3
|
||||||
##
|
##
|
||||||
{ 'command': 'block-job-pause', 'data': { 'device': 'str' } }
|
{ 'command': 'block-job-pause', 'data': { 'device': 'str' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-job-resume:
|
# @block-job-resume:
|
||||||
|
@ -2772,7 +2797,8 @@
|
||||||
#
|
#
|
||||||
# Since: 1.3
|
# Since: 1.3
|
||||||
##
|
##
|
||||||
{ 'command': 'block-job-resume', 'data': { 'device': 'str' } }
|
{ 'command': 'block-job-resume', 'data': { 'device': 'str' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-job-complete:
|
# @block-job-complete:
|
||||||
|
@ -2800,7 +2826,8 @@
|
||||||
#
|
#
|
||||||
# Since: 1.3
|
# Since: 1.3
|
||||||
##
|
##
|
||||||
{ 'command': 'block-job-complete', 'data': { 'device': 'str' } }
|
{ 'command': 'block-job-complete', 'data': { 'device': 'str' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-job-dismiss:
|
# @block-job-dismiss:
|
||||||
|
@ -2820,7 +2847,8 @@
|
||||||
#
|
#
|
||||||
# Since: 2.12
|
# Since: 2.12
|
||||||
##
|
##
|
||||||
{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' } }
|
{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-job-finalize:
|
# @block-job-finalize:
|
||||||
|
@ -2838,7 +2866,8 @@
|
||||||
#
|
#
|
||||||
# Since: 2.12
|
# Since: 2.12
|
||||||
##
|
##
|
||||||
{ 'command': 'block-job-finalize', 'data': { 'id': 'str' } }
|
{ 'command': 'block-job-finalize', 'data': { 'id': 'str' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockdevDiscardOptions:
|
# @BlockdevDiscardOptions:
|
||||||
|
@ -4354,7 +4383,8 @@
|
||||||
# <- { "return": {} }
|
# <- { "return": {} }
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true }
|
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true,
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @blockdev-reopen:
|
# @blockdev-reopen:
|
||||||
|
@ -4398,7 +4428,8 @@
|
||||||
# Since: 6.1
|
# Since: 6.1
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-reopen',
|
{ 'command': 'blockdev-reopen',
|
||||||
'data': { 'options': ['BlockdevOptions'] } }
|
'data': { 'options': ['BlockdevOptions'] },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @blockdev-del:
|
# @blockdev-del:
|
||||||
|
@ -4431,7 +4462,8 @@
|
||||||
# <- { "return": {} }
|
# <- { "return": {} }
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
|
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockdevCreateOptionsFile:
|
# @BlockdevCreateOptionsFile:
|
||||||
|
@ -4872,7 +4904,8 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-create',
|
{ 'command': 'blockdev-create',
|
||||||
'data': { 'job-id': 'str',
|
'data': { 'job-id': 'str',
|
||||||
'options': 'BlockdevCreateOptions' } }
|
'options': 'BlockdevCreateOptions' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockdevAmendOptionsLUKS:
|
# @BlockdevAmendOptionsLUKS:
|
||||||
|
@ -4944,7 +4977,8 @@
|
||||||
'node-name': 'str',
|
'node-name': 'str',
|
||||||
'options': 'BlockdevAmendOptions',
|
'options': 'BlockdevAmendOptions',
|
||||||
'*force': 'bool' },
|
'*force': 'bool' },
|
||||||
'features': [ 'unstable' ] }
|
'features': [ 'unstable' ],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockErrorAction:
|
# @BlockErrorAction:
|
||||||
|
@ -5294,7 +5328,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'block-set-write-threshold',
|
{ '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:
|
# @x-blockdev-change:
|
||||||
|
@ -5355,7 +5390,8 @@
|
||||||
'data' : { 'parent': 'str',
|
'data' : { 'parent': 'str',
|
||||||
'*child': 'str',
|
'*child': 'str',
|
||||||
'*node': 'str' },
|
'*node': 'str' },
|
||||||
'features': [ 'unstable' ] }
|
'features': [ 'unstable' ],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @x-blockdev-set-iothread:
|
# @x-blockdev-set-iothread:
|
||||||
|
@ -5397,7 +5433,8 @@
|
||||||
'data' : { 'node-name': 'str',
|
'data' : { 'node-name': 'str',
|
||||||
'iothread': 'StrOrNull',
|
'iothread': 'StrOrNull',
|
||||||
'*force': 'bool' },
|
'*force': 'bool' },
|
||||||
'features': [ 'unstable' ] }
|
'features': [ 'unstable' ],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @QuorumOpType:
|
# @QuorumOpType:
|
||||||
|
@ -5529,7 +5566,8 @@
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-snapshot-internal-sync',
|
{ 'command': 'blockdev-snapshot-internal-sync',
|
||||||
'data': 'BlockdevSnapshotInternal' }
|
'data': 'BlockdevSnapshotInternal',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @blockdev-snapshot-delete-internal-sync:
|
# @blockdev-snapshot-delete-internal-sync:
|
||||||
|
@ -5576,4 +5614,5 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'blockdev-snapshot-delete-internal-sync',
|
{ 'command': 'blockdev-snapshot-delete-internal-sync',
|
||||||
'data': { 'device': 'str', '*id': 'str', '*name': 'str'},
|
'data': { 'device': 'str', '*id': 'str', '*name': 'str'},
|
||||||
'returns': 'SnapshotInfo' }
|
'returns': 'SnapshotInfo',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
|
@ -65,7 +65,8 @@
|
||||||
'data': { 'addr': 'SocketAddressLegacy',
|
'data': { 'addr': 'SocketAddressLegacy',
|
||||||
'*tls-creds': 'str',
|
'*tls-creds': 'str',
|
||||||
'*tls-authz': 'str',
|
'*tls-authz': 'str',
|
||||||
'*max-connections': 'uint32' } }
|
'*max-connections': 'uint32' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockExportOptionsNbdBase:
|
# @BlockExportOptionsNbdBase:
|
||||||
|
@ -215,7 +216,8 @@
|
||||||
# Since: 1.3
|
# Since: 1.3
|
||||||
##
|
##
|
||||||
{ 'command': 'nbd-server-add',
|
{ 'command': 'nbd-server-add',
|
||||||
'data': 'NbdServerAddOptions', 'boxed': true, 'features': ['deprecated'] }
|
'data': 'NbdServerAddOptions', 'boxed': true, 'features': ['deprecated'],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockExportRemoveMode:
|
# @BlockExportRemoveMode:
|
||||||
|
@ -260,7 +262,8 @@
|
||||||
##
|
##
|
||||||
{ 'command': 'nbd-server-remove',
|
{ 'command': 'nbd-server-remove',
|
||||||
'data': {'name': 'str', '*mode': 'BlockExportRemoveMode'},
|
'data': {'name': 'str', '*mode': 'BlockExportRemoveMode'},
|
||||||
'features': ['deprecated'] }
|
'features': ['deprecated'],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @nbd-server-stop:
|
# @nbd-server-stop:
|
||||||
|
@ -270,7 +273,8 @@
|
||||||
#
|
#
|
||||||
# Since: 1.3
|
# Since: 1.3
|
||||||
##
|
##
|
||||||
{ 'command': 'nbd-server-stop' }
|
{ 'command': 'nbd-server-stop',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlockExportType:
|
# @BlockExportType:
|
||||||
|
@ -342,7 +346,8 @@
|
||||||
# Since: 5.2
|
# Since: 5.2
|
||||||
##
|
##
|
||||||
{ 'command': 'block-export-add',
|
{ 'command': 'block-export-add',
|
||||||
'data': 'BlockExportOptions', 'boxed': true }
|
'data': 'BlockExportOptions', 'boxed': true,
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-export-del:
|
# @block-export-del:
|
||||||
|
@ -362,7 +367,8 @@
|
||||||
# Since: 5.2
|
# Since: 5.2
|
||||||
##
|
##
|
||||||
{ 'command': 'block-export-del',
|
{ 'command': 'block-export-del',
|
||||||
'data': { 'id': 'str', '*mode': 'BlockExportRemoveMode' } }
|
'data': { 'id': 'str', '*mode': 'BlockExportRemoveMode' },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BLOCK_EXPORT_DELETED:
|
# @BLOCK_EXPORT_DELETED:
|
||||||
|
@ -406,4 +412,5 @@
|
||||||
#
|
#
|
||||||
# Since: 5.2
|
# Since: 5.2
|
||||||
##
|
##
|
||||||
{ 'command': 'query-block-exports', 'returns': ['BlockExportInfo'] }
|
{ 'command': 'query-block-exports', 'returns': ['BlockExportInfo'],
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
|
@ -496,7 +496,8 @@
|
||||||
# <- { "return": {} }
|
# <- { "return": {} }
|
||||||
##
|
##
|
||||||
{ 'command': 'block_set_io_throttle', 'boxed': true,
|
{ 'command': 'block_set_io_throttle', 'boxed': true,
|
||||||
'data': 'BlockIOThrottle' }
|
'data': 'BlockIOThrottle',
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @block-latency-histogram-set:
|
# @block-latency-histogram-set:
|
||||||
|
@ -572,4 +573,5 @@
|
||||||
'*boundaries': ['uint64'],
|
'*boundaries': ['uint64'],
|
||||||
'*boundaries-read': ['uint64'],
|
'*boundaries-read': ['uint64'],
|
||||||
'*boundaries-write': ['uint64'],
|
'*boundaries-write': ['uint64'],
|
||||||
'*boundaries-flush': ['uint64'] } }
|
'*boundaries-flush': ['uint64'] },
|
||||||
|
'allow-preconfig': true }
|
||||||
|
|
|
@ -46,6 +46,7 @@ qapi_all_modules = [
|
||||||
'replay',
|
'replay',
|
||||||
'run-state',
|
'run-state',
|
||||||
'sockets',
|
'sockets',
|
||||||
|
'stats',
|
||||||
'trace',
|
'trace',
|
||||||
'transaction',
|
'transaction',
|
||||||
'yank',
|
'yank',
|
||||||
|
|
|
@ -93,3 +93,4 @@
|
||||||
{ 'include': 'audio.json' }
|
{ 'include': 'audio.json' }
|
||||||
{ 'include': 'acpi.json' }
|
{ 'include': 'acpi.json' }
|
||||||
{ 'include': 'pci.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);
|
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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
@ -2729,5 +2773,13 @@ int main(int argc, char **argv)
|
||||||
g_test_add_func("/cutils/strtosz/metric",
|
g_test_add_func("/cutils/strtosz/metric",
|
||||||
test_qemu_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();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
# Makefile for VM tests
|
# 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)
|
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/% \
|
$(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \
|
||||||
$(SRC_PATH)/tests/vm/basevm.py \
|
$(SRC_PATH)/tests/vm/basevm.py \
|
||||||
$(SRC_PATH)/tests/vm/Makefile.include \
|
$(SRC_PATH)/tests/vm/Makefile.include \
|
||||||
check-venv
|
$(VM_VENV)
|
||||||
@mkdir -p $(IMAGES_DIR)
|
@mkdir -p $(IMAGES_DIR)
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
$(TESTS_PYTHON) $< \
|
$(VM_PYTHON) $< \
|
||||||
$(if $(V)$(DEBUG), --debug) \
|
$(if $(V)$(DEBUG), --debug) \
|
||||||
$(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \
|
$(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \
|
||||||
$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
|
$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
|
||||||
|
@ -100,11 +109,10 @@ $(IMAGES_DIR)/%.img: $(SRC_PATH)/tests/vm/% \
|
||||||
--build-image $@, \
|
--build-image $@, \
|
||||||
" VM-IMAGE $*")
|
" VM-IMAGE $*")
|
||||||
|
|
||||||
|
|
||||||
# Build in VM $(IMAGE)
|
# Build in VM $(IMAGE)
|
||||||
vm-build-%: $(IMAGES_DIR)/%.img check-venv
|
vm-build-%: $(IMAGES_DIR)/%.img $(VM_VENV)
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
$(TESTS_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
$(VM_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
||||||
$(if $(V)$(DEBUG), --debug) \
|
$(if $(V)$(DEBUG), --debug) \
|
||||||
$(if $(DEBUG), --interactive) \
|
$(if $(DEBUG), --interactive) \
|
||||||
$(if $(J),--jobs $(J)) \
|
$(if $(J),--jobs $(J)) \
|
||||||
|
@ -128,9 +136,9 @@ vm-boot-serial-%: $(IMAGES_DIR)/%.img
|
||||||
-device virtio-net-pci,netdev=vnet \
|
-device virtio-net-pci,netdev=vnet \
|
||||||
|| true
|
|| true
|
||||||
|
|
||||||
vm-boot-ssh-%: $(IMAGES_DIR)/%.img check-venv
|
vm-boot-ssh-%: $(IMAGES_DIR)/%.img $(VM_VENV)
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
$(TESTS_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
$(VM_PYTHON) $(SRC_PATH)/tests/vm/$* \
|
||||||
$(if $(J),--jobs $(J)) \
|
$(if $(J),--jobs $(J)) \
|
||||||
$(if $(V)$(DEBUG), --debug) \
|
$(if $(V)$(DEBUG), --debug) \
|
||||||
$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
|
$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
|
||||||
|
|
|
@ -872,6 +872,25 @@ int parse_debug_env(const char *name, int max, int initial)
|
||||||
return debug;
|
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.
|
* Return human readable string for size @val.
|
||||||
* @val can be anything that uint64_t allows (no more than "16 EiB").
|
* @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)
|
char *size_to_str(uint64_t val)
|
||||||
{
|
{
|
||||||
static const char *suffixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
|
|
||||||
uint64_t div;
|
uint64_t div;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -891,25 +909,23 @@ char *size_to_str(uint64_t val)
|
||||||
* (see e41b509d68afb1f for more info)
|
* (see e41b509d68afb1f for more info)
|
||||||
*/
|
*/
|
||||||
frexp(val / (1000.0 / 1024.0), &i);
|
frexp(val / (1000.0 / 1024.0), &i);
|
||||||
i = (i - 1) / 10;
|
i = (i - 1) / 10 * 10;
|
||||||
div = 1ULL << (i * 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)
|
char *freq_to_str(uint64_t freq_hz)
|
||||||
{
|
{
|
||||||
static const char *const suffixes[] = { "", "K", "M", "G", "T", "P", "E" };
|
|
||||||
double freq = freq_hz;
|
double freq = freq_hz;
|
||||||
size_t idx = 0;
|
size_t exp10 = 0;
|
||||||
|
|
||||||
while (freq >= 1000.0) {
|
while (freq >= 1000.0) {
|
||||||
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)
|
int qemu_pstrcmp0(const char **str1, const char **str2)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue