View Javadoc
1   /**
2    * Oshi (https://github.com/dblock/oshi)
3    * 
4    * Copyright (c) 2010 - 2015 The Oshi Project Team
5    * 
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of the Eclipse Public License v1.0
8    * which accompanies this distribution, and is available at
9    * http://www.eclipse.org/legal/epl-v10.html
10   * 
11   * Contributors:
12   * dblock[at]dblock[dot]org
13   * alessandro[at]perucchi[dot]org
14   * widdis[at]gmail[dot]com
15   * https://github.com/dblock/oshi/graphs/contributors
16   */
17  package oshi.software.os.linux.proc;
18  
19  import java.io.IOException;
20  import java.lang.management.ManagementFactory;
21  import java.util.List;
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  import oshi.hardware.Processor;
26  import oshi.util.FileUtil;
27  import oshi.util.ParseUtil;
28  
29  /**
30   * A CPU as defined in Linux /proc.
31   * 
32   * @author alessandro[at]perucchi[dot]org
33   * @author alessio.fachechi[at]gmail[dot]com
34   * @author widdis[at]gmail[dot]com
35   */
36  @SuppressWarnings("restriction")
37  public class CentralProcessor implements Processor {
38  	// Determine whether MXBean supports Oracle JVM methods
39  	private static final java.lang.management.OperatingSystemMXBean OS_MXBEAN = ManagementFactory
40  			.getOperatingSystemMXBean();;
41  	private static boolean sunMXBean;
42  	static {
43  		try {
44  			Class.forName("com.sun.management.OperatingSystemMXBean");
45  			// Initialize CPU usage
46  			((com.sun.management.OperatingSystemMXBean) OS_MXBEAN)
47  					.getSystemCpuLoad();
48  			sunMXBean = true;
49  		} catch (ClassNotFoundException e) {
50  			sunMXBean = false;
51  		}
52  	}
53  	// Maintain two sets of previous ticks to be used for calculating usage
54  	// between them.
55  	// System ticks (static)
56  	private static long tickTime = System.currentTimeMillis();
57  	private static long[] prevTicks = new long[4];
58  	private static long[] curTicks = new long[4];
59  	static {
60  		updateSystemTicks();
61  		System.arraycopy(curTicks, 0, prevTicks, 0, curTicks.length);
62  	}
63  
64  	// Maintain similar arrays for per-processor ticks (class variables)
65  	private long procTickTime = System.currentTimeMillis();
66  	private long[] prevProcTicks = new long[4];
67  	private long[] curProcTicks = new long[4];
68  
69  	// Initialize numCPU
70  	private static int numCPU = 0;
71  	static {
72  		try {
73  			List<String> procCpu = FileUtil.readFile("/proc/cpuinfo");
74  			for (String cpu : procCpu) {
75  				if (cpu.startsWith("core id")) {
76  					numCPU++;
77  				}
78  			}
79  		} catch (IOException e) {
80  			System.err.println("Problem with: /proc/cpuinfo");
81  			System.err.println(e.getMessage());
82  		}
83  	}
84  	// Set up array to maintain current ticks for rapid reference. This array
85  	// will be updated in place and used as a cache to avoid rereading file
86  	// while iterating processors
87  	private static long[][] allProcessorTicks = new long[numCPU][4];
88  	private static long allProcTickTime = 0;
89  
90  	private int processorNumber;
91  	private String cpuVendor;
92  	private String cpuName;
93  	private String cpuIdentifier = null;
94  	private String cpuStepping;
95  	private String cpuModel;
96  	private String cpuFamily;
97  	private Long cpuVendorFreq = null;
98  	private Boolean cpu64;
99  
100 	/**
101 	 * Create a Processor with the given number
102 	 * 
103 	 * @param procNo
104 	 */
105 	public CentralProcessor(int procNo) {
106 		if (procNo >= numCPU)
107 			throw new IllegalArgumentException("Processor number (" + procNo
108 					+ ") must be less than the number of CPUs: " + numCPU);
109 		this.processorNumber = procNo;
110 		updateProcessorTicks();
111 		System.arraycopy(allProcessorTicks[processorNumber], 0, curProcTicks,
112 				0, curProcTicks.length);
113 	}
114 
115 	/**
116 	 * {@inheritDoc}
117 	 */
118 	@Override
119 	public int getProcessorNumber() {
120 		return processorNumber;
121 	}
122 
123 	/**
124 	 * Vendor identifier, eg. GenuineIntel.
125 	 * 
126 	 * @return Processor vendor.
127 	 */
128 	@Override
129 	public String getVendor() {
130 		return this.cpuVendor;
131 	}
132 
133 	/**
134 	 * Set processor vendor.
135 	 * 
136 	 * @param vendor
137 	 *            Vendor.
138 	 */
139 	@Override
140 	public void setVendor(String vendor) {
141 		this.cpuVendor = vendor;
142 	}
143 
144 	/**
145 	 * Name, eg. Intel(R) Core(TM)2 Duo CPU T7300 @ 2.00GHz
146 	 * 
147 	 * @return Processor name.
148 	 */
149 	@Override
150 	public String getName() {
151 		return this.cpuName;
152 	}
153 
154 	/**
155 	 * Set processor name.
156 	 * 
157 	 * @param name
158 	 *            Name.
159 	 */
160 	@Override
161 	public void setName(String name) {
162 		this.cpuName = name;
163 	}
164 
165 	/**
166 	 * Vendor frequency (in Hz), eg. for processor named Intel(R) Core(TM)2 Duo
167 	 * CPU T7300 @ 2.00GHz the vendor frequency is 2000000000.
168 	 * 
169 	 * @return Processor frequency or -1 if unknown.
170 	 */
171 	@Override
172 	public long getVendorFreq() {
173 		if (this.cpuVendorFreq == null) {
174 			Pattern pattern = Pattern.compile("@ (.*)$");
175 			Matcher matcher = pattern.matcher(getName());
176 
177 			if (matcher.find()) {
178 				String unit = matcher.group(1);
179 				this.cpuVendorFreq = Long.valueOf(ParseUtil.parseHertz(unit));
180 			} else {
181 				this.cpuVendorFreq = Long.valueOf(-1L);
182 			}
183 		}
184 
185 		return this.cpuVendorFreq.longValue();
186 	}
187 
188 	/**
189 	 * Set vendor frequency.
190 	 * 
191 	 * @param freq
192 	 *            Frequency.
193 	 */
194 	@Override
195 	public void setVendorFreq(long freq) {
196 		this.cpuVendorFreq = Long.valueOf(freq);
197 	}
198 
199 	/**
200 	 * Identifier, eg. x86 Family 6 Model 15 Stepping 10.
201 	 * 
202 	 * @return Processor identifier.
203 	 */
204 	@Override
205 	public String getIdentifier() {
206 		if (this.cpuIdentifier == null) {
207 			StringBuilder sb = new StringBuilder();
208 			if (getVendor().contentEquals("GenuineIntel"))
209 				sb.append(isCpu64bit() ? "Intel64" : "x86");
210 			else
211 				sb.append(getVendor());
212 			sb.append(" Family ");
213 			sb.append(getFamily());
214 			sb.append(" Model ");
215 			sb.append(getModel());
216 			sb.append(" Stepping ");
217 			sb.append(getStepping());
218 			this.cpuIdentifier = sb.toString();
219 		}
220 		return this.cpuIdentifier;
221 	}
222 
223 	/**
224 	 * Set processor identifier.
225 	 * 
226 	 * @param identifier
227 	 *            Identifier.
228 	 */
229 	@Override
230 	public void setIdentifier(String identifier) {
231 		this.cpuIdentifier = identifier;
232 	}
233 
234 	/**
235 	 * Is CPU 64bit?
236 	 * 
237 	 * @return True if cpu is 64bit.
238 	 */
239 	@Override
240 	public boolean isCpu64bit() {
241 		return this.cpu64.booleanValue();
242 	}
243 
244 	/**
245 	 * Set flag is cpu is 64bit.
246 	 * 
247 	 * @param cpu64
248 	 *            True if cpu is 64.
249 	 */
250 	@Override
251 	public void setCpu64(boolean cpu64) {
252 		this.cpu64 = Boolean.valueOf(cpu64);
253 	}
254 
255 	/**
256 	 * @return the stepping
257 	 */
258 	@Override
259 	public String getStepping() {
260 		return this.cpuStepping;
261 	}
262 
263 	/**
264 	 * @param stepping
265 	 *            the stepping to set
266 	 */
267 	@Override
268 	public void setStepping(String stepping) {
269 		this.cpuStepping = stepping;
270 	}
271 
272 	/**
273 	 * @return the model
274 	 */
275 	@Override
276 	public String getModel() {
277 		return this.cpuModel;
278 	}
279 
280 	/**
281 	 * @param model
282 	 *            the model to set
283 	 */
284 	@Override
285 	public void setModel(String model) {
286 		this.cpuModel = model;
287 	}
288 
289 	/**
290 	 * @return the family
291 	 */
292 	@Override
293 	public String getFamily() {
294 		return this.cpuFamily;
295 	}
296 
297 	/**
298 	 * @param family
299 	 *            the family to set
300 	 */
301 	@Override
302 	public void setFamily(String family) {
303 		this.cpuFamily = family;
304 	}
305 
306 	/**
307 	 * {@inheritDoc}
308 	 */
309 	@Override
310 	@Deprecated
311 	public float getLoad() {
312 		// TODO Remove in 2.0
313 		return (float) getSystemCpuLoadBetweenTicks() * 100;
314 	}
315 
316 	/**
317 	 * {@inheritDoc}
318 	 */
319 	@Override
320 	public double getSystemCpuLoadBetweenTicks() {
321 		// Check if > ~ 0.95 seconds since last tick count.
322 		long now = System.currentTimeMillis();
323 		boolean update = (now - tickTime > 950);
324 		if (update) {
325 			// Enough time has elapsed.
326 			// Update latest
327 			updateSystemTicks();
328 			tickTime = now;
329 		}
330 		// Calculate total
331 		long total = 0;
332 		for (int i = 0; i < curTicks.length; i++) {
333 			total += (curTicks[i] - prevTicks[i]);
334 		}
335 		// Calculate idle from last field [3]
336 		long idle = curTicks[3] - prevTicks[3];
337 
338 		// Copy latest ticks to earlier position for next call
339 		if (update) {
340 			System.arraycopy(curTicks, 0, prevTicks, 0, curTicks.length);
341 		}
342 
343 		// return
344 		if (total > 0 && idle >= 0) {
345 			return (double) (total - idle) / total;
346 		}
347 		return 0d;
348 	}
349 
350 	/**
351 	 * {@inheritDoc}
352 	 */
353 	@Override
354 	public long[] getSystemCpuLoadTicks() {
355 		updateSystemTicks();
356 		// Make a copy
357 		long[] ticks = new long[curTicks.length];
358 		System.arraycopy(curTicks, 0, ticks, 0, curTicks.length);
359 		return ticks;
360 	}
361 
362 	/**
363 	 * Updates system tick information from parsing /proc/stat. Array with four
364 	 * elements representing clock ticks or milliseconds (platform dependent)
365 	 * spent in User (0), Nice (1), System (2), and Idle (3) states. By
366 	 * measuring the difference between ticks across a time interval, CPU load
367 	 * over that interval may be calculated.
368 	 * 
369 	 * @return An array of 4 long values representing time spent in User,
370 	 *         Nice(if applicable), System, and Idle states.
371 	 */
372 	private static void updateSystemTicks() {
373 		// /proc/stat expected format
374 		// first line is overall user,nice,system,idle, etc.
375 		// cpu 3357 0 4313 1362393 ...
376 		String tickStr = "";
377 		try {
378 			List<String> procStat = FileUtil.readFile("/proc/stat");
379 			if (!procStat.isEmpty())
380 				tickStr = procStat.get(0);
381 		} catch (IOException e) {
382 			System.err.println("Problem with: /proc/stat");
383 			System.err.println(e.getMessage());
384 			return;
385 		}
386 		String[] tickArr = tickStr.split("\\s+");
387 		if (tickArr.length < 5)
388 			return;
389 		for (int i = 0; i < 4; i++) {
390 			curTicks[i] = Long.parseLong(tickArr[i + 1]);
391 		}
392 	}
393 
394 	/**
395 	 * {@inheritDoc}
396 	 */
397 	@Override
398 	public double getSystemCpuLoad() {
399 		if (sunMXBean) {
400 			return ((com.sun.management.OperatingSystemMXBean) OS_MXBEAN)
401 					.getSystemCpuLoad();
402 		}
403 		return getSystemCpuLoadBetweenTicks();
404 	}
405 
406 	/**
407 	 * {@inheritDoc}
408 	 */
409 	@Override
410 	public double getSystemLoadAverage() {
411 		return OS_MXBEAN.getSystemLoadAverage();
412 	}
413 
414 	/**
415 	 * {@inheritDoc}
416 	 */
417 	@Override
418 	public double getProcessorCpuLoadBetweenTicks() {
419 		// Check if > ~ 0.95 seconds since last tick count.
420 		long now = System.currentTimeMillis();
421 		if (now - procTickTime > 950) {
422 			// Enough time has elapsed. Update array in place
423 			updateProcessorTicks();
424 			// Copy arrays in place
425 			System.arraycopy(curProcTicks, 0, prevProcTicks, 0,
426 					curProcTicks.length);
427 			System.arraycopy(allProcessorTicks[processorNumber], 0,
428 					curProcTicks, 0, curProcTicks.length);
429 			procTickTime = now;
430 		}
431 		long total = 0;
432 		for (int i = 0; i < curProcTicks.length; i++) {
433 			total += (curProcTicks[i] - prevProcTicks[i]);
434 		}
435 		// Calculate idle from last field [3]
436 		long idle = curProcTicks[3] - prevProcTicks[3];
437 		// update
438 		return (total > 0 && idle >= 0) ? (double) (total - idle) / total : 0d;
439 	}
440 
441 	/**
442 	 * {@inheritDoc}
443 	 */
444 	public long[] getProcessorCpuLoadTicks() {
445 		updateProcessorTicks();
446 		return allProcessorTicks[processorNumber];
447 	}
448 
449 	/**
450 	 * Updates the tick array for all processors if more than 100ms has elapsed
451 	 * since the last update. This permits using the allProcessorTicks as a
452 	 * cache when iterating over processors so that the /proc/stat file is only
453 	 * read once
454 	 */
455 	private static void updateProcessorTicks() {
456 		// Update no more frequently than 100ms so this is only triggered once
457 		// during iteration over Processors
458 		long now = System.currentTimeMillis();
459 		if (now - allProcTickTime < 100)
460 			return;
461 
462 		// /proc/stat expected format
463 		// first line is overall user,nice,system,idle, etc.
464 		// cpu 3357 0 4313 1362393 ...
465 		// per-processor subsequent lines for cpu0, cpu1, etc.
466 		try {
467 			int cpu = 0;
468 			List<String> procStat = FileUtil.readFile("/proc/stat");
469 			for (String stat : procStat) {
470 				if (stat.startsWith("cpu") && !stat.startsWith("cpu ")) {
471 					String[] tickArr = stat.split("\\s+");
472 					if (tickArr.length < 5)
473 						break;
474 					for (int i = 0; i < 4; i++) {
475 						allProcessorTicks[cpu][i] = Long
476 								.parseLong(tickArr[i + 1]);
477 					}
478 					if (++cpu >= numCPU)
479 						break;
480 				}
481 			}
482 		} catch (IOException e) {
483 			System.err.println("Problem with: /proc/stat");
484 			System.err.println(e.getMessage());
485 		}
486 		allProcTickTime = now;
487 	}
488 
489 	@Override
490 	public String toString() {
491 		return getName();
492 	}
493 }