[libvirt] [PATCH 0/6] Add virNodeGetCpuTime() API

Hi, everyone. I wrote new API called virNodeGetCpuTime(). It returns cumulative cpu time of the node from /proc/stat since node boots up. Previous discussion is here. http://www.mail-archive.com/libvir-list@redhat.com/msg32552.html Minoru Usui (6): [1/6] virNodeGetCpuTime: Expose new API [2/6] virNodeGetCpuTime: Define internal driver API [3/6] virNodeGetCpuTime: Implement public API [4/6] virNodeGetCpuTime: Implement remote protocol [5/6] virNodeGetCpuTime: Implement virsh support [6/6] virNodeGetCpuTime: Implement linux support daemon/remote.c | 23 ++++++++++++ daemon/remote_dispatch_prototypes.h | 8 ++++ daemon/remote_dispatch_ret.h | 1 + daemon/remote_dispatch_table.h | 5 +++ include/libvirt/libvirt.h.in | 26 ++++++++++++++ src/driver.h | 4 ++ src/esx/esx_driver.c | 1 + src/libvirt.c | 38 ++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/nodeinfo.c | 60 +++++++++++++++++++++++++++++++ src/nodeinfo.h | 2 +- src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 27 ++++++++++++++ src/remote/remote_protocol.c | 15 ++++++++ src/remote/remote_protocol.h | 11 ++++++ src/remote/remote_protocol.x | 10 +++++- src/remote_protocol-structs | 6 +++ src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xenapi/xenapi_driver.c | 1 + tools/virsh.c | 66 +++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++ 30 files changed, 320 insertions(+), 2 deletions(-) -- Minoru Usui <usui@mxm.nes.nec.co.jp>

virNodeGetCpuTime: Expose new API include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index bd36015..b61ce9c 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -228,6 +228,21 @@ struct _virNodeInfo { unsigned int threads;/* number of threads per core */ }; +/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +}; /** * virDomainSchedParameterType: @@ -460,6 +475,14 @@ int virDomainMigrateSetMaxSpeed(virDomainPtr domain, typedef virNodeInfo *virNodeInfoPtr; /** + * virNodeCpuTimePtr: + * + * a virNodeCpuTimePtr is a pointer to a virNodeCpuTime structure. + */ + +typedef virNodeCpuTime *virNodeCpuTimePtr; + +/** * virConnectFlags * * Flags when opening a connection to a hypervisor @@ -593,6 +616,9 @@ int virNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info); char * virConnectGetCapabilities (virConnectPtr conn); +int virNodeGetCpuTime (virConnectPtr conn, + virNodeCpuTimePtr cpu_time); + unsigned long long virNodeGetFreeMemory (virConnectPtr conn); int virNodeGetSecurityModel (virConnectPtr conn, diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index b4aed41..53575e1 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -434,6 +434,7 @@ LIBVIRT_0.9.0 { virEventRunDefaultImpl; virStorageVolDownload; virStorageVolUpload; + virNodeGetCpuTime; } LIBVIRT_0.8.8; # .... define new API here using predicted next version number .... -- 1.7.1 -- Minoru Usui <usui@mxm.nes.nec.co.jp>

On 03/31/2011 07:55 PM, Minoru Usui wrote:
virNodeGetCpuTime: Expose new API
include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-)
+/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +};
Can we portably get all of this information on Windows? If not, how do you express which values we don't know how to obtain?
@@ -593,6 +616,9 @@ int virNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info); char * virConnectGetCapabilities (virConnectPtr conn);
+int virNodeGetCpuTime (virConnectPtr conn, + virNodeCpuTimePtr cpu_time); +
Rather than locking ourselves into yet another inflexible API (no flags parameter and a hard-coded struct means no way to extend this if we ever come up with some new stat to query), should we instead be following the lead of getMemoryParameters which takes a typed-name/value array to pass an arbitrary number of parameters, which allows extension without a new API?
+++ b/src/libvirt_public.syms @@ -434,6 +434,7 @@ LIBVIRT_0.9.0 { virEventRunDefaultImpl; virStorageVolDownload; virStorageVolUpload; + virNodeGetCpuTime; } LIBVIRT_0.8.8;
While I think that something along the lines of this API is appropriate for libvirt (indeed, knowing a host's CPU utilization can indeed be a factor for upper-level management software in deciding whether to migrate another domain on or off of the machine), it's too late to put it into 0.9.0. We'd be setting bad precedent by accepting this after the first release candidate did a feature freeze, so you'd need to adjust this to 0.9.1. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

2011/4/1 Eric Blake <eblake@redhat.com>:
On 03/31/2011 07:55 PM, Minoru Usui wrote:
virNodeGetCpuTime: Expose new API
include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-)
+/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +};
Can we portably get all of this information on Windows? If not, how do you express which values we don't know how to obtain?
In the context of ESX I vote against this absolute CPU time values. ESX provides this values relative to a 20 second timeslots with 1 hour of history. This makes it nearly impossible to obtain the absolute CPU time. The same problem already exists for the domain's virtual CPU time. When you look at virt-top's usage of the domain's virtual CPU time, you see that it actually doesn't really care about the absolute value, but deduces the CPU utilization from it. I suggest that we find a different representation for this information that is not by definition impossible to implement for ESX. Matthias

Hi, Matthias. On Fri, 1 Apr 2011 20:22:17 +0200 Matthias Bolte <matthias.bolte@googlemail.com> wrote:
2011/4/1 Eric Blake <eblake@redhat.com>:
On 03/31/2011 07:55 PM, Minoru Usui wrote:
virNodeGetCpuTime: Expose new API
include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-)
+/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +};
Can we portably get all of this information on Windows? If not, how do you express which values we don't know how to obtain?
In the context of ESX I vote against this absolute CPU time values. ESX provides this values relative to a 20 second timeslots with 1 hour of history. This makes it nearly impossible to obtain the absolute CPU time. The same problem already exists for the domain's virtual CPU time.
When you look at virt-top's usage of the domain's virtual CPU time, you see that it actually doesn't really care about the absolute value, but deduces the CPU utilization from it. I suggest that we find a different representation for this information that is not by definition impossible to implement for ESX.
Matthias
I didn't know ESX couldn't return absolute CPU time value. Thank you for your comment. We really want to get CPU utilization information of the node, not absolute CPU time values. But linux doesn't provide CPU utilization directly, so my patch returns absolute CPU time values, and CPU utilization is calculated by client which uses new API. To return CPU utilization by new API, I think there are two issues of implementing on linux. a) How much interval does calculate CPU utilization? To calculate CPU utilization on linux, we need to get absolute CPU time value of the node from /proc/stat two times. How much interval properly? 1sec? 1min? or others? b) Can new API wait its interval? If we select simply implementation, new API waits its interval. But API user don't want to wait every API calls, if its interval is long. So I think libvirtd will be calculating CPU utilization in background every interval. Is this approach OK? -- Minoru Usui <usui@mxm.nes.nec.co.jp>

On Mon, Apr 04, 2011 at 11:03:10AM +0900, Minoru Usui wrote:
Hi, Matthias.
On Fri, 1 Apr 2011 20:22:17 +0200 Matthias Bolte <matthias.bolte@googlemail.com> wrote:
2011/4/1 Eric Blake <eblake@redhat.com>:
On 03/31/2011 07:55 PM, Minoru Usui wrote:
virNodeGetCpuTime: Expose new API
include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-)
+/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +};
Can we portably get all of this information on Windows? If not, how do you express which values we don't know how to obtain?
In the context of ESX I vote against this absolute CPU time values. ESX provides this values relative to a 20 second timeslots with 1 hour of history. This makes it nearly impossible to obtain the absolute CPU time. The same problem already exists for the domain's virtual CPU time.
When you look at virt-top's usage of the domain's virtual CPU time, you see that it actually doesn't really care about the absolute value, but deduces the CPU utilization from it. I suggest that we find a different representation for this information that is not by definition impossible to implement for ESX.
Matthias
I didn't know ESX couldn't return absolute CPU time value. Thank you for your comment.
We really want to get CPU utilization information of the node, not absolute CPU time values. But linux doesn't provide CPU utilization directly, so my patch returns absolute CPU time values, and CPU utilization is calculated by client which uses new API.
To return CPU utilization by new API, I think there are two issues of implementing on linux.
a) How much interval does calculate CPU utilization? To calculate CPU utilization on linux, we need to get absolute CPU time value of the node from /proc/stat two times. How much interval properly? 1sec? 1min? or others?
The fact that there is the question of what is the right interval demonstrates the inherant flaw in such an API design. Providing the raw absolute time allows an app much more flexiblity in how they work with the data, avoiding the need for such policies in libvirt.
b) Can new API wait its interval? If we select simply implementation, new API waits its interval. But API user don't want to wait every API calls, if its interval is long. So I think libvirtd will be calculating CPU utilization in background every interval. Is this approach OK?
IMHO we don't really want libvirtd to be constantly polling & calculating this data, at least not unless an application is currently asking for it. I think we want this API to have the style that is like the current virDomainMemoryStats API. Then, we can define a set of parameters that can be fetched, allowing each parameter to be optional eg enum { VIR_NODE_CPU_TIME_KERNEL, VIR_NODE_CPU_TIME_USER, VIR_NODE_CPU_TIME_IDLE, VIR_NODE_CPU_TIME_IOWAIT, VIR_NODE_CPU_TIME_UTILIZATION, }; For QEMU we'd provide the first 4 values, allowing apps maximum flexibility in how they calculate utilization over different time periods. For VMWare we'd provide only the last value. An app like virt-manager, can display UTILIZATION value directly if that is present, otherwise it will be able to calculate data from the other times as it does now for domains. So it would work with both QEMU and VMWare, to the best of its abilities. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

2011/4/4 Daniel P. Berrange <berrange@redhat.com>:
On Mon, Apr 04, 2011 at 11:03:10AM +0900, Minoru Usui wrote:
Hi, Matthias.
On Fri, 1 Apr 2011 20:22:17 +0200 Matthias Bolte <matthias.bolte@googlemail.com> wrote:
2011/4/1 Eric Blake <eblake@redhat.com>:
On 03/31/2011 07:55 PM, Minoru Usui wrote:
virNodeGetCpuTime: Expose new API
include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-)
+/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +};
Can we portably get all of this information on Windows? If not, how do you express which values we don't know how to obtain?
In the context of ESX I vote against this absolute CPU time values. ESX provides this values relative to a 20 second timeslots with 1 hour of history. This makes it nearly impossible to obtain the absolute CPU time. The same problem already exists for the domain's virtual CPU time.
When you look at virt-top's usage of the domain's virtual CPU time, you see that it actually doesn't really care about the absolute value, but deduces the CPU utilization from it. I suggest that we find a different representation for this information that is not by definition impossible to implement for ESX.
Matthias
I didn't know ESX couldn't return absolute CPU time value. Thank you for your comment.
We really want to get CPU utilization information of the node, not absolute CPU time values. But linux doesn't provide CPU utilization directly, so my patch returns absolute CPU time values, and CPU utilization is calculated by client which uses new API.
To return CPU utilization by new API, I think there are two issues of implementing on linux.
a) How much interval does calculate CPU utilization? To calculate CPU utilization on linux, we need to get absolute CPU time value of the node from /proc/stat two times. How much interval properly? 1sec? 1min? or others?
The fact that there is the question of what is the right interval demonstrates the inherant flaw in such an API design. Providing the raw absolute time allows an app much more flexiblity in how they work with the data, avoiding the need for such policies in libvirt.
b) Can new API wait its interval? If we select simply implementation, new API waits its interval. But API user don't want to wait every API calls, if its interval is long. So I think libvirtd will be calculating CPU utilization in background every interval. Is this approach OK?
IMHO we don't really want libvirtd to be constantly polling & calculating this data, at least not unless an application is currently asking for it. I think we want this API to have the style that is like the current virDomainMemoryStats API. Then, we can define a set of parameters that can be fetched, allowing each parameter to be optional
eg
enum { VIR_NODE_CPU_TIME_KERNEL, VIR_NODE_CPU_TIME_USER, VIR_NODE_CPU_TIME_IDLE, VIR_NODE_CPU_TIME_IOWAIT, VIR_NODE_CPU_TIME_UTILIZATION, };
For QEMU we'd provide the first 4 values, allowing apps maximum flexibility in how they calculate utilization over different time periods. For VMWare we'd provide only the last value.
An app like virt-manager, can display UTILIZATION value directly if that is present, otherwise it will be able to calculate data from the other times as it does now for domains. So it would work with both QEMU and VMWare, to the best of its abilities.
Regards, Daniel
For ESX the driver doesn't even need to calculate a usage/utilization value, because the ESX server already does this on it's own and the driver can just ask for it. The usage value is in percent and 100% represents all CPUs on the server. I like that approach. Matthias

Hi, Daniel, Matthias Thank you for your comments. On Mon, 4 Apr 2011 14:30:32 +0200 Matthias Bolte <matthias.bolte@googlemail.com> wrote:
2011/4/4 Daniel P. Berrange <berrange@redhat.com>:
On Mon, Apr 04, 2011 at 11:03:10AM +0900, Minoru Usui wrote:
Hi, Matthias.
On Fri, 1 Apr 2011 20:22:17 +0200 Matthias Bolte <matthias.bolte@googlemail.com> wrote:
2011/4/1 Eric Blake <eblake@redhat.com>:
On 03/31/2011 07:55 PM, Minoru Usui wrote:
virNodeGetCpuTime: Expose new API
include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-)
+/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +};
Can we portably get all of this information on Windows? If not, how do you express which values we don't know how to obtain?
In the context of ESX I vote against this absolute CPU time values. ESX provides this values relative to a 20 second timeslots with 1 hour of history. This makes it nearly impossible to obtain the absolute CPU time. The same problem already exists for the domain's virtual CPU time.
When you look at virt-top's usage of the domain's virtual CPU time, you see that it actually doesn't really care about the absolute value, but deduces the CPU utilization from it. I suggest that we find a different representation for this information that is not by definition impossible to implement for ESX.
Matthias
I didn't know ESX couldn't return absolute CPU time value. Thank you for your comment.
We really want to get CPU utilization information of the node, not absolute CPU time values. But linux doesn't provide CPU utilization directly, so my patch returns absolute CPU time values, and CPU utilization is calculated by client which uses new API.
To return CPU utilization by new API, I think there are two issues of implementing on linux.
a) How much interval does calculate CPU utilization? To calculate CPU utilization on linux, we need to get absolute CPU time value of the node from /proc/stat two times. How much interval properly? 1sec? 1min? or others?
The fact that there is the question of what is the right interval demonstrates the inherant flaw in such an API design. Providing the raw absolute time allows an app much more flexiblity in how they work with the data, avoiding the need for such policies in libvirt.
b) Can new API wait its interval? If we select simply implementation, new API waits its interval. But API user don't want to wait every API calls, if its interval is long. So I think libvirtd will be calculating CPU utilization in background every interval. Is this approach OK?
IMHO we don't really want libvirtd to be constantly polling & calculating this data, at least not unless an application is currently asking for it. I think we want this API to have the style that is like the current virDomainMemoryStats API. Then, we can define a set of parameters that can be fetched, allowing each parameter to be optional
eg
enum { VIR_NODE_CPU_TIME_KERNEL, VIR_NODE_CPU_TIME_USER, VIR_NODE_CPU_TIME_IDLE, VIR_NODE_CPU_TIME_IOWAIT, VIR_NODE_CPU_TIME_UTILIZATION, };
For QEMU we'd provide the first 4 values, allowing apps maximum flexibility in how they calculate utilization over different time periods. For VMWare we'd provide only the last value.
An app like virt-manager, can display UTILIZATION value directly if that is present, otherwise it will be able to calculate data from the other times as it does now for domains. So it would work with both QEMU and VMWare, to the best of its abilities.
Regards, Daniel
For ESX the driver doesn't even need to calculate a usage/utilization value, because the ESX server already does this on it's own and the driver can just ask for it. The usage value is in percent and 100% represents all CPUs on the server.
I like that approach.
Matthias
OK. I'll change the user I/F to above one. -- Minoru Usui <usui@mxm.nes.nec.co.jp>

Hi, Eric On Fri, 01 Apr 2011 10:19:20 -0600 Eric Blake <eblake@redhat.com> wrote:
On 03/31/2011 07:55 PM, Minoru Usui wrote:
virNodeGetCpuTime: Expose new API
include/libvirt/libvirt.h.in | 26 ++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 2 files changed, 27 insertions(+), 0 deletions(-)
+/** + * virNodeCpuTime: + * + * a virNodeCpuTime is a structure filled by virNodeGetCpuTime() and providing + * the information for the cpu time of Node. + */ + +typedef struct _virNodeCpuTime virNodeCpuTime; + +struct _virNodeCpuTime { + unsigned long long user; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; +};
Can we portably get all of this information on Windows? If not, how do you express which values we don't know how to obtain?
@@ -593,6 +616,9 @@ int virNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info); char * virConnectGetCapabilities (virConnectPtr conn);
+int virNodeGetCpuTime (virConnectPtr conn, + virNodeCpuTimePtr cpu_time); +
Rather than locking ourselves into yet another inflexible API (no flags parameter and a hard-coded struct means no way to extend this if we ever come up with some new stat to query), should we instead be following the lead of getMemoryParameters which takes a typed-name/value array to pass an arbitrary number of parameters, which allows extension without a new API?
OK. I'll change its user I/F like virDomainGetMemoryParameters(), if it doesn't return absolute CPU time values.
+++ b/src/libvirt_public.syms @@ -434,6 +434,7 @@ LIBVIRT_0.9.0 { virEventRunDefaultImpl; virStorageVolDownload; virStorageVolUpload; + virNodeGetCpuTime; } LIBVIRT_0.8.8;
While I think that something along the lines of this API is appropriate for libvirt (indeed, knowing a host's CPU utilization can indeed be a factor for upper-level management software in deciding whether to migrate another domain on or off of the machine), it's too late to put it into 0.9.0. We'd be setting bad precedent by accepting this after the first release candidate did a feature freeze, so you'd need to adjust this to 0.9.1.
OK. I'll change it.
-- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
-- Minoru Usui <usui@mxm.nes.nec.co.jp>

virNodeGetCpuTime: Define internal driver API --- src/driver.h | 4 ++++ src/esx/esx_driver.c | 1 + src/libxl/libxl_driver.c | 1 + src/lxc/lxc_driver.c | 1 + src/openvz/openvz_driver.c | 1 + src/phyp/phyp_driver.c | 1 + src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 1 + src/test/test_driver.c | 1 + src/uml/uml_driver.c | 1 + src/vbox/vbox_tmpl.c | 1 + src/vmware/vmware_driver.c | 1 + src/xen/xen_driver.c | 1 + src/xenapi/xenapi_driver.c | 1 + 14 files changed, 17 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index e5f91ca..f64fe31 100644 --- a/src/driver.h +++ b/src/driver.h @@ -347,6 +347,9 @@ typedef struct _virDriver virDriver; typedef virDriver *virDriverPtr; typedef int + (*virDrvNodeGetCpuTime) + (virConnectPtr conn, virNodeCpuTimePtr cpu_time); +typedef int (*virDrvNodeGetCellsFreeMemory) (virConnectPtr conn, unsigned long long *freeMems, @@ -602,6 +605,7 @@ struct _virDriver { virDrvDomainBlockPeek domainBlockPeek; virDrvDomainMemoryPeek domainMemoryPeek; virDrvDomainGetBlockInfo domainGetBlockInfo; + virDrvNodeGetCpuTime nodeGetCpuTime; virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory; virDrvNodeGetFreeMemory getFreeMemory; virDrvDomainEventRegister domainEventRegister; diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index deda372..6e55949 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -4638,6 +4638,7 @@ static virDriver esxDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ NULL, /* nodeGetCellsFreeMemory */ esxNodeGetFreeMemory, /* nodeGetFreeMemory */ NULL, /* domainEventRegister */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index e996ff6..9b5a70e 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -2316,6 +2316,7 @@ static virDriver libxlDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ NULL, /* nodeGetCellsFreeMemory */ libxlNodeGetFreeMemory, /* getFreeMemory */ libxlDomainEventRegister, /* domainEventRegister */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e905302..0e0c325 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2869,6 +2869,7 @@ static virDriver lxcDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + nodeGetCpuTime, /* nodeGetCpuTime */ nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ nodeGetFreeMemory, /* getFreeMemory */ lxcDomainEventRegister, /* domainEventRegister */ diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index fb30c37..7335c8d 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1617,6 +1617,7 @@ static virDriver openvzDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ NULL, /* domainEventRegister */ diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 51f9ff6..839649f 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -4018,6 +4018,7 @@ static virDriver phypDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ NULL, /* domainEventRegister */ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index dd12dc8..20bf4eb 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6886,6 +6886,7 @@ static virDriver qemuDriver = { qemudDomainBlockPeek, /* domainBlockPeek */ qemudDomainMemoryPeek, /* domainMemoryPeek */ qemuDomainGetBlockInfo, /* domainGetBlockInfo */ + nodeGetCpuTime, /* nodeGetCpuTime */ nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ nodeGetFreeMemory, /* getFreeMemory */ qemuDomainEventRegister, /* domainEventRegister */ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index bf94e70..2393055 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -11259,6 +11259,7 @@ static virDriver remote_driver = { remoteDomainBlockPeek, /* domainBlockPeek */ remoteDomainMemoryPeek, /* domainMemoryPeek */ remoteDomainGetBlockInfo, /* domainGetBlockInfo */ + remoteNodeGetCpuTime, /* nodeGetCpuTime */ remoteNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ remoteNodeGetFreeMemory, /* getFreeMemory */ remoteDomainEventRegister, /* domainEventRegister */ diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 17f5ad9..f122935 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5410,6 +5410,7 @@ static virDriver testDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ testDomainEventRegister, /* domainEventRegister */ diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index e2bd5f2..93fb59e 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2212,6 +2212,7 @@ static virDriver umlDriver = { umlDomainBlockPeek, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + nodeGetCpuTime, /* nodeGetCpuTime */ nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ nodeGetFreeMemory, /* getFreeMemory */ NULL, /* domainEventRegister */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 8bd27dd..6f2d4fe 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -8600,6 +8600,7 @@ virDriver NAME(Driver) = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ nodeGetFreeMemory, /* getFreeMemory */ #if VBOX_API_VERSION == 2002 || VBOX_API_VERSION == 4000 diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index b5e416b..635aa59 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -970,6 +970,7 @@ static virDriver vmwareDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ NULL, /* domainEventRegister */ diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 9f47722..af18baa 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -2104,6 +2104,7 @@ static virDriver xenUnifiedDriver = { xenUnifiedDomainBlockPeek, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ xenUnifiedNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ xenUnifiedNodeGetFreeMemory, /* getFreeMemory */ xenUnifiedDomainEventRegister, /* domainEventRegister */ diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 27206a0..7800dd1 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -1848,6 +1848,7 @@ static virDriver xenapiDriver = { NULL, /* domainBlockPeek */ NULL, /* domainMemoryPeek */ NULL, /* domainGetBlockInfo */ + NULL, /* nodeGetCpuTime */ xenapiNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ xenapiNodeGetFreeMemory, /* getFreeMemory */ NULL, /* domainEventRegister */ -- 1.7.1 -- Minoru Usui <usui@mxm.nes.nec.co.jp>

virNodeGetCpuTime: Implement public API --- src/libvirt.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 38 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 9bdb4c8..f3ef6ed 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -4260,6 +4260,44 @@ error: } /** + * virNodeGetCpuTime: + * @conn: pointer to the hypervisor connection + * + * provides the cumulative CPU time, when the Node booting up. + * Note: The CPU time used in nanoseconds. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virNodeGetCpuTime(virConnectPtr conn ATTRIBUTE_UNUSED, + virNodeCpuTimePtr cpu_time) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + + if (!VIR_IS_CONNECT (conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return 0; + } + + if (conn->driver->nodeGetCpuTime) { + int ret; + ret = conn->driver->nodeGetCpuTime(conn, cpu_time); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return 0; +} + +/** * virNodeGetFreeMemory: * @conn: pointer to the hypervisor connection * -- 1.7.1 -- Minoru Usui <usui@mxm.nes.nec.co.jp>

virNodeGetCpuTime: Implement remote protocol --- daemon/remote.c | 23 +++++++++++++++++++++++ daemon/remote_dispatch_prototypes.h | 8 ++++++++ daemon/remote_dispatch_ret.h | 1 + daemon/remote_dispatch_table.h | 5 +++++ src/remote/remote_driver.c | 26 ++++++++++++++++++++++++++ src/remote/remote_protocol.c | 15 +++++++++++++++ src/remote/remote_protocol.h | 11 +++++++++++ src/remote/remote_protocol.x | 10 +++++++++- src/remote_protocol-structs | 6 ++++++ 9 files changed, 104 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 1700c2d..64daad8 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -679,6 +679,29 @@ remoteDispatchGetCapabilities (struct qemud_server *server ATTRIBUTE_UNUSED, } static int +remoteDispatchNodeGetCpuTime (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + void *args ATTRIBUTE_UNUSED, + remote_node_get_cpu_time_ret *ret) +{ + virNodeCpuTime cpu_time; + + if (virNodeGetCpuTime(conn, &cpu_time) == -1) { + remoteDispatchConnError(rerr, conn); + return -1; + } + ret->user = cpu_time.user; + ret->system = cpu_time.system; + ret->idle = cpu_time.idle; + ret->iowait = cpu_time.iowait; + + return 0; +} + +static int remoteDispatchNodeGetCellsFreeMemory (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client ATTRIBUTE_UNUSED, virConnectPtr conn, diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index 18bf41d..6cfe443 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -1138,6 +1138,14 @@ static int remoteDispatchNodeGetCellsFreeMemory( remote_error *err, remote_node_get_cells_free_memory_args *args, remote_node_get_cells_free_memory_ret *ret); +static int remoteDispatchNodeGetCpuTime( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + void *args, + remote_node_get_cpu_time_ret *ret); static int remoteDispatchNodeGetFreeMemory( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h index 114e832..dfed98b 100644 --- a/daemon/remote_dispatch_ret.h +++ b/daemon/remote_dispatch_ret.h @@ -140,3 +140,4 @@ remote_domain_is_updated_ret val_remote_domain_is_updated_ret; remote_get_sysinfo_ret val_remote_get_sysinfo_ret; remote_domain_get_blkio_parameters_ret val_remote_domain_get_blkio_parameters_ret; + remote_node_get_cpu_time_ret val_remote_node_get_cpu_time_ret; diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index b39f7c2..3e93d3e 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -1052,3 +1052,8 @@ .args_filter = (xdrproc_t) xdr_remote_storage_vol_download_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* NodeGetCpuTime => 210 */ + .fn = (dispatch_fn) remoteDispatchNodeGetCpuTime, + .args_filter = (xdrproc_t) xdr_void, + .ret_filter = (xdrproc_t) xdr_remote_node_get_cpu_time_ret, +}, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 2393055..aba68fd 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -1934,6 +1934,32 @@ done: } static int +remoteNodeGetCpuTime (virConnectPtr conn, virNodeCpuTimePtr cpu_time) +{ + int rv = -1; + remote_node_get_cpu_time_ret ret; + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_CPU_TIME, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_node_get_cpu_time_ret, (char *) &ret) == -1) + goto done; + + cpu_time->user = ret.user; + cpu_time->system = ret.system; + cpu_time->idle = ret.idle; + cpu_time->iowait = ret.iowait; + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems, int startCell, diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 5604371..eb9c4b9 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -607,6 +607,21 @@ xdr_remote_get_capabilities_ret (XDR *xdrs, remote_get_capabilities_ret *objp) } bool_t +xdr_remote_node_get_cpu_time_ret (XDR *xdrs, remote_node_get_cpu_time_ret *objp) +{ + + if (!xdr_uint64_t (xdrs, &objp->user)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->system)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->idle)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->iowait)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_node_get_cells_free_memory_args (XDR *xdrs, remote_node_get_cells_free_memory_args *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index d9bf151..c17a03b 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -304,6 +304,14 @@ struct remote_get_capabilities_ret { }; typedef struct remote_get_capabilities_ret remote_get_capabilities_ret; +struct remote_node_get_cpu_time_ret { + uint64_t user; + uint64_t system; + uint64_t idle; + uint64_t iowait; +}; +typedef struct remote_node_get_cpu_time_ret remote_node_get_cpu_time_ret; + struct remote_node_get_cells_free_memory_args { int startCell; int maxCells; @@ -2413,6 +2421,7 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_NODE_GET_CPU_TIME = 210, }; typedef enum remote_procedure remote_procedure; @@ -2486,6 +2495,7 @@ extern bool_t xdr_remote_get_max_vcpus_args (XDR *, remote_get_max_vcpus_args*) extern bool_t xdr_remote_get_max_vcpus_ret (XDR *, remote_get_max_vcpus_ret*); extern bool_t xdr_remote_node_get_info_ret (XDR *, remote_node_get_info_ret*); extern bool_t xdr_remote_get_capabilities_ret (XDR *, remote_get_capabilities_ret*); +extern bool_t xdr_remote_node_get_cpu_time_ret (XDR *, remote_node_get_cpu_time_ret*); extern bool_t xdr_remote_node_get_cells_free_memory_args (XDR *, remote_node_get_cells_free_memory_args*); extern bool_t xdr_remote_node_get_cells_free_memory_ret (XDR *, remote_node_get_cells_free_memory_ret*); extern bool_t xdr_remote_node_get_free_memory_ret (XDR *, remote_node_get_free_memory_ret*); @@ -2843,6 +2853,7 @@ extern bool_t xdr_remote_get_max_vcpus_args (); extern bool_t xdr_remote_get_max_vcpus_ret (); extern bool_t xdr_remote_node_get_info_ret (); extern bool_t xdr_remote_get_capabilities_ret (); +extern bool_t xdr_remote_node_get_cpu_time_ret (); extern bool_t xdr_remote_node_get_cells_free_memory_args (); extern bool_t xdr_remote_node_get_cells_free_memory_ret (); extern bool_t xdr_remote_node_get_free_memory_ret (); diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 675eccd..a16a74a 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -440,6 +440,13 @@ struct remote_get_capabilities_ret { remote_nonnull_string capabilities; }; +struct remote_node_get_cpu_time_ret { + unsigned hyper user; + unsigned hyper system; + unsigned hyper idle; + unsigned hyper iowait; +}; + struct remote_node_get_cells_free_memory_args { int startCell; int maxCells; @@ -2176,7 +2183,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, - REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209 + REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, + REMOTE_PROC_NODE_GET_CPU_TIME = 210 /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 944553c..415132f 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -151,6 +151,12 @@ struct remote_node_get_info_ret { struct remote_get_capabilities_ret { remote_nonnull_string capabilities; }; +struct remote_node_get_cpu_time_ret { + uint64_t user; + uint64_t system; + uint64_t idle; + uint64_t iowait; +}; struct remote_node_get_cells_free_memory_args { int startCell; int maxCells; -- 1.7.1 -- Minoru Usui <usui@mxm.nes.nec.co.jp>

virNodeGetCpuTime: Implement virsh support Add nodecputime subcommand to virsh. This subcommand prints below output. # ./virsh nodecputime user : 4280000000000.0s system: 13620000000000.0s idle : 1697380000000000.0s iowait: 76120000000000.0s # ./virsh nodecputime --percent user : 6.4% system: 3.2% idle : 89.6% iowait: 0.8 --- tools/virsh.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++++ 2 files changed, 72 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index faeaf47..5da35d8 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -3387,6 +3387,71 @@ cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) } /* + * "nodecputime" command + */ +static const vshCmdInfo info_nodecputime[] = { + {"help", N_("Prints cpu time of the node.")}, + {"desc", N_("Returns user/system/idle/iowait time of the node.(nsec)")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_cpu_time[] = { + {"percent", VSH_OT_BOOL, 0, N_("prints by percentage during 1 second.")}, + {NULL, 0, 0, NULL} +}; + +#define NSEC_TO_SEC ((double)1.0 / 1000 * 1000 * 1000) +static int +cmdNodeCpuTime(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virNodeCpuTime cpu_time[2]; + int percent = vshCommandOptBool(cmd, "percent"); + double user, sys, idle, iowait, total; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return FALSE; + + memset(&cpu_time, 0, sizeof(cpu_time)); + + if (virNodeGetCpuTime(ctl->conn, &cpu_time[0]) < 0) { + vshError(ctl, "%s", _("failed to get cpu time of the node.")); + return FALSE; + } + + if (!percent) { + vshPrint(ctl, "%-15s %.1lfs\n", _("user :"), + cpu_time[0].user * NSEC_TO_SEC); + vshPrint(ctl, "%-15s %.1lfs\n", _("system:"), + cpu_time[0].system * NSEC_TO_SEC); + vshPrint(ctl, "%-15s %.1lfs\n", _("idle :"), + cpu_time[0].idle * NSEC_TO_SEC); + vshPrint(ctl, "%-15s %.1lfs\n", _("iowait:"), + cpu_time[0].iowait * NSEC_TO_SEC); + return TRUE; + } + + sleep(1); + + if (virNodeGetCpuTime(ctl->conn, &cpu_time[1]) < 0) { + vshError(ctl, "%s", _("failed to get cpu time of the node.")); + return FALSE; + } + + user = cpu_time[1].user - cpu_time[0].user; + sys = cpu_time[1].system - cpu_time[0].system; + idle = cpu_time[1].idle - cpu_time[0].idle; + iowait = cpu_time[1].iowait - cpu_time[0].iowait; + total = user + sys + idle + iowait; + + vshPrint(ctl, "%-15s %5.1lf%%\n", _("user :"), user / total * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", _("system:"), sys / total * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", _("idle :"), idle / total * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", _("iowait:"), iowait / total * 100); + + return TRUE; +} + +/* * "capabilities" command */ static const vshCmdInfo info_capabilities[] = { @@ -10851,6 +10916,7 @@ static const vshCmdDef hostAndHypervisorCmds[] = { {"freecell", cmdFreecell, opts_freecell, info_freecell}, {"hostname", cmdHostname, NULL, info_hostname}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo}, + {"nodecputime", cmdNodeCpuTime, opts_node_cpu_time, info_nodecputime}, {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, info_qemu_monitor_command}, {"sysinfo", cmdSysinfo, NULL, info_sysinfo}, {"uri", cmdURI, NULL, info_uri}, diff --git a/tools/virsh.pod b/tools/virsh.pod index e882261..244b097 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -237,6 +237,12 @@ Print the XML representation of the hypervisor sysinfo, if available. Returns basic information about the node, like number and type of CPU, and size of the physical memory. +=item B<nodecputime> optional I<--percent> + +Returns user/system/idle/iowait cpu time of the node, if I<--percent> +is specified this will prints percentage of each kind of cpu time +during 1 second. + =item B<capabilities> Print an XML document describing the capabilities of the hypervisor -- 1.7.1 -- Minoru Usui <usui@mxm.nes.nec.co.jp>

virNodeGetCpuTime: Implement linux support --- src/libvirt_private.syms | 1 + src/nodeinfo.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 2 +- 3 files changed, 62 insertions(+), 1 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 65a86d3..b879454 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -651,6 +651,7 @@ virNodeDeviceObjUnlock; # nodeinfo.h nodeCapsInitNUMA; +nodeGetCpuTime; nodeGetCellsFreeMemory; nodeGetFreeMemory; nodeGetInfo; diff --git a/src/nodeinfo.c b/src/nodeinfo.c index 5d40aca..81222ec 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -57,12 +57,15 @@ #ifdef __linux__ # define CPUINFO_PATH "/proc/cpuinfo" # define CPU_SYS_PATH "/sys/devices/system/cpu" +# define PROCSTAT_PATH "/proc/stat" /* NB, this is not static as we need to call it from the testsuite */ int linuxNodeInfoCPUPopulate(FILE *cpuinfo, virNodeInfoPtr nodeinfo, bool need_hyperthreads); +int linuxNodeCpuTime(FILE *procstat, virNodeCpuTimePtr cpu_time); + /* Return the positive decimal contents of the given * CPU_SYS_PATH/cpu%u/FILE, or -1 on error. If MISSING_OK and the * file could not be found, return 1 instead of an error; this is @@ -322,6 +325,38 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo, return 0; } +#define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK)) + +int linuxNodeCpuTime(FILE *procstat, virNodeCpuTimePtr cpu_time) +{ + char line[1024]; + unsigned long long usr, ni, sys, idle, iowait; + unsigned long long irq, softirq, steal, guest, guest_nice;; + + memset(cpu_time, 0, sizeof(*cpu_time)); + while (fgets(line, sizeof(line), procstat) != NULL) { + char *buf = line; + + if (STRPREFIX(buf, "cpu ")) { /* aka total logical CPU time */ + if (sscanf(buf, + "%*s %llu %llu %llu %llu %llu" // user ~ iowait + "%llu %llu %llu %llu %llu", // irq ~ guest_nice + &usr, &ni, &sys, &idle, &iowait, + &irq, &softirq, &steal, &guest, &guest_nice) < 4) { + return -1; + } + cpu_time->user = (usr + ni) * TICK_TO_NSEC; + cpu_time->system = (sys + irq + softirq) * TICK_TO_NSEC; + cpu_time->idle = idle * TICK_TO_NSEC; + cpu_time->iowait = iowait * TICK_TO_NSEC; + + return 0; + } + } + + nodeReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no \'cpu\' line found")); + return -1; +} #endif int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) { @@ -360,6 +395,31 @@ int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) { #endif } +int nodeGetCpuTime(virConnectPtr conn ATTRIBUTE_UNUSED, + virNodeCpuTimePtr cpu_time) +{ + +#ifdef __linux__ + { + int ret; + FILE *procstat = fopen(PROCSTAT_PATH, "r"); + if (!procstat) { + virReportSystemError(errno, + _("cannot open %s"), PROCSTAT_PATH); + return -1; + } + ret = linuxNodeCpuTime(procstat, cpu_time); + VIR_FORCE_FCLOSE(procstat); + + return ret; + } +#else + nodeReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node CPU time not implemented on this platform")); + return -1; +#endif +} + #if HAVE_NUMACTL # if LIBNUMA_API_VERSION <= 1 # define NUMA_MAX_N_CPUS 4096 diff --git a/src/nodeinfo.h b/src/nodeinfo.h index 88bac6c..106e9c1 100644 --- a/src/nodeinfo.h +++ b/src/nodeinfo.h @@ -30,7 +30,7 @@ int nodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo); int nodeCapsInitNUMA(virCapsPtr caps); - +int nodeGetCpuTime(virConnectPtr conn, virNodeCpuTimePtr cpu_time); int nodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems, int startCell, -- 1.7.1 -- Minoru Usui <usui@mxm.nes.nec.co.jp>
participants (4)
-
Daniel P. Berrange
-
Eric Blake
-
Matthias Bolte
-
Minoru Usui