From patchwork Fri Jul 31 17:36:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 502709 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id B1E851402BB for ; Sat, 1 Aug 2015 03:37:38 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=d22E2iP3; dkim-atps=neutral Received: from localhost ([::1]:45469 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZLEFU-0003kd-Uj for incoming@patchwork.ozlabs.org; Fri, 31 Jul 2015 13:37:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33127) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZLEF1-0002yX-0z for qemu-devel@nongnu.org; Fri, 31 Jul 2015 13:37:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZLEEz-0002jN-IL for qemu-devel@nongnu.org; Fri, 31 Jul 2015 13:37:06 -0400 Received: from mail-qg0-x234.google.com ([2607:f8b0:400d:c04::234]:35270) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZLEEz-0002jA-Dq for qemu-devel@nongnu.org; Fri, 31 Jul 2015 13:37:05 -0400 Received: by qgii95 with SMTP id i95so50547360qgi.2 for ; Fri, 31 Jul 2015 10:37:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=p5Z6rLyBCjqjeVZr/K9ua3W1tKUhzFW4KF9BAr3dwWA=; b=d22E2iP3sjK6ScKlo2sAIwLOHmd34IC1S71lHG5eWw9BqKpOrUgooMru8FZ3Cs8i3R rPJsuJa/s74a1G0UKXGE60+3iDz3aW99Qw2fj0u2sB+dKtlYm4U/YfAFAxKjaKF53e7F wB4YmdbjFMLiUWvEua0h2cS3KcBdZMFkqh4ArEimQbIhyeugZZHWPqED0ZPa8Qn/1D1n KnDaMf+Ut9WVt72Addo3dTMnbm6UNecRP8jBrymKLgEpbKdEgzZrGISHeip4ZM9QRRcr yXSpF2tPzlAc2dfyVuNEJmSBsI41eOiBfnnQ6518881BY5uZiGBRsQuDj+dDZ+OnOXIC iTJg== X-Received: by 10.140.106.101 with SMTP id d92mr6157665qgf.70.1438364224993; Fri, 31 Jul 2015 10:37:04 -0700 (PDT) Received: from localhost (APoitiers-257-1-125-104.w109-215.abo.wanadoo.fr. [109.215.44.104]) by smtp.gmail.com with ESMTPSA id q74sm1255208qkh.35.2015.07.31.10.37.02 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Jul 2015 10:37:03 -0700 (PDT) From: marcandre.lureau@redhat.com To: qemu-devel@nongnu.org Date: Fri, 31 Jul 2015 19:36:48 +0200 Message-Id: <1438364209-24940-3-git-send-email-marcandre.lureau@redhat.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1438364209-24940-1-git-send-email-marcandre.lureau@redhat.com> References: <1438364209-24940-1-git-send-email-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400d:c04::234 Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , mdroth@linux.vnet.ibm.com, jbelka@redhat.com Subject: [Qemu-devel] [RFC 2/3] qga: implement get-memory-info for Linux X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Marc-André Lureau Signed-off-by: Marc-André Lureau --- qga/commands-posix.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++-- qga/main.c | 28 ++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index eb4036e..9534c2d 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -28,6 +28,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/queue.h" #include "qemu/host-utils.h" +#include "glib-compat.h" #ifndef CONFIG_HAS_ENVIRON #ifdef __APPLE__ @@ -2328,10 +2329,99 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp) return info; } +static long meminfo_value(gchar * const *col) +{ + int i; + + g_return_val_if_fail(col && col[0], 0); + + for (i = 1; col[i]; i++) { + if (strlen(col[i]) > 0) { + return g_ascii_strtoll(col[i], NULL, 10); + } + } + + g_return_val_if_reached(0); +} + GuestMemoryInfo *qmp_guest_get_memory_info(Error **errp) { - error_setg(errp, QERR_UNSUPPORTED); - return NULL; + static guint64 last_time, last_swap_in, last_swap_out; + static guint64 last_pf_major, last_pf_minor; + GError *err = NULL; + GuestMemoryInfo *info; + gchar *contents = NULL; + gchar **lines; + int i; + guint64 time; + + if (!g_file_get_contents("/proc/meminfo", &contents, NULL, &err)) { + error_setg(errp, "unable to read meminfo: %s", err->message); + g_clear_error(&err); + return NULL; + } + + info = g_new0(GuestMemoryInfo, 1); + + lines = g_strsplit(contents, "\n", -1); + for (i = 0; lines[i]; i++) { + gchar **col = g_strsplit(lines[i], " ", -1); + if (g_strcmp0(col[0], "MemTotal:") == 0) { + info->mem_total = meminfo_value(col); + } else if (g_strcmp0(col[0], "MemAvailable:") == 0) { + /* available since kernel 3.2 */ + info->mem_free = meminfo_value(col); + } else if (g_strcmp0(col[0], "Cached:") == 0) { + info->mem_cached = meminfo_value(col); + } else if (g_strcmp0(col[0], "SwapTotal:") == 0) { + info->swap_total = meminfo_value(col); + } else if (g_strcmp0(col[0], "SwapFree:") == 0) { + info->swap_free = meminfo_value(col); + } + g_strfreev(col); + } + g_strfreev(lines); + + g_free(contents); + + if (!g_file_get_contents("/proc/vmstat", &contents, NULL, &err)) { + error_setg(errp, "unable to read meminfo: %s", err->message); + g_clear_error(&err); + g_free(info); + return NULL; + } + + time = g_get_monotonic_time(); + double elapsed = (time - last_time + 1) / (double)G_USEC_PER_SEC; + +#define UPDATE(Field) do { \ + guint64 val = g_ascii_strtoll(col[1], NULL, 10); \ + info->Field = (val - last_ ##Field) / elapsed; \ + last_ ##Field = val; \ +} while (0) + + lines = g_strsplit(contents, "\n", -1); + for (i = 0; lines[i]; i++) { + gchar **col = g_strsplit(lines[i], " ", -1); + if (g_strcmp0(col[0], "pswpin") == 0) { + UPDATE(swap_in); + } else if (g_strcmp0(col[0], "pswpout") == 0) { + UPDATE(swap_out); + } else if (g_strcmp0(col[0], "pgfault") == 0) { + UPDATE(pf_minor); + } else if (g_strcmp0(col[0], "pgmajfault") == 0) { + UPDATE(pf_major); + } + g_strfreev(col); + } + g_strfreev(lines); + +#undef UPDATE + + last_time = time; + g_free(contents); + + return info; } #else /* defined(__linux__) */ diff --git a/qga/main.c b/qga/main.c index aef007b..4790e26 100644 --- a/qga/main.c +++ b/qga/main.c @@ -42,6 +42,7 @@ #define CONFIG_FSFREEZE #endif #endif +#include "qga-qmp-commands.h" #ifndef _WIN32 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0" @@ -901,6 +902,31 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp) return handle; } +static void initialize_memory_stats(void) +{ + GuestMemoryInfo *info = qmp_guest_get_memory_info(NULL); + + if (!info) { + return; + } + + /* just for checking at start if everything looks ok */ + g_debug("mem-total: %" G_GUINT64_FORMAT " kB\n" + "mem-free: %" G_GUINT64_FORMAT " kB\n" + "mem-cached: %" G_GUINT64_FORMAT " kB\n" + "swap-total: %" G_GUINT64_FORMAT " kB\n" + "swap-free: %" G_GUINT64_FORMAT " kB\n" + "swap-in: %" G_GUINT64_FORMAT " kB\n" + "swap-out: %" G_GUINT64_FORMAT " kB\n" + "pf-major: %" G_GUINT64_FORMAT " kB\n" + "pf-minor: %" G_GUINT64_FORMAT " kB\n", + info->mem_total, info->mem_free, info->mem_cached, + info->swap_total, info->swap_free, info->swap_in, info->swap_out, + info->pf_major, info->pf_minor); + + g_free(info); +} + static void ga_print_cmd(QmpCommand *cmd, void *opaque) { printf("%s\n", qmp_command_name(cmd)); @@ -1256,6 +1282,8 @@ static int run_agent(GAState *s) } #endif + initialize_memory_stats(); + s->main_loop = g_main_loop_new(NULL, false); if (!channel_init(ga_state, method, device_path)) { g_critical("failed to initialize guest agent channel");