Commit 7a7a933e authored by Martin Krastev's avatar Martin Krastev Committed by Zack Rusin
Browse files

drm/vmwgfx: Introduce VMware mks-guest-stats



VMware mks-guest-stats mechanism allows the collection of performance stats from
guest userland GL contexts, as well as from vmwgfx kernelspace, via a set of sw-
defined performance counters. The userspace performance counters are (de)registerd
with vmware-vmx-stats hypervisor via new iocts. The vmwgfx kernelspace counters
are controlled at build-time via a new config DRM_VMWGFX_MKSSTATS.

* Add vmw_mksstat_{add|remove|reset}_ioctl controlling the tracking of
  mks-guest-stats in guest winsys contexts
* Add DRM_VMWGFX_MKSSTATS config to drivers/gpu/drm/vmwgfx/Kconfig controlling
  the instrumentation of vmwgfx for kernelspace mks-guest-stats counters
* Instrument vmwgfx vmw_execbuf_ioctl to collect mks-guest-stats according to
  DRM_VMWGFX_MKSSTATS

Signed-off-by: default avatarMartin Krastev <krastevm@vmware.com>
Reviewed-by: default avatarZack Rusin <zackr@vmware.com>
Signed-off-by: default avatarZack Rusin <zackr@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210609172307.131929-3-zackr@vmware.com
parent d92223ea
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -22,3 +22,10 @@ config DRM_VMWGFX_FBCON
	   Choose this option if you are shipping a new vmwgfx
	   userspace driver that supports using the kernel driver.

config DRM_VMWGFX_MKSSTATS
	bool "Enable mksGuestStats instrumentation of vmwgfx by default"
	depends on DRM_VMWGFX
	default n
	help
	   Choose this option to instrument the kernel driver for mksGuestStats.
+90 −2
Original line number Diff line number Diff line
@@ -23,9 +23,11 @@
 * SOFTWARE.
 *
 **********************************************************/
#ifndef _VM_BASIC_TYPES_H_
#define _VM_BASIC_TYPES_H_
#ifndef _SVGA_TYPES_H_
#define _SVGA_TYPES_H_
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/page.h>

typedef u32 uint32;
typedef s32 int32;
@@ -48,4 +50,90 @@ typedef bool Bool;

#define CONST64U(x) x##ULL

/*
 * MKS Guest Stats types
 */

typedef struct MKSGuestStatCounter {
	atomic64_t count;
} MKSGuestStatCounter;

typedef struct MKSGuestStatCounterTime {
	MKSGuestStatCounter counter;
	atomic64_t selfCycles;
	atomic64_t totalCycles;
} MKSGuestStatCounterTime;

/*
 * Flags for MKSGuestStatInfoEntry::flags below
 */

#define MKS_GUEST_STAT_FLAG_NONE    0
#define MKS_GUEST_STAT_FLAG_TIME    (1U << 0)

typedef __attribute__((aligned(32))) struct MKSGuestStatInfoEntry {
	union {
		const char *s;
		uint64 u;
	} name;
	union {
		const char *s;
		uint64 u;
	} description;
	uint64 flags;
	union {
		MKSGuestStatCounter *counter;
		MKSGuestStatCounterTime *counterTime;
		uint64 u;
	} stat;
} MKSGuestStatInfoEntry;

#define INVALID_PPN64       ((PPN64)0x000fffffffffffffULL)
#define vmw_num_pages(size) (PAGE_ALIGN(size) >> PAGE_SHIFT)

#define MKS_GUEST_STAT_INSTANCE_DESC_LENGTH 1024
#define MKS_GUEST_STAT_INSTANCE_MAX_STATS   4096
#define MKS_GUEST_STAT_INSTANCE_MAX_STAT_PPNS                \
	(vmw_num_pages(MKS_GUEST_STAT_INSTANCE_MAX_STATS *   \
		sizeof(MKSGuestStatCounterTime)))
#define MKS_GUEST_STAT_INSTANCE_MAX_INFO_PPNS                \
	(vmw_num_pages(MKS_GUEST_STAT_INSTANCE_MAX_STATS *   \
		sizeof(MKSGuestStatInfoEntry)))
#define MKS_GUEST_STAT_AVERAGE_NAME_LENGTH  40
#define MKS_GUEST_STAT_INSTANCE_MAX_STRS_PPNS                \
	(vmw_num_pages(MKS_GUEST_STAT_INSTANCE_MAX_STATS *   \
		MKS_GUEST_STAT_AVERAGE_NAME_LENGTH))

/*
 * The MKSGuestStatInstanceDescriptor is used as main interface to
 * communicate guest stats back to the host code.  The guest must
 * allocate an instance of this structure at the start of a page and
 * provide the physical address to the host.  From there the host code
 * can walk this structure to find other (pinned) pages containing the
 * stats data.
 *
 * Since the MKSGuestStatInfoEntry structures contain userlevel
 * pointers, the InstanceDescriptor also contains pointers to the
 * begining of these sections allowing the host side code to correctly
 * interpret the pointers.
 *
 * Because the host side code never acknowledges anything back to the
 * guest there is no strict requirement to maintain compatability
 * across releases.  If the interface changes the host might not be
 * able to log stats, but the guest will continue to run normally.
 */

typedef struct MKSGuestStatInstanceDescriptor {
	uint64 reservedMBZ; /* must be zero for now. */
	uint64 statStartVA; /* VA of the start of the stats section. */
	uint64 strsStartVA; /* VA of the start of the strings section. */
	uint64 statLength;  /* length of the stats section in bytes. */
	uint64 infoLength;  /* length of the info entry section in bytes. */
	uint64 strsLength;  /* length of the strings section in bytes. */
	PPN64  statPPNs[MKS_GUEST_STAT_INSTANCE_MAX_STAT_PPNS]; /* stat counters */
	PPN64  infoPPNs[MKS_GUEST_STAT_INSTANCE_MAX_INFO_PPNS]; /* stat info */
	PPN64  strsPPNs[MKS_GUEST_STAT_INSTANCE_MAX_STRS_PPNS]; /* strings */
	char   description[MKS_GUEST_STAT_INSTANCE_DESC_LENGTH];
} MKSGuestStatInstanceDescriptor;

#endif
+0 −22
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _VM_BASIC_TYPES_H_
#define _VM_BASIC_TYPES_H_
#include <linux/kernel.h>

typedef u32 uint32;
typedef s32 int32;
typedef u64 uint64;
typedef u16 uint16;
typedef s16 int16;
typedef u8  uint8;
typedef s8  int8;

typedef uint64 PA;
typedef uint32 PPN;
typedef uint64 PPN64;

typedef bool Bool;

#define MAX_UINT32 U32_MAX

#endif
+20 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include "vmwgfx_binding.h"
#include "vmwgfx_devcaps.h"
#include "vmwgfx_drv.h"
#include "vmwgfx_mksstat.h"

#define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"

@@ -148,6 +149,14 @@
#define DRM_IOCTL_VMW_MSG						\
	DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_MSG,			\
		struct drm_vmw_msg_arg)
#define DRM_IOCTL_VMW_MKSSTAT_RESET				\
	DRM_IO(DRM_COMMAND_BASE + DRM_VMW_MKSSTAT_RESET)
#define DRM_IOCTL_VMW_MKSSTAT_ADD				\
	DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_MKSSTAT_ADD,	\
		struct drm_vmw_mksstat_add_arg)
#define DRM_IOCTL_VMW_MKSSTAT_REMOVE				\
	DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_MKSSTAT_REMOVE,	\
		struct drm_vmw_mksstat_remove_arg)

/*
 * The core DRM version of this macro doesn't account for
@@ -244,6 +253,15 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
	VMW_IOCTL_DEF(VMW_MSG,
		      vmw_msg_ioctl,
		      DRM_RENDER_ALLOW),
	VMW_IOCTL_DEF(VMW_MKSSTAT_RESET,
		      vmw_mksstat_reset_ioctl,
		      DRM_RENDER_ALLOW),
	VMW_IOCTL_DEF(VMW_MKSSTAT_ADD,
		      vmw_mksstat_add_ioctl,
		      DRM_RENDER_ALLOW),
	VMW_IOCTL_DEF(VMW_MKSSTAT_REMOVE,
		      vmw_mksstat_remove_ioctl,
		      DRM_RENDER_ALLOW),
};

static const struct pci_device_id vmw_pci_id_list[] = {
@@ -1137,6 +1155,8 @@ static void vmw_driver_unload(struct drm_device *dev)
	for (i = vmw_res_context; i < vmw_res_max; ++i)
		idr_destroy(&dev_priv->res_idr[i]);

	vmw_mksstat_remove_all(dev_priv);

	pci_release_regions(pdev);
}

+27 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
 *
 * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA
 * Copyright 2009-2021 VMware, Inc., Palo Alto, CA., USA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
@@ -91,6 +91,9 @@
#define VMW_RES_FENCE ttm_driver_type3
#define VMW_RES_SHADER ttm_driver_type4

#define MKSSTAT_CAPACITY_LOG2 5U
#define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2)

struct vmw_fpriv {
	struct ttm_object_file *tfile;
	bool gb_aware; /* user-space is guest-backed aware */
@@ -630,6 +633,18 @@ struct vmw_private {
	struct vmw_validation_mem vvm;

	uint32 *devcaps;

	/*
	 * mksGuestStat instance-descriptor and pid arrays
	 */
	struct page *mksstat_user_pages[MKSSTAT_CAPACITY];
	atomic_t mksstat_user_pids[MKSSTAT_CAPACITY];

#if IS_ENABLED(CONFIG_DRM_VMWGFX_MKSSTATS)
	struct page *mksstat_kern_pages[MKSSTAT_CAPACITY];
	u8 mksstat_kern_top_timer[MKSSTAT_CAPACITY];
	atomic_t mksstat_kern_pids[MKSSTAT_CAPACITY];
#endif
};

static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res)
@@ -1503,6 +1518,17 @@ __printf(1, 2) int vmw_host_printf(const char *fmt, ...);
int vmw_msg_ioctl(struct drm_device *dev, void *data,
		  struct drm_file *file_priv);

/* Host mksGuestStats -vmwgfx_msg.c: */
int vmw_mksstat_get_kern_slot(pid_t pid, struct vmw_private *dev_priv);

int vmw_mksstat_reset_ioctl(struct drm_device *dev, void *data,
		      struct drm_file *file_priv);
int vmw_mksstat_add_ioctl(struct drm_device *dev, void *data,
		      struct drm_file *file_priv);
int vmw_mksstat_remove_ioctl(struct drm_device *dev, void *data,
		      struct drm_file *file_priv);
int vmw_mksstat_remove_all(struct vmw_private *dev_priv);

/* VMW logging */

/**
Loading