/* Copyright (C) 2009 Red Hat, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define TAB_LEN 4 #define VALUE_TABS 7 #define INVALID_STAT_REF (~(uint32_t)0) static SpiceStat *reds_stat = NULL; static uint64_t *values = NULL; void print_stat_tree(int32_t node_index, int depth) { SpiceStatNode *node = &reds_stat->nodes[node_index]; int i; if ((node->flags & SPICE_STAT_NODE_MASK_SHOW) == SPICE_STAT_NODE_MASK_SHOW) { printf("%*s%s", depth * TAB_LEN, "", node->name); if (node->flags & SPICE_STAT_NODE_FLAG_VALUE) { printf(":%*s%llu (%llu)\n", (VALUE_TABS - depth) * TAB_LEN - strlen(node->name) - 1, "", node->value, node->value - values[node_index]); values[node_index] = node->value; } else { printf("\n"); if (node->first_child_index != INVALID_STAT_REF) { print_stat_tree(node->first_child_index, depth + 1); } } } if (node->next_sibling_index != INVALID_STAT_REF) { print_stat_tree(node->next_sibling_index, depth); } } int main(int argc, char **argv) { char *shm_name; pid_t kvm_pid; uint64_t *val; uint32_t num_of_nodes = 0; size_t shm_size; size_t shm_old_size; int shm_name_len; int ret = -1; int fd; if (argc != 2 || !(kvm_pid = atoi(argv[1]))) { printf("usage: reds_stat [qemu_pid] (e.g. `pgrep qemu`)\n"); return -1; } shm_name_len = strlen(SPICE_STAT_SHM_NAME) + strlen(argv[1]); if (!(shm_name = (char *)malloc(shm_name_len))) { perror("malloc"); return -1; } snprintf(shm_name, shm_name_len, SPICE_STAT_SHM_NAME, kvm_pid); if ((fd = shm_open(shm_name, O_RDONLY, 0444)) == -1) { perror("shm_open"); free(shm_name); return -1; } shm_size = sizeof(SpiceStat); reds_stat = (SpiceStat *)mmap(NULL, shm_size, PROT_READ, MAP_SHARED, fd, 0); if (reds_stat == (SpiceStat *)MAP_FAILED) { perror("mmap"); goto error1; } if (reds_stat->magic != SPICE_STAT_MAGIC) { printf("bad magic %u\n", reds_stat->magic); goto error2; } if (reds_stat->version != SPICE_STAT_VERSION) { printf("bad version %u\n", reds_stat->version); goto error2; } while (1) { system("clear"); printf("spice statistics\n\n"); if (num_of_nodes != reds_stat->num_of_nodes) { num_of_nodes = reds_stat->num_of_nodes; shm_old_size = shm_size; shm_size = sizeof(SpiceStat) + num_of_nodes * sizeof(SpiceStatNode); reds_stat = mremap(reds_stat, shm_old_size, shm_size, MREMAP_MAYMOVE); if (reds_stat == (SpiceStat *)MAP_FAILED) { perror("mremap"); goto error3; } values = (uint64_t *)realloc(values, num_of_nodes * sizeof(uint64_t)); if (values == NULL) { perror("realloc"); goto error3; } memset(values, 0, num_of_nodes * sizeof(uint64_t)); } print_stat_tree(reds_stat->root_index, 0); sleep(1); } ret = 0; error3: free(values); error2: munmap(reds_stat, shm_size); error1: shm_unlink(shm_name); free(shm_name); return ret; }