Merge pull request #14741 from jasontedor/return-of-the-cpu-percent

Add system CPU percent to OS stats
This commit is contained in:
Jason Tedor 2015-11-17 13:49:49 -05:00
commit 450aa7b3ce
9 changed files with 109 additions and 35 deletions

View File

@ -0,0 +1,20 @@
package org.elasticsearch.monitor;
import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
public class Probes {
public static short getLoadAndScaleToPercent(Method method, OperatingSystemMXBean osMxBean) {
if (method != null) {
try {
double load = (double) method.invoke(osMxBean);
if (load >= 0) {
return (short) (load * 100);
}
} catch (Throwable t) {
return -1;
}
}
return -1;
}
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.monitor.os; package org.elasticsearch.monitor.os;
import org.apache.lucene.util.Constants; import org.apache.lucene.util.Constants;
import org.elasticsearch.monitor.Probes;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean; import java.lang.management.OperatingSystemMXBean;
@ -34,6 +35,7 @@ public class OsProbe {
private static final Method getFreeSwapSpaceSize; private static final Method getFreeSwapSpaceSize;
private static final Method getTotalSwapSpaceSize; private static final Method getTotalSwapSpaceSize;
private static final Method getSystemLoadAverage; private static final Method getSystemLoadAverage;
private static final Method getSystemCpuLoad;
static { static {
getFreePhysicalMemorySize = getMethod("getFreePhysicalMemorySize"); getFreePhysicalMemorySize = getMethod("getFreePhysicalMemorySize");
@ -41,6 +43,7 @@ public class OsProbe {
getFreeSwapSpaceSize = getMethod("getFreeSwapSpaceSize"); getFreeSwapSpaceSize = getMethod("getFreeSwapSpaceSize");
getTotalSwapSpaceSize = getMethod("getTotalSwapSpaceSize"); getTotalSwapSpaceSize = getMethod("getTotalSwapSpaceSize");
getSystemLoadAverage = getMethod("getSystemLoadAverage"); getSystemLoadAverage = getMethod("getSystemLoadAverage");
getSystemCpuLoad = getMethod("getSystemCpuLoad");
} }
/** /**
@ -113,6 +116,10 @@ public class OsProbe {
} }
} }
public short getSystemCpuPercent() {
return Probes.getLoadAndScaleToPercent(getSystemCpuLoad, osMxBean);
}
private static class OsProbeHolder { private static class OsProbeHolder {
private final static OsProbe INSTANCE = new OsProbe(); private final static OsProbe INSTANCE = new OsProbe();
} }
@ -136,7 +143,9 @@ public class OsProbe {
public OsStats osStats() { public OsStats osStats() {
OsStats stats = new OsStats(); OsStats stats = new OsStats();
stats.timestamp = System.currentTimeMillis(); stats.timestamp = System.currentTimeMillis();
stats.loadAverage = getSystemLoadAverage(); stats.cpu = new OsStats.Cpu();
stats.cpu.percent = getSystemCpuPercent();
stats.cpu.loadAverage = getSystemLoadAverage();
OsStats.Mem mem = new OsStats.Mem(); OsStats.Mem mem = new OsStats.Mem();
mem.total = getTotalPhysicalMemorySize(); mem.total = getTotalPhysicalMemorySize();

View File

@ -36,7 +36,7 @@ public class OsStats implements Streamable, ToXContent {
long timestamp; long timestamp;
double loadAverage = -1; Cpu cpu = null;
Mem mem = null; Mem mem = null;
@ -49,10 +49,7 @@ public class OsStats implements Streamable, ToXContent {
return timestamp; return timestamp;
} }
public double getLoadAverage() { public Cpu getCpu() { return cpu; }
return loadAverage;
}
public Mem getMem() { public Mem getMem() {
return mem; return mem;
@ -65,6 +62,8 @@ public class OsStats implements Streamable, ToXContent {
static final class Fields { static final class Fields {
static final XContentBuilderString OS = new XContentBuilderString("os"); static final XContentBuilderString OS = new XContentBuilderString("os");
static final XContentBuilderString TIMESTAMP = new XContentBuilderString("timestamp"); static final XContentBuilderString TIMESTAMP = new XContentBuilderString("timestamp");
static final XContentBuilderString CPU = new XContentBuilderString("cpu");
static final XContentBuilderString PERCENT = new XContentBuilderString("percent");
static final XContentBuilderString LOAD_AVERAGE = new XContentBuilderString("load_average"); static final XContentBuilderString LOAD_AVERAGE = new XContentBuilderString("load_average");
static final XContentBuilderString MEM = new XContentBuilderString("mem"); static final XContentBuilderString MEM = new XContentBuilderString("mem");
@ -85,7 +84,12 @@ public class OsStats implements Streamable, ToXContent {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(Fields.OS); builder.startObject(Fields.OS);
builder.field(Fields.TIMESTAMP, getTimestamp()); builder.field(Fields.TIMESTAMP, getTimestamp());
builder.field(Fields.LOAD_AVERAGE, getLoadAverage()); if (cpu != null) {
builder.startObject(Fields.CPU);
builder.field(Fields.PERCENT, cpu.getPercent());
builder.field(Fields.LOAD_AVERAGE, cpu.getLoadAverage());
builder.endObject();
}
if (mem != null) { if (mem != null) {
builder.startObject(Fields.MEM); builder.startObject(Fields.MEM);
@ -120,7 +124,7 @@ public class OsStats implements Streamable, ToXContent {
@Override @Override
public void readFrom(StreamInput in) throws IOException { public void readFrom(StreamInput in) throws IOException {
timestamp = in.readVLong(); timestamp = in.readVLong();
loadAverage = in.readDouble(); cpu = in.readOptionalStreamable(Cpu::new);
if (in.readBoolean()) { if (in.readBoolean()) {
mem = Mem.readMem(in); mem = Mem.readMem(in);
} }
@ -132,7 +136,7 @@ public class OsStats implements Streamable, ToXContent {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeVLong(timestamp); out.writeVLong(timestamp);
out.writeDouble(loadAverage); out.writeOptionalStreamable(cpu);
if (mem == null) { if (mem == null) {
out.writeBoolean(false); out.writeBoolean(false);
} else { } else {
@ -147,6 +151,39 @@ public class OsStats implements Streamable, ToXContent {
} }
} }
public static class Cpu implements Streamable {
short percent = -1;
double loadAverage = -1;
Cpu() {}
public static Cpu readCpu(StreamInput in) throws IOException {
Cpu cpu = new Cpu();
cpu.readFrom(in);
return cpu;
}
@Override
public void readFrom(StreamInput in) throws IOException {
percent = in.readShort();
loadAverage = in.readDouble();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeShort(percent);
out.writeDouble(loadAverage);
}
public short getPercent() {
return percent;
}
public double getLoadAverage() {
return loadAverage;
}
}
public static class Swap implements Streamable { public static class Swap implements Streamable {
long total = -1; long total = -1;
@ -230,5 +267,4 @@ public class OsStats implements Streamable, ToXContent {
private static short calculatePercentage(long used, long max) { private static short calculatePercentage(long used, long max) {
return max <= 0 ? 0 : (short) (Math.round((100d * used) / max)); return max <= 0 ? 0 : (short) (Math.round((100d * used) / max));
} }
} }

View File

@ -20,6 +20,7 @@
package org.elasticsearch.monitor.process; package org.elasticsearch.monitor.process;
import org.elasticsearch.bootstrap.BootstrapInfo; import org.elasticsearch.bootstrap.BootstrapInfo;
import org.elasticsearch.monitor.Probes;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean; import java.lang.management.OperatingSystemMXBean;
@ -88,17 +89,7 @@ public class ProcessProbe {
* Returns the process CPU usage in percent * Returns the process CPU usage in percent
*/ */
public short getProcessCpuPercent() { public short getProcessCpuPercent() {
if (getProcessCpuLoad != null) { return Probes.getLoadAndScaleToPercent(getProcessCpuLoad, osMxBean);
try {
double load = (double) getProcessCpuLoad.invoke(osMxBean);
if (load >= 0) {
return (short) (load * 100);
}
} catch (Throwable t) {
return -1;
}
}
return -1;
} }
/** /**

View File

@ -130,6 +130,7 @@ public class RestNodesAction extends AbstractCatAction {
table.addCell("file_desc.percent", "default:false;alias:fdp,fileDescriptorPercent;text-align:right;desc:used file descriptor ratio"); table.addCell("file_desc.percent", "default:false;alias:fdp,fileDescriptorPercent;text-align:right;desc:used file descriptor ratio");
table.addCell("file_desc.max", "default:false;alias:fdm,fileDescriptorMax;text-align:right;desc:max file descriptors"); table.addCell("file_desc.max", "default:false;alias:fdm,fileDescriptorMax;text-align:right;desc:max file descriptors");
table.addCell("cpu", "alias:cpu;text-align:right;desc:recent cpu usage");
table.addCell("load", "alias:l;text-align:right;desc:most recent load avg"); table.addCell("load", "alias:l;text-align:right;desc:most recent load avg");
table.addCell("uptime", "default:false;alias:u;text-align:right;desc:node uptime"); table.addCell("uptime", "default:false;alias:u;text-align:right;desc:node uptime");
table.addCell("node.role", "alias:r,role,dc,nodeRole;desc:d:data node, c:client node"); table.addCell("node.role", "alias:r,role,dc,nodeRole;desc:d:data node, c:client node");
@ -258,7 +259,8 @@ public class RestNodesAction extends AbstractCatAction {
table.addCell(processStats == null ? null : calculatePercentage(processStats.getOpenFileDescriptors(), processStats.getMaxFileDescriptors())); table.addCell(processStats == null ? null : calculatePercentage(processStats.getOpenFileDescriptors(), processStats.getMaxFileDescriptors()));
table.addCell(processStats == null ? null : processStats.getMaxFileDescriptors()); table.addCell(processStats == null ? null : processStats.getMaxFileDescriptors());
table.addCell(osStats == null ? null : String.format(Locale.ROOT, "%.2f", osStats.getLoadAverage())); table.addCell(osStats == null ? null : Short.toString(osStats.getCpu().getPercent()));
table.addCell(osStats == null ? null : String.format(Locale.ROOT, "%.2f", osStats.getCpu().getLoadAverage()));
table.addCell(jvmStats == null ? null : jvmStats.getUptime()); table.addCell(jvmStats == null ? null : jvmStats.getUptime());
table.addCell(node.clientNode() ? "c" : node.dataNode() ? "d" : "-"); table.addCell(node.clientNode() ? "c" : node.dataNode() ? "d" : "-");
table.addCell(masterId == null ? "x" : masterId.equals(node.id()) ? "*" : node.masterNode() ? "m" : "-"); table.addCell(masterId == null ? "x" : masterId.equals(node.id()) ? "*" : node.masterNode() ? "m" : "-");

View File

@ -41,12 +41,10 @@ public class OsProbeBenchmark {
probe.getTotalSwapSpaceSize(); probe.getTotalSwapSpaceSize();
probe.getFreeSwapSpaceSize(); probe.getFreeSwapSpaceSize();
probe.getSystemLoadAverage(); probe.getSystemLoadAverage();
probe.getSystemCpuPercent();
} }
logger.info("--> warmed up"); logger.info("--> warmed up");
logger.info("--> testing 'getTotalPhysicalMemorySize' method..."); logger.info("--> testing 'getTotalPhysicalMemorySize' method...");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) { for (int i = 0; i < ITERATIONS; i++) {
@ -86,5 +84,13 @@ public class OsProbeBenchmark {
} }
elapsed = System.currentTimeMillis() - start; elapsed = System.currentTimeMillis() - start;
logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS)); logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
logger.info("--> testing 'getSystemCpuPercent' method...");
start = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
probe.getSystemCpuPercent();
}
elapsed = System.currentTimeMillis() - start;
logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
} }
} }

View File

@ -22,13 +22,7 @@ package org.elasticsearch.monitor.os;
import org.apache.lucene.util.Constants; import org.apache.lucene.util.Constants;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
public class OsProbeTests extends ESTestCase { public class OsProbeTests extends ESTestCase {
OsProbe probe = OsProbe.getInstance(); OsProbe probe = OsProbe.getInstance();
@ -47,12 +41,13 @@ public class OsProbeTests extends ESTestCase {
OsStats stats = probe.osStats(); OsStats stats = probe.osStats();
assertNotNull(stats); assertNotNull(stats);
assertThat(stats.getTimestamp(), greaterThan(0L)); assertThat(stats.getTimestamp(), greaterThan(0L));
assertThat(stats.getCpu().getPercent(), anyOf(equalTo((short) -1), is(both(greaterThanOrEqualTo((short) 0)).and(lessThanOrEqualTo((short) 100)))));
if (Constants.WINDOWS) { if (Constants.WINDOWS) {
// Load average is always -1 on Windows platforms // Load average is always -1 on Windows platforms
assertThat(stats.getLoadAverage(), equalTo((double) -1)); assertThat(stats.getCpu().getLoadAverage(), equalTo((double) -1));
} else { } else {
// Load average can be negative if not available or not computed yet, otherwise it should be >= 0 // Load average can be negative if not available or not computed yet, otherwise it should be >= 0
assertThat(stats.getLoadAverage(), anyOf(lessThan((double) 0), greaterThanOrEqualTo((double) 0))); assertThat(stats.getCpu().getLoadAverage(), anyOf(lessThan((double) 0), greaterThanOrEqualTo((double) 0)));
} }
assertNotNull(stats.getMem()); assertNotNull(stats.getMem());

View File

@ -128,7 +128,10 @@ the operating system:
`os.timestamp`:: `os.timestamp`::
Last time the operating system statistics have been refreshed Last time the operating system statistics have been refreshed
`os.load_average`:: `os.cpu.percent`::
Recent CPU usage for the whole system, or -1 if not supported
`os.cpu.load_average`::
System load average for the last minute, or -1 if not supported System load average for the last minute, or -1 if not supported
`os.mem.total_in_bytes`:: `os.mem.total_in_bytes`::

View File

@ -428,3 +428,15 @@ controls the backing queue for the thread pool and modifying this is an expert s
and high risk of being misused. The ability to change the thread pool type for any thread pool has been removed; do note and high risk of being misused. The ability to change the thread pool type for any thread pool has been removed; do note
that it is still possible to adjust relevant thread pool parameters for each of the thread pools (e.g., depending on that it is still possible to adjust relevant thread pool parameters for each of the thread pools (e.g., depending on
the thread pool type, `keep_alive`, `queue_size`, etc.). the thread pool type, `keep_alive`, `queue_size`, etc.).
=== Adding system CPU percent to OS stats
The recent CPU usage (as a percent) has been added to the OS stats reported under the node stats API and the cat nodes
API. The breaking change here is that there is a new object in the "os" object in the node stats response. This object
is called "cpu" and includes "percent" and "load_average" as fields. This moves the "load_average" field that was
previously a top-level field in the "os" object to the "cpu" object. Additionally, the "cpu" field in the cat nodes API
response is output by default.
Finally, the API for org.elasticsearch.monitor.os.OsStats has changed. The `getLoadAverage` method has been removed. The
value for this can now be obtained from `OsStats.Cpu#getLoadAverage`. Additionally, the recent CPU usage can be obtained
from `OsStats.Cpu#getPercent`.