From: Oliver Kurth Date: Tue, 24 Apr 2018 00:08:18 +0000 (-0700) Subject: Add new guest metrics to be consumed by vROps. X-Git-Tag: stable-10.3.0~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=995befcb0d6156fb47773c96db6d478173d1bc89;p=thirdparty%2Fopen-vm-tools.git Add new guest metrics to be consumed by vROps. Windows: * ProcessorQueueLength * CurrentDiskQueueLength * AvgDiskQueueLength Linux: * CPU run queue size * Current disk queue size * Average disk queue size --- diff --git a/open-vm-tools/lib/include/guestStats.h b/open-vm-tools/lib/include/guestStats.h index d5af939cf..c59b97c88 100644 --- a/open-vm-tools/lib/include/guestStats.h +++ b/open-vm-tools/lib/include/guestStats.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008-2017 VMware, Inc. All rights reserved. + * Copyright (C) 2008-2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -33,6 +33,8 @@ #include "vm_assert.h" #include "vm_basic_types.h" +#define PUBLISH_EXPERIMENTAL_STATS 0 + /* * Version 1: Legacy data * Version 2: Dead @@ -244,7 +246,7 @@ typedef enum { /* * Defined stat IDs for guest tools builtin query. - * See vmx/vigorapi/guestStats.java for documentation + * See vmx/vigorapi/GuestStats.java for documentation * * NOTE: These IDs are relative to GUEST_TOOLS_NAMESPACE * NOTE: DO NOT re-order or remove the IDs. IDs can only be added to the end, @@ -252,7 +254,7 @@ typedef enum { * of bumping the namespace version. */ #define GUEST_STAT_TOOLS_IDS \ - /* 2015u1 stats */ \ + /* 6.0u1 stats */ \ DEFINE_GUEST_STAT(GuestStatID_Invalid, 0, "__INVALID__") \ DEFINE_GUEST_STAT(GuestStatID_None, 1, "__NONE__") \ DEFINE_GUEST_STAT(GuestStatID_ContextSwapRate, 2, "guest.contextSwapRate") \ @@ -266,7 +268,7 @@ typedef enum { DEFINE_GUEST_STAT(GuestStatID_PhysicalPageSize, 10, "guest.page.size") \ DEFINE_GUEST_STAT(GuestStatID_HugePageSize, 11, "guest.hugePage.size") \ DEFINE_GUEST_STAT(GuestStatID_Linux_HugePagesTotal, 12, "guest.hugePage.total") \ - /* 2016 stats */ \ + /* 6.5 stats */ \ DEFINE_GUEST_STAT(GuestStatID_MemNeededReservation, 13, "guest.mem.neededReservation") \ DEFINE_GUEST_STAT(GuestStatID_PageSwapInRate, 14, "guest.swap.pageInRate") \ DEFINE_GUEST_STAT(GuestStatID_PageSwapOutRate, 15, "guest.swap.pageOutRate") \ @@ -315,7 +317,14 @@ typedef enum { DEFINE_GUEST_STAT(GuestStatID_Windows_DiskWriteRate, 58, "guest.disk.writeRate") \ DEFINE_GUEST_STAT(GuestStatID_Windows_AutomaticSwapFileMax, 59, "guest.swap.automaticFileMax") \ DEFINE_GUEST_STAT(GuestStatID_Linux_MemTotal, 60, "guest.mem.total") \ - DEFINE_GUEST_STAT(GuestStatID_Max, 61, "__MAX__") + /* (6.7, ] stats */ \ + DEFINE_GUEST_STAT(GuestStatID_Linux_CpuRunQueue, 61, "guest.cpu.runQueue") \ + DEFINE_GUEST_STAT(GuestStatID_Linux_DiskRequestQueue, 62, "guest.disk.requestQueue") \ + DEFINE_GUEST_STAT(GuestStatID_Linux_DiskRequestQueueAvg, 63, "guest.disk.requestQueueAvg") \ + DEFINE_GUEST_STAT(GuestStatID_Windows_ProcessorQueue, 64, "guest.processor.queue") \ + DEFINE_GUEST_STAT(GuestStatID_Windows_DiskQueue, 65, "guest.disk.queue") \ + DEFINE_GUEST_STAT(GuestStatID_Windows_DiskQueueAvg, 66, "guest.disk.queueAvg") \ + DEFINE_GUEST_STAT(GuestStatID_Max, 67, "__MAX__") /* * Define stats enumeration diff --git a/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c b/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c index fe55037a0..731b9b008 100644 --- a/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c +++ b/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 1998-2017 VMware, Inc. All rights reserved. + * Copyright (C) 1998-2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -1700,7 +1700,7 @@ GuestInfoServerShutdown(gpointer src, gatherStatsTimeoutSource = NULL; } -#if !defined(__APPLE__) +#if defined(__linux__) || defined(USERWORLD) || defined(_WIN32) GuestInfo_StatProviderShutdown(); #endif diff --git a/open-vm-tools/services/plugins/guestInfo/perfMonLinux.c b/open-vm-tools/services/plugins/guestInfo/perfMonLinux.c index d5ea95136..e6c551e42 100644 --- a/open-vm-tools/services/plugins/guestInfo/perfMonLinux.c +++ b/open-vm-tools/services/plugins/guestInfo/perfMonLinux.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2008-2017 VMware, Inc. All rights reserved. + * Copyright (C) 2008-2018 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -25,15 +25,18 @@ #include "vm_basic_defs.h" #include "vmware.h" +#include "str.h" #include "strutil.h" #include "debug.h" #include "guestInfoInt.h" #include "guestStats.h" #include "posix.h" #include "hashTable.h" +#include "conf.h" #define GUEST_INFO_PREALLOC_SIZE 4096 #define INT_AS_HASHKEY(x) ((const void *)(uintptr_t)(x)) +#define KEY_FORMAT "%s|%s" #define STAT_FILE "/proc/stat" #define VMSTAT_FILE "/proc/vmstat" @@ -41,26 +44,28 @@ #define MEMINFO_FILE "/proc/meminfo" #define ZONEINFO_FILE "/proc/zoneinfo" #define SWAPPINESS_FILE "/proc/sys/vm/swappiness" +#define DISKSTATS_FILE "/proc/diskstats" -#define PUBLISH_P1_2015_STATS 1 -#define PUBLISH_P1_2016_STATS 1 -#define PUBLISH_P2_STATS 1 +#define SYSFS_BLOCK_FOLDER "/sys/block" /* * For now, all data collection is of uint64 values. Rates are always returned * as a double, derived from the uint64 data. - * - * TODO: Deal with collected and reported data types being different. */ -#define STAT_FLAG(x) PUBLISH_##x##_STATS -#define DECLARE_STAT(collect, publish, file, isRegExp, locatorString, reportID, units, dataType) \ - { file, STAT_FLAG(collect), STAT_FLAG(publish), isRegExp, locatorString, reportID, units, dataType } +static Bool gReleased = TRUE; +static Bool gInternal = FALSE; +#if PUBLISH_EXPERIMENTAL_STATS +static Bool gExperimental = PUBLISH_EXPERIMENTAL_STATS; +#endif +static Bool gUnstable = FALSE; + +#define DECLARE_STAT(publish, file, isRegExp, locatorString, reportID, units, dataType) \ + { file, publish, isRegExp, locatorString, reportID, units, dataType } typedef struct { const char *sourceFile; - Bool collect; - Bool publish; + const Bool *publish; Bool isRegExp; const char *locatorString; GuestStatToolsID reportID; @@ -69,54 +74,63 @@ typedef struct { } GuestInfoQuery; GuestInfoQuery guestInfoQuerySpecTable[] = { - DECLARE_STAT(P1_2015, P1_2015, MEMINFO_FILE, FALSE, "Hugepagesize", GuestStatID_HugePageSize, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2015, ZONEINFO_FILE,TRUE, "present", GuestStatID_MemPhysUsable, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2015, MEMINFO_FILE, FALSE, "MemFree", GuestStatID_MemFree, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2015, MEMINFO_FILE, FALSE, "Active(file)", GuestStatID_MemActiveFileCache, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2015, MEMINFO_FILE, FALSE, "SwapFree", GuestStatID_SwapSpaceRemaining, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2015, MEMINFO_FILE, FALSE, "HugePages_Total", GuestStatID_Linux_HugePagesTotal, GuestUnitsHugePages, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2015, VMSTAT_FILE, FALSE, "pgpgin", GuestStatID_PageInRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P1_2015, P1_2015, VMSTAT_FILE, FALSE, "pgpgout", GuestStatID_PageOutRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P1_2015, P1_2015, STAT_FILE, FALSE, "ctxt", GuestStatID_ContextSwapRate, GuestUnitsNumberPerSecond, GuestTypeDouble), - DECLARE_STAT(P1_2015, P1_2015, NULL, FALSE, NULL, GuestStatID_PhysicalPageSize, GuestUnitsBytes, GuestTypeUint64), - - DECLARE_STAT(P1_2015, P1_2016, MEMINFO_FILE, FALSE, "MemAvailable", GuestStatID_Linux_MemAvailable, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2016, MEMINFO_FILE, FALSE, "Inactive(file)", GuestStatID_Linux_MemInactiveFile, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2016, MEMINFO_FILE, FALSE, "SReclaimable", GuestStatID_Linux_MemSlabReclaim, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2016, MEMINFO_FILE, FALSE, "Buffers", GuestStatID_Linux_MemBuffers, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2016, MEMINFO_FILE, FALSE, "Cached", GuestStatID_Linux_MemCached, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P1_2016, NULL, FALSE, NULL, GuestStatID_SwapSpaceUsed, GuestUnitsKiB, GuestTypeUint64), - - DECLARE_STAT(P1_2015, P2, MEMINFO_FILE, FALSE, "MemTotal", GuestStatID_Linux_MemTotal, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P2, MEMINFO_FILE, FALSE, "SwapTotal", GuestStatID_SwapFilesCurrent, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P2, NULL, FALSE, NULL, GuestStatID_SwapFilesMax, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2015, P2, ZONEINFO_FILE, TRUE, "low", GuestStatID_Linux_LowWaterMark, GuestUnitsPages, GuestTypeUint64), - -#if PUBLISH_P1_2016_STATS - DECLARE_STAT(P1_2016, P1_2016, MEMINFO_FILE, FALSE, "Active(anon)", GuestStatID_Linux_MemActiveAnon, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2016, P1_2016, MEMINFO_FILE, FALSE, "Inactive(anon)", GuestStatID_Linux_MemInactiveAnon, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2016, P1_2016, MEMINFO_FILE, FALSE, "Inactive", GuestStatID_Linux_MemInactive, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2016, P1_2016, MEMINFO_FILE, FALSE, "Active", GuestStatID_Linux_MemActive, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2016, P1_2016, MEMINFO_FILE, FALSE, "Unevictable", GuestStatID_Linux_MemPinned, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2016, P1_2016, MEMINFO_FILE, FALSE, "Dirty", GuestStatID_Linux_MemDirty, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P1_2016, P1_2016, VMSTAT_FILE, FALSE, "pswpin", GuestStatID_PageSwapInRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P1_2016, P1_2016, VMSTAT_FILE, FALSE, "pswpout", GuestStatID_PageSwapOutRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P1_2016, P1_2016, NULL, FALSE, NULL, GuestStatID_ThreadCreationRate, GuestUnitsNumberPerSecond, GuestTypeDouble), - DECLARE_STAT(P1_2016, P1_2016, SWAPPINESS_FILE, FALSE, NULL, GuestStatID_Linux_Swappiness, GuestUnitsPercent, GuestTypeUint64), + DECLARE_STAT(&gReleased, MEMINFO_FILE, FALSE, "Hugepagesize", GuestStatID_HugePageSize, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gReleased, ZONEINFO_FILE, TRUE, "present", GuestStatID_MemPhysUsable, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gReleased, MEMINFO_FILE, FALSE, "MemFree", GuestStatID_MemFree, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gReleased, MEMINFO_FILE, FALSE, "Active(file)", GuestStatID_MemActiveFileCache, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gReleased, MEMINFO_FILE, FALSE, "SwapFree", GuestStatID_SwapSpaceRemaining, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gReleased, MEMINFO_FILE, FALSE, "HugePages_Total", GuestStatID_Linux_HugePagesTotal, GuestUnitsHugePages, GuestTypeUint64), + DECLARE_STAT(&gReleased, VMSTAT_FILE, FALSE, "pgpgin", GuestStatID_PageInRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gReleased, VMSTAT_FILE, FALSE, "pgpgout", GuestStatID_PageOutRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gReleased, STAT_FILE, FALSE, "ctxt", GuestStatID_ContextSwapRate, GuestUnitsNumberPerSecond, GuestTypeDouble), + DECLARE_STAT(&gReleased, NULL, FALSE, NULL, GuestStatID_PhysicalPageSize, GuestUnitsBytes, GuestTypeUint64), + DECLARE_STAT(&gReleased, NULL, FALSE, NULL, GuestStatID_MemNeeded, GuestUnitsKiB, GuestTypeUint64), + + DECLARE_STAT(&gReleased, NULL, FALSE, NULL, GuestStatID_MemNeededReservation, GuestUnitsKiB, GuestTypeUint64), + + DECLARE_STAT(&gInternal, MEMINFO_FILE, FALSE, "MemAvailable", GuestStatID_Linux_MemAvailable, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gInternal, MEMINFO_FILE, FALSE, "Inactive(file)", GuestStatID_Linux_MemInactiveFile, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gInternal, MEMINFO_FILE, FALSE, "SReclaimable", GuestStatID_Linux_MemSlabReclaim, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gInternal, MEMINFO_FILE, FALSE, "Buffers", GuestStatID_Linux_MemBuffers, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gInternal, MEMINFO_FILE, FALSE, "Cached", GuestStatID_Linux_MemCached, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gInternal, ZONEINFO_FILE, TRUE, "low", GuestStatID_Linux_LowWaterMark, GuestUnitsPages, GuestTypeUint64), + DECLARE_STAT(&gInternal, MEMINFO_FILE, FALSE, "MemTotal", GuestStatID_Linux_MemTotal, GuestUnitsKiB, GuestTypeUint64), + +#if PUBLISH_EXPERIMENTAL_STATS + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "SwapTotal", GuestStatID_SwapFilesCurrent, GuestUnitsKiB, GuestTypeUint64), + /* GuestStatID_SwapSpaceUsed depends on GuestStatID_SwapFilesCurrent */ + DECLARE_STAT(&gExperimental, NULL, FALSE, NULL, GuestStatID_SwapSpaceUsed, GuestUnitsKiB, GuestTypeUint64), + /* GuestStatID_SwapFilesMax depends on GuestStatID_SwapFilesCurrent */ + DECLARE_STAT(&gExperimental, NULL, FALSE, NULL, GuestStatID_SwapFilesMax, GuestUnitsKiB, GuestTypeUint64), + + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "Active(anon)", GuestStatID_Linux_MemActiveAnon, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "Inactive(anon)", GuestStatID_Linux_MemInactiveAnon, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "Inactive", GuestStatID_Linux_MemInactive, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "Active", GuestStatID_Linux_MemActive, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "Unevictable", GuestStatID_Linux_MemPinned, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "Dirty", GuestStatID_Linux_MemDirty, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, FALSE, "pswpin", GuestStatID_PageSwapInRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, FALSE, "pswpout", GuestStatID_PageSwapOutRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + /* Not implemented + DECLARE_STAT(&gExperimental, NULL, FALSE, NULL, GuestStatID_ThreadCreationRate, GuestUnitsNumberPerSecond, GuestTypeDouble), + */ + DECLARE_STAT(&gExperimental, SWAPPINESS_FILE, FALSE, NULL, GuestStatID_Linux_Swappiness, GuestUnitsPercent, GuestTypeUint64), + + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "SwapCached", GuestStatID_Linux_MemSwapCached, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "Committed_AS", GuestStatID_Linux_MemCommitted, GuestUnitsKiB, GuestTypeUint64), + DECLARE_STAT(&gExperimental, MEMINFO_FILE, FALSE, "HugePages_Free", GuestStatID_Linux_HugePagesFree, GuestUnitsHugePages, GuestTypeUint64), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, FALSE, "pgfault", GuestStatID_Linux_PageFaultRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, FALSE, "pgmajfault", GuestStatID_Linux_PageMajorFaultRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, FALSE, "pgfree", GuestStatID_Linux_PageFreeRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, TRUE, "pgsteal_", GuestStatID_Linux_PageStealRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, TRUE, "pgscan_kswapd_", GuestStatID_Linux_PageSwapScanRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gExperimental, VMSTAT_FILE, TRUE, "pgscan_direct_", GuestStatID_Linux_PageDirectScanRate, GuestUnitsPagesPerSecond, GuestTypeDouble), + DECLARE_STAT(&gExperimental, STAT_FILE, FALSE, "processes", GuestStatID_ProcessCreationRate, GuestUnitsNumberPerSecond, GuestTypeDouble), #endif -#if PUBLISH_P2_STATS - DECLARE_STAT(P2, P2, MEMINFO_FILE, FALSE, "SwapCached", GuestStatID_Linux_MemSwapCached, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P2, P2, MEMINFO_FILE, FALSE, "Committed_AS", GuestStatID_Linux_MemCommitted, GuestUnitsKiB, GuestTypeUint64), - DECLARE_STAT(P2, P2, MEMINFO_FILE, FALSE, "HugePages_Free", GuestStatID_Linux_HugePagesFree, GuestUnitsHugePages, GuestTypeUint64), - DECLARE_STAT(P2, P2, VMSTAT_FILE, FALSE, "pgfault", GuestStatID_Linux_PageFaultRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P2, P2, VMSTAT_FILE, FALSE, "pgmajfault", GuestStatID_Linux_PageMajorFaultRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P2, P2, VMSTAT_FILE, FALSE, "pgfree", GuestStatID_Linux_PageFreeRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P2, P2, VMSTAT_FILE, TRUE, "pgsteal_", GuestStatID_Linux_PageStealRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P2, P2, VMSTAT_FILE, TRUE, "pgscan_kswapd_", GuestStatID_Linux_PageSwapScanRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P2, P2, VMSTAT_FILE, TRUE, "pgscan_direct_", GuestStatID_Linux_PageDirectScanRate, GuestUnitsPagesPerSecond, GuestTypeDouble), - DECLARE_STAT(P2, P2, STAT_FILE, FALSE, "processes", GuestStatID_ProcessCreationRate, GuestUnitsNumberPerSecond, GuestTypeDouble), -#endif + DECLARE_STAT(&gUnstable, STAT_FILE, FALSE, "procs_running", GuestStatID_Linux_CpuRunQueue, GuestUnitsNumber, GuestTypeUint64), + DECLARE_STAT(&gUnstable, NULL, FALSE, NULL, GuestStatID_Linux_DiskRequestQueue, GuestUnitsNumber, GuestTypeUint64), + DECLARE_STAT(&gUnstable, NULL, FALSE, NULL, GuestStatID_Linux_DiskRequestQueueAvg, GuestUnitsNumber, GuestTypeDouble), }; #define N_QUERIES (sizeof guestInfoQuerySpecTable / sizeof(GuestInfoQuery)) @@ -143,6 +157,78 @@ typedef struct { double timeStamp; } GuestInfoCollector; +static GuestInfoCollector *gCurrentCollector = NULL; +static GuestInfoCollector *gPreviousCollector = NULL; + +static void +GuestInfoDeriveMemNeeded(GuestInfoCollector *collector); + +typedef struct GuestInfoDiskStatsList { + struct GuestInfoDiskStatsList *next; + char *diskName; + unsigned int weightedTime[2]; // In milliseconds +} GuestInfoDiskStatsList; + +static GuestInfoDiskStatsList *gDiskStatsList = NULL; + + +/* + *---------------------------------------------------------------------- + * + * GuestInfoDeleteDiskStatsList -- + * + * Delete disk device stats list. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GuestInfoDeleteDiskStatsList(GuestInfoDiskStatsList *head) // IN/OUT: +{ + GuestInfoDiskStatsList *curr = head; + + while (curr != NULL) { + GuestInfoDiskStatsList *next = curr->next; + free(curr->diskName); + free(curr); + curr = next; + } +} + + +/* + *---------------------------------------------------------------------- + * + * GuestInfoIsBlockDevice -- + * + * Verify block device name. + * + * Results: + * TRUE name is block device name + * FALSE otherwise + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Bool +GuestInfoIsBlockDevice(const char *name) // IN: +{ + char path[PATH_MAX]; // PATH_MAX is defined to 4096 + + Str_Sprintf(path, sizeof path, "%s/%s", SYSFS_BLOCK_FOLDER, name); + + return (access(path, F_OK) == 0); +} + /* *---------------------------------------------------------------------- @@ -172,7 +258,7 @@ GuestInfoGetUpTime(double *now) // OUT: return result; } - if (fgets(line, sizeof line, fp) != NULL) { + if (fgets(line, sizeof line, fp) == line) { double idle; if (sscanf(line, "%lf %lf", now, &idle) == 2) { @@ -203,39 +289,35 @@ GuestInfoGetUpTime(double *now) // OUT: */ static void -GuestInfoStoreStat(const char *pathName, // IN: file stat is in - GuestInfoStat *stat, // IN/OUT: stat +GuestInfoStoreStat(GuestInfoStat *stat, // IN/OUT: stat uint64 value) // IN: value to be added to stat { ASSERT(stat); - ASSERT(stat->query); // TODO: consider supporting regexp here. - if (strcmp(stat->query->sourceFile, pathName) == 0) { - switch (stat->err) { - case 0: - ASSERT(stat->count != 0); - - if (((stat->count + 1) < stat->count) || - ((stat->value + value) < stat->value)) { - stat->err = EOVERFLOW; - } else { - stat->count++; - stat->value += value; - } - break; + switch (stat->err) { + case 0: + ASSERT(stat->count != 0); - case ENOENT: - ASSERT(stat->count == 0); + if (((stat->count + 1) < stat->count) || + ((stat->value + value) < stat->value)) { + stat->err = EOVERFLOW; + } else { + stat->count++; + stat->value += value; + } + break; - stat->err = 0; - stat->count = 1; - stat->value = value; - break; + case ENOENT: + ASSERT(stat->count == 0); - default: // Some sort of error - sorry, thank you for playing... - break; - } + stat->err = 0; + stat->count = 1; + stat->value = value; + break; + + default: // Some sort of error - sorry, thank you for playing... + break; } } @@ -243,13 +325,9 @@ GuestInfoStoreStat(const char *pathName, // IN: file stat is in /* *---------------------------------------------------------------------- * - * GuestInfoCollectStat -- - * - * Collect a stat. + * GuestInfoStoreStatByID -- * - * NOTE: Exact match data cannot be used in a regExp. This is a - * performance choice. We can discuss this when we have full - * programmability. + * Store a stat value by its ID. * * Results: * None. @@ -261,41 +339,32 @@ GuestInfoStoreStat(const char *pathName, // IN: file stat is in */ static void -GuestInfoCollectStat(const char *pathName, // IN: - GuestInfoCollector *collector, // IN/OUT: - const char *fieldName, // IN: - uint64 value) // IN: +GuestInfoStoreStatByID(GuestStatToolsID reportID, // IN: + GuestInfoCollector *collector, // IN/OUT: + uint64 value) // IN: { GuestInfoStat *stat = NULL; - if (!HashTable_Lookup(collector->exactMatches, fieldName, (void **) &stat)) { - uint32 i; - - for (i = 0; i < collector->numRegExps; i++) { - GuestInfoStat *thisOne = collector->regExps[i]; - - if (StrUtil_StartsWith(fieldName, thisOne->query->locatorString)) { - stat = thisOne; - } - } - } + HashTable_Lookup(collector->reportMap, + INT_AS_HASHKEY(reportID), + (void **) &stat); - if (stat != NULL) { - GuestInfoStoreStat(pathName, stat, value); - } + GuestInfoStoreStat(stat, value); } /* *---------------------------------------------------------------------- * - * GuestInfoReadProcMemInfoData -- + * GuestInfoCollectStat -- * - * Reads /proc/meminfo to contribute to a collection. + * Collect a stat. + * + * NOTE: Exact match data cannot be used in a regExp. This is a + * performance choice. * * Results: - * TRUE Success! - * FALSE Failure! + * None. * * Side effects: * None. @@ -303,45 +372,34 @@ GuestInfoCollectStat(const char *pathName, // IN: *---------------------------------------------------------------------- */ -static Bool -GuestInfoProcMemInfoData(GuestInfoCollector *collector) // IN: +static void +GuestInfoCollectStat(const char *pathName, // IN: + GuestInfoCollector *collector, // IN/OUT: + const char *fieldName, // IN: + uint64 value) // IN: { - char line[512]; - FILE *fp = Posix_Fopen(MEMINFO_FILE, "r"); - - if (fp == NULL) { - g_warning("%s: Error opening " MEMINFO_FILE ".\n", __FUNCTION__); - return FALSE; - } - - while (fgets(line, sizeof line, fp) == line) { - char *p; - uint64 value = 0; - char *fieldName = strtok(line, " \t"); - char *fieldData = strtok(NULL, " \t"); + GuestInfoStat *stat = NULL; + char *key = Str_SafeAsprintf(NULL, KEY_FORMAT, pathName, fieldName); - if (fieldName == NULL) { - continue; - } + if (!HashTable_Lookup(collector->exactMatches, key, (void **) &stat)) { + uint32 i; - p = strrchr(fieldName, ':'); - if (p == NULL) { - continue; - } else { - *p = '\0'; - } + for (i = 0; i < collector->numRegExps; i++) { + GuestInfoStat *thisOne = collector->regExps[i]; - if ((fieldData == NULL) || - (sscanf(fieldData, "%"FMT64"u", &value) != 1)) { - continue; + if (strcmp(pathName, thisOne->query->sourceFile) == 0 && + StrUtil_StartsWith(fieldName, thisOne->query->locatorString)) { + stat = thisOne; + break; + } } - - GuestInfoCollectStat(MEMINFO_FILE, collector, fieldName, value); } - fclose(fp); + free(key); - return TRUE; + if (stat != NULL) { + GuestInfoStoreStat(stat, value); + } } @@ -350,7 +408,11 @@ GuestInfoProcMemInfoData(GuestInfoCollector *collector) // IN: * * GuestInfoProcData -- * - * Reads a "stat file" and contribute to the collection. + * Reads a "stat file" and contributes to the collection. + * + * NOTE: If caller specifies a fieldSeparator, it has to be present + * in the fieldName being parsed. '\0' represents an unspecified + * fieldSeparator. * * Results: * TRUE Success! @@ -364,9 +426,10 @@ GuestInfoProcMemInfoData(GuestInfoCollector *collector) // IN: static Bool GuestInfoProcData(const char *pathName, // IN: path name - GuestInfoCollector *collector) // IN: + char fieldSeparator, // IN/OPT: + GuestInfoCollector *collector) // IN/OUT: { - char line[4096]; + char line[4096]; // Close to length of /proc/stat intr line FILE *fp = Posix_Fopen(pathName, "r"); if (fp == NULL) { @@ -374,15 +437,34 @@ GuestInfoProcData(const char *pathName, // IN: path name return FALSE; } - while (fgets(line, sizeof line, fp) != NULL) { + /* + * If a line inside the file is longer than what the buffer can hold, + * fgets still succeeds, the next fgets call continues at the previously + * stopped location in the line. + */ + while (fgets(line, sizeof line, fp) == line) { uint64 value = 0; - char *fieldName = strtok(line, " \t"); - char *fieldData = strtok(NULL, " \t"); + char *savedPtr = NULL; + char *fieldName = strtok_r(line, " \t", &savedPtr); + char *fieldData = strtok_r(NULL, " \t", &savedPtr); if (fieldName == NULL) { continue; } + if (fieldSeparator != '\0') { + char *p = strrchr(fieldName, fieldSeparator); + if (p == NULL) { + /* + * When fieldSeparator is specified, fieldName is expected + * to have it. + */ + continue; + } else { + *p = '\0'; + } + } + if ((fieldData == NULL) || (sscanf(fieldData, "%"FMT64"u", &value) != 1)) { continue; @@ -402,7 +484,7 @@ GuestInfoProcData(const char *pathName, // IN: path name * * GuestInfoProcSimpleValue -- * - * Reads the specified /proc file, extracts a single, simple value and + * Reads the stat /proc file, extracts a single, simple value and * adds it to the collection. * * Results: @@ -414,42 +496,47 @@ GuestInfoProcData(const char *pathName, // IN: path name * *---------------------------------------------------------------------- */ -#if PUBLISH_P1_2016_STATS +#if PUBLISH_EXPERIMENTAL_STATS static Bool -GuestInfoProcSimpleValue(const char *pathName, // IN: - GuestStatToolsID reportID, // IN: +GuestInfoProcSimpleValue(GuestStatToolsID reportID, // IN: GuestInfoCollector *collector) // IN/OUT: { - char line[4096]; - uint64 value = 0; - FILE *fp = Posix_Fopen(pathName, "r"); + char line[512]; + uint64 value; + FILE *fp; Bool success = FALSE; + GuestInfoStat *stat = NULL; + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(reportID), + (void **) &stat); + ASSERT(stat); + if (stat == NULL) { + g_warning("%s: Error stat ID %d not found.\n", __FUNCTION__, reportID); + return success; + } + + ASSERT(stat->query->sourceFile); + fp = Posix_Fopen(stat->query->sourceFile, "r"); if (fp == NULL) { - g_warning("%s: Error opening %s.\n", __FUNCTION__, pathName); + g_warning("%s: Error opening %s.\n", + __FUNCTION__, stat->query->sourceFile); return success; } - if (fgets(line, sizeof line, fp) != NULL) { + if (fgets(line, sizeof line, fp) == line) { + value = 0; if (sscanf(line, "%"FMT64"u", &value) == 1) { + stat->err = 0; + stat->count = 1; + stat->value = value; + success = TRUE; } } fclose(fp); - if (success) { - GuestInfoStat *stat = NULL; - - HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(reportID), - (void **) &stat); - - if (stat != NULL) { - GuestInfoStoreStat(pathName, stat, value); - } - } - return success; } #endif @@ -470,9 +557,10 @@ GuestInfoProcSimpleValue(const char *pathName, // IN: * *---------------------------------------------------------------------- */ +#if PUBLISH_EXPERIMENTAL_STATS static void -GuestInfoDeriveSwapData(GuestInfoCollector *collector) // IN: current collection +GuestInfoDeriveSwapData(GuestInfoCollector *collector) // IN/OUT: { uint64 swapFree = 0; uint64 swapTotal = 0; @@ -521,7 +609,6 @@ GuestInfoDeriveSwapData(GuestInfoCollector *collector) // IN: current collectio ASSERT(swapTotal >= swapFree); swapUsed = (swapTotal >= swapFree) ? swapTotal - swapFree : 0; - if ((swapSpaceUsed != NULL) && (swapSpaceUsed->err != 0)) { swapSpaceUsed->value = swapUsed; swapSpaceUsed->count = 1; @@ -530,6 +617,177 @@ GuestInfoDeriveSwapData(GuestInfoCollector *collector) // IN: current collectio } } } +#endif + + +/* + *---------------------------------------------------------------------- + * + * GuestInfoDecreaseCpuRunQueueByOne -- + * + * Exclude the collector thread, make the result be consistent with + * "sar -q". + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GuestInfoDecreaseCpuRunQueueByOne(GuestInfoCollector *collector) // IN/OUT: +{ + GuestInfoStat *stat = NULL; + + HashTable_Lookup(collector->reportMap, + INT_AS_HASHKEY(GuestStatID_Linux_CpuRunQueue), + (void **) &stat); + + ASSERT(stat != NULL); + ASSERT(stat->err == 0); + ASSERT(stat->count == 1); + if (stat != NULL && stat->err == 0 && stat->count == 1) { + if (stat->value > 0) { + stat->value--; + } + } +} + + +/* + *---------------------------------------------------------------------- + * + * GuestInfoProcDiskStatsData -- + * + * Reads /proc/diskstats, extract disk request queue stats and + * adds them to the collection. + * + * Results: + * TRUE Success! + * FALSE Failure! + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Bool +GuestInfoProcDiskStatsData(GuestInfoCollector *collector) // IN/OUT: +{ + static int curr = 0; + + int prev; + GuestInfoDiskStatsList **listItem; + uint64 inflightIOsSum; + Bool setStats; // Only when no disk device change in between + + char line[512]; + FILE *fp = Posix_Fopen(DISKSTATS_FILE, "r"); + + if (fp == NULL) { + g_warning("%s: Error opening " DISKSTATS_FILE ".\n", __FUNCTION__); + return FALSE; + } + + prev = curr ^ 1; // curr = 0 => prev = 1; curr = 1 => prev = 0 + listItem = &gDiskStatsList; + inflightIOsSum = 0; + setStats = (gDiskStatsList != NULL) ? TRUE : FALSE; + + while (fgets(line, sizeof line, fp) == line) { + /* + * Linux kernel diskstats_show format string: + * "%4d %7d %s %lu %lu %lu %u %lu %lu %lu %u %u %u %u\n" + * + * Matching data types are selected to calculate accumulating fields' + * increment correctly in case of overflow for both 32 and 64 bit + * Linux systems. + */ + int assignedCount; + char diskName[NAME_MAX + 1]; // NAME_MAX is defined to 255 + long unsigned int readIOs; // # of reads completed + long unsigned int writeIOs; // # of writes completed + unsigned int inflightIOs; // # of I/Os currently in progress + unsigned int weightedTime; // Weighted # of milliseconds + // spent in doing I/Os + assignedCount = sscanf(line, + "%*d %*d %" XSTR(NAME_MAX) "s " + "%lu %*u %*u %*u " + "%lu %*u %*u %*u " + "%u %*u %u", + diskName, // '\0' is added automatically + &readIOs, + &writeIOs, + &inflightIOs, &weightedTime); + if (assignedCount != 5 || + (readIOs == 0 && writeIOs == 0) || + !GuestInfoIsBlockDevice(diskName)) { + continue; + } + + inflightIOsSum += inflightIOs; + + if (*listItem != NULL) { + if (strcmp((*listItem)->diskName, diskName) == 0) { + (*listItem)->weightedTime[curr] = weightedTime; + } else { + /* Disk hot plug/unplug, rebuild the rest of the list. */ + GuestInfoDeleteDiskStatsList(*listItem); + *listItem = NULL; + } + } + + if (*listItem == NULL) { + *listItem = (GuestInfoDiskStatsList *) + Util_SafeMalloc(sizeof **listItem); + (*listItem)->next = NULL; + (*listItem)->diskName = Util_SafeStrdup(diskName); + (*listItem)->weightedTime[curr] = weightedTime; + (*listItem)->weightedTime[prev] = 0; + + /* Also covers disk hot plug at the end of the list. */ + setStats = FALSE; + } + + listItem = &((*listItem)->next); + } + + fclose(fp); + + if (listItem == &gDiskStatsList // No qualified disk device found + || *listItem != NULL) { // Disk hot unplug at the end of the list + GuestInfoDeleteDiskStatsList(*listItem); + *listItem = NULL; + setStats = FALSE; + } + + if (setStats) { + GuestInfoDiskStatsList *currDiskStats = gDiskStatsList; + uint64 weightedTimeDeltaSum = 0; + + while (currDiskStats != NULL) { + unsigned int weightedTimeDelta = currDiskStats->weightedTime[curr] - + currDiskStats->weightedTime[prev]; + weightedTimeDeltaSum += weightedTimeDelta; + currDiskStats = currDiskStats->next; + } + + GuestInfoStoreStatByID(GuestStatID_Linux_DiskRequestQueue, + collector, + inflightIOsSum); + GuestInfoStoreStatByID(GuestStatID_Linux_DiskRequestQueueAvg, + collector, + weightedTimeDeltaSum); + } + + curr = prev; + + return TRUE; +} /* @@ -549,7 +807,7 @@ GuestInfoDeriveSwapData(GuestInfoCollector *collector) // IN: current collectio */ static void -GuestInfoCollect(GuestInfoCollector *collector) // IN: +GuestInfoCollect(GuestInfoCollector *collector) // IN/OUT: { uint32 i; GuestInfoStat *stat; @@ -565,32 +823,23 @@ GuestInfoCollect(GuestInfoCollector *collector) // IN: } /* Collect new values */ - GuestInfoProcMemInfoData(collector); - GuestInfoProcData(VMSTAT_FILE, collector); - GuestInfoProcData(STAT_FILE, collector); - GuestInfoProcData(ZONEINFO_FILE, collector); -#if PUBLISH_P1_2016_STATS - GuestInfoProcSimpleValue(SWAPPINESS_FILE, GuestStatID_Linux_Swappiness, - collector); -#endif + GuestInfoProcData(MEMINFO_FILE, ':', collector); + GuestInfoProcData(VMSTAT_FILE, '\0', collector); + GuestInfoProcData(STAT_FILE, '\0', collector); + GuestInfoProcData(ZONEINFO_FILE, '\0', collector); +#if PUBLISH_EXPERIMENTAL_STATS + GuestInfoProcSimpleValue(GuestStatID_Linux_Swappiness, collector); GuestInfoDeriveSwapData(collector); +#endif collector->timeData = GuestInfoGetUpTime(&collector->timeStamp); /* * We make sure physical page size is always present. */ - - stat = NULL; - HashTable_Lookup(collector->reportMap, - INT_AS_HASHKEY(GuestStatID_PhysicalPageSize), - (void **) &stat); - - if ((stat != NULL) && (stat->err != 0)) { - stat->value = pageSize; - stat->count = 1; - stat->err = 0; - } + GuestInfoStoreStatByID(GuestStatID_PhysicalPageSize, + collector, + pageSize); /* * Attempt to fix up memPhysUsable if it is not available. @@ -618,6 +867,12 @@ GuestInfoCollect(GuestInfoCollector *collector) // IN: stat->value = memTotal->value; } } + + GuestInfoDeriveMemNeeded(collector); + if (gUnstable) { + GuestInfoDecreaseCpuRunQueueByOne(collector); + GuestInfoProcDiskStatsData(collector); + } } @@ -798,7 +1053,7 @@ GuestInfoAppendStat(int errnoValue, // IN: static void GuestInfoAppendRate(Bool emitNameSpace, // IN: - GuestStatToolsID reportID, // IN: Id of the stat + GuestStatToolsID reportID, // IN: ID of the stat GuestInfoCollector *current, // IN: current collection GuestInfoCollector *previous, // IN: previous collection DynBuf *statBuf) // IN/OUT: stat data @@ -821,9 +1076,28 @@ GuestInfoAppendRate(Bool emitNameSpace, // IN: ((currentStat != NULL) && (currentStat->err == 0)) && ((previousStat != NULL) && (previousStat->err == 0))) { double timeDelta = current->timeStamp - previous->timeStamp; - double valueDelta = currentStat->value - previousStat->value; + double valueDelta; + + /* + * DiskRequestQueueAvg GuestInfoStat::value is weighted number of + * milliseconds delta in uint64 type, need to divide it by 1000 to + * turn the number in seconds. + * + * Host side drops the fraction part of double data type. Therefore, + * we preserve 2 decimal points by scaling up the value 100x. + * The consumers of this stat need to divide it by 100 to retrieve + * two digits after decimal point. + * + * (value / 1000) * 100 = value / 10 + */ + if (reportID == GuestStatID_Linux_DiskRequestQueueAvg) { + valueDelta = ((double)(currentStat->value)) / 10; + } else { + valueDelta = currentStat->value - previousStat->value; + } valueDouble = valueDelta / timeDelta; + errnoValue = 0; } @@ -856,9 +1130,10 @@ GuestInfoAppendRate(Bool emitNameSpace, // IN: /* *---------------------------------------------------------------------- * - * GuestInfoAppendMemNeeded -- + * GuestInfoDeriveMemNeeded -- * - * Synthesize memNeeded and append it to the stat buffer. + * Update memory needed stats that are calculated + * rather than fetched. * * Results: * None. @@ -870,9 +1145,7 @@ GuestInfoAppendRate(Bool emitNameSpace, // IN: */ static void -GuestInfoAppendMemNeeded(GuestInfoCollector *current, // IN: current collection - Bool emitNameSpace, // IN: - DynBuf *statBuf) // IN/OUT: stats data +GuestInfoDeriveMemNeeded(GuestInfoCollector *collector) // IN/OUT: { uint64 memNeeded; uint64 memNeededReservation; @@ -880,13 +1153,13 @@ GuestInfoAppendMemNeeded(GuestInfoCollector *current, // IN: current collection GuestInfoStat *memAvail = NULL; GuestInfoStat *memPhysUsable = NULL; - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_MemPhysUsable), (void **) &memPhysUsable); ASSERT(memPhysUsable != NULL); - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemAvailable), (void **) &memAvail); @@ -901,25 +1174,25 @@ GuestInfoAppendMemNeeded(GuestInfoCollector *current, // IN: current collection GuestInfoStat *memInactiveFile = NULL; GuestInfoStat *lowWaterMark = NULL; - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_MemFree), (void **) &memFree); - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemCached), (void **) &memCache); - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemBuffers), (void **) &memBuffers); - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_MemActiveFileCache), (void **) &memActiveFile); - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemSlabReclaim), (void **) &memSlabReclaim); - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemInactiveFile), (void **) &memInactiveFile); - HashTable_Lookup(current->reportMap, + HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_LowWaterMark), (void **) &lowWaterMark); @@ -983,51 +1256,13 @@ GuestInfoAppendMemNeeded(GuestInfoCollector *current, // IN: current collection memNeededReservation = 0; } -#if PUBLISH_P1_2015_STATS - GuestInfoAppendStat(0, - emitNameSpace, - GuestStatID_MemNeeded, - GuestUnitsKiB, GuestTypeUint64, - &memNeeded, - GuestInfoBytesNeededUIntDatum(memNeeded), - statBuf); - - emitNameSpace = FALSE; -#endif - -#if PUBLISH_P2_STATS - GuestInfoAppendStat(0, - emitNameSpace, - GuestStatID_MemNeededReservation, - GuestUnitsKiB, GuestTypeUint64, - &memNeededReservation, - GuestInfoBytesNeededUIntDatum(memNeededReservation), - statBuf); -#endif -} - - -/* - *---------------------------------------------------------------------- - * - * GuestInfoIsRate -- - * - * Is the specified unit a rate? - * - * Results: - * TRUE Yes - * FALSE No - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ + GuestInfoStoreStatByID(GuestStatID_MemNeeded, + collector, + memNeeded); -static Bool -GuestInfoIsRate(GuestValueUnits units) // IN: -{ - return ((units & GuestUnitsModifier_Rate) != 0); + GuestInfoStoreStatByID(GuestStatID_MemNeededReservation, + collector, + memNeededReservation); } @@ -1065,16 +1300,16 @@ GuestInfoEncodeStats(GuestInfoCollector *current, // IN: current collection for (i = 0; i < current->numStats; i++) { GuestInfoStat *stat = ¤t->stats[i]; - if (!stat->query->publish) { + if (!*(stat->query->publish)) { continue; } - if (GuestInfoIsRate(stat->query->units)) { - ASSERT(stat->query->dataType == GuestTypeDouble); + if (stat->query->dataType == GuestTypeDouble) { GuestInfoAppendRate(emitNameSpace, stat->query->reportID, current, previous, statBuf); } else { ASSERT(stat->query->dataType == GuestTypeUint64); + ASSERT((stat->query->units & GuestUnitsModifier_Rate) == 0); GuestInfoAppendStat(stat->err, emitNameSpace, stat->query->reportID, @@ -1087,8 +1322,6 @@ GuestInfoEncodeStats(GuestInfoCollector *current, // IN: current collection emitNameSpace = FALSE; // use the smallest representation } - - GuestInfoAppendMemNeeded(current, emitNameSpace, statBuf); } @@ -1144,7 +1377,7 @@ GuestInfoConstructCollector(GuestInfoQuery *queries, // IN: { uint32 i; uint32 regExp = 0; - GuestInfoCollector *collector = calloc(1, sizeof *collector); + GuestInfoCollector *collector = Util_SafeCalloc(1, sizeof *collector); if (collector == NULL) { return NULL; @@ -1158,14 +1391,15 @@ GuestInfoConstructCollector(GuestInfoQuery *queries, // IN: collector->numRegExps = 0; for (i = 0; i < numQueries; i++) { - if (queries[i].isRegExp && queries[i].collect) { + if (queries[i].isRegExp) { collector->numRegExps++; } } collector->numStats = numQueries; - collector->stats = calloc(numQueries, sizeof *collector->stats); - collector->regExps = calloc(collector->numRegExps, sizeof(GuestInfoStat *)); + collector->stats = Util_SafeCalloc(numQueries, sizeof *collector->stats); + collector->regExps = Util_SafeCalloc(collector->numRegExps, + sizeof(GuestInfoStat *)); if ((collector->exactMatches == NULL) || (collector->reportMap == NULL) || @@ -1185,18 +1419,17 @@ GuestInfoConstructCollector(GuestInfoQuery *queries, // IN: stat->query = query; - if (!query->collect) { - continue; - } - if (query->isRegExp) { + ASSERT(query->sourceFile); ASSERT(query->locatorString); collector->regExps[regExp++] = stat; } else { - if (query->locatorString != NULL) { - HashTable_Insert(collector->exactMatches, query->locatorString, - stat); + if (query->sourceFile != NULL && query->locatorString != NULL) { + char *key = Str_SafeAsprintf(NULL, KEY_FORMAT, query->sourceFile, + query->locatorString); + HashTable_Insert(collector->exactMatches, key, stat); + free(key); } } @@ -1230,8 +1463,6 @@ Bool GuestInfoTakeSample(DynBuf *statBuf) // IN/OUT: inited, ready to fill { GuestInfoCollector *temp; - static GuestInfoCollector *current = NULL; - static GuestInfoCollector *previous = NULL; ASSERT(statBuf && DynBuf_GetSize(statBuf) == 0); @@ -1241,33 +1472,33 @@ GuestInfoTakeSample(DynBuf *statBuf) // IN/OUT: inited, ready to fill } /* First time through, allocate all necessary memory */ - if (previous == NULL) { - current = GuestInfoConstructCollector(guestInfoQuerySpecTable, + if (gPreviousCollector == NULL) { + gCurrentCollector = GuestInfoConstructCollector(guestInfoQuerySpecTable, N_QUERIES); - previous = GuestInfoConstructCollector(guestInfoQuerySpecTable, + gPreviousCollector = GuestInfoConstructCollector(guestInfoQuerySpecTable, N_QUERIES); } - if ((current == NULL) || - (previous == NULL)) { - GuestInfoDestroyCollector(current); - current = NULL; - GuestInfoDestroyCollector(previous); - previous = NULL; + if ((gCurrentCollector == NULL) || + (gPreviousCollector == NULL)) { + GuestInfoDestroyCollector(gCurrentCollector); + gCurrentCollector = NULL; + GuestInfoDestroyCollector(gPreviousCollector); + gPreviousCollector = NULL; return FALSE; } /* Collect the current data */ - GuestInfoCollect(current); + GuestInfoCollect(gCurrentCollector); /* Encode the captured data */ - GuestInfoEncodeStats(current, previous, statBuf); + GuestInfoEncodeStats(gCurrentCollector, gPreviousCollector, statBuf); /* Switch the collections for next time. */ - temp = current; - current = previous; - previous = temp; + temp = gCurrentCollector; + gCurrentCollector = gPreviousCollector; + gPreviousCollector = temp; return TRUE; } @@ -1297,6 +1528,11 @@ GuestInfo_StatProviderPoll(gpointer data) g_debug("Entered guest info stats gather.\n"); + gUnstable = g_key_file_get_boolean(ctx->config, + CONFGROUPNAME_GUESTINFO, + "enable-unstable-stats", + NULL); + /* Send the vmstats to the VMX. */ DynBuf_Init(&stats); @@ -1331,5 +1567,11 @@ GuestInfo_StatProviderPoll(gpointer data) void GuestInfo_StatProviderShutdown(void) { - // Nothing to do here for now + GuestInfoDeleteDiskStatsList(gDiskStatsList); + gDiskStatsList = NULL; + + GuestInfoDestroyCollector(gCurrentCollector); + gCurrentCollector = NULL; + GuestInfoDestroyCollector(gPreviousCollector); + gPreviousCollector = NULL; }