mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 11:22:23 +00:00
util: Add virHostCPUGetTscInfo
On a KVM x86_64 host which supports invariant TSC this function can be used to detect the TSC frequency and the availability of TSC scaling. The magic MSR numbers required to check if VMX scaling is supported on the host are documented in Volume 3 of the Intel® 64 and IA-32 Architectures Software Developer’s Manual. Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
parent
02c1d3a6e1
commit
f0f6faba63
@ -1324,6 +1324,69 @@ virHostCPUGetMSR(unsigned long index,
|
||||
return virHostCPUGetMSRFromKVM(index, msr);
|
||||
}
|
||||
|
||||
|
||||
# define VMX_PROCBASED_CTLS2_MSR 0x48b
|
||||
# define VMX_USE_TSC_SCALING (1 << 25)
|
||||
|
||||
/*
|
||||
* This function should only be called when the host CPU supports invariant TSC
|
||||
* (invtsc CPUID feature).
|
||||
*
|
||||
* Returns pointer to the TSC info structure on success,
|
||||
* NULL when TSC cannot be probed otherwise.
|
||||
*/
|
||||
virHostCPUTscInfoPtr
|
||||
virHostCPUGetTscInfo(void)
|
||||
{
|
||||
virHostCPUTscInfoPtr info;
|
||||
VIR_AUTOCLOSE kvmFd = -1;
|
||||
VIR_AUTOCLOSE vmFd = -1;
|
||||
VIR_AUTOCLOSE vcpuFd = -1;
|
||||
uint64_t msr = 0;
|
||||
int rc;
|
||||
|
||||
if ((kvmFd = open(KVM_DEVICE, O_RDONLY)) < 0) {
|
||||
virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((vmFd = ioctl(kvmFd, KVM_CREATE_VM, 0)) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to create KVM VM for TSC probing"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((vcpuFd = ioctl(vmFd, KVM_CREATE_VCPU, 0)) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to create KVM vCPU for TSC probing"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((rc = ioctl(vcpuFd, KVM_GET_TSC_KHZ)) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("Unable to probe TSC frequency"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC(info) < 0)
|
||||
return NULL;
|
||||
|
||||
info->frequency = rc * 1000ULL;
|
||||
|
||||
if (virHostCPUGetMSR(VMX_PROCBASED_CTLS2_MSR, &msr) == 0) {
|
||||
/* High 32 bits of the MSR value indicate whether specific control
|
||||
* can be set to 1. */
|
||||
msr >>= 32;
|
||||
|
||||
info->scaling = virTristateBoolFromBool(!!(msr & VMX_USE_TSC_SCALING));
|
||||
}
|
||||
|
||||
VIR_DEBUG("Detected TSC frequency %llu Hz, scaling %s",
|
||||
info->frequency, virTristateBoolTypeToString(info->scaling));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
@ -1335,6 +1398,14 @@ virHostCPUGetMSR(unsigned long index ATTRIBUTE_UNUSED,
|
||||
return -1;
|
||||
}
|
||||
|
||||
virHostCPUTscInfoPtr
|
||||
virHostCPUGetTscInfo(void)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s",
|
||||
_("Probing TSC is not supported on this platform"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LINUX_KVM_H && defined(KVM_GET_MSRS) && \
|
||||
(defined(__i386__) || defined(__x86_64__)) && \
|
||||
(defined(__linux__) || defined(__FreeBSD__)) */
|
||||
|
@ -25,6 +25,15 @@
|
||||
# include "internal.h"
|
||||
# include "virarch.h"
|
||||
# include "virbitmap.h"
|
||||
# include "virenum.h"
|
||||
|
||||
|
||||
typedef struct _virHostCPUTscInfo virHostCPUTscInfo;
|
||||
typedef virHostCPUTscInfo *virHostCPUTscInfoPtr;
|
||||
struct _virHostCPUTscInfo {
|
||||
unsigned long long frequency;
|
||||
virTristateBool scaling;
|
||||
};
|
||||
|
||||
|
||||
int virHostCPUGetStats(int cpuNum,
|
||||
@ -69,4 +78,6 @@ unsigned int virHostCPUGetMicrocodeVersion(void);
|
||||
int virHostCPUGetMSR(unsigned long index,
|
||||
uint64_t *msr);
|
||||
|
||||
virHostCPUTscInfoPtr virHostCPUGetTscInfo(void);
|
||||
|
||||
#endif /* LIBVIRT_VIRHOSTCPU_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user