1
2
3
4
5 package oshi.driver.windows.perfmon;
6
7 import java.util.Arrays;
8 import java.util.List;
9 import java.util.Map;
10
11 import oshi.annotation.concurrent.ThreadSafe;
12 import oshi.driver.windows.perfmon.ProcessInformation.IdleProcessorTimeProperty;
13 import oshi.driver.windows.perfmon.SystemInformation.ProcessorQueueLengthProperty;
14 import oshi.util.tuples.Pair;
15
16
17
18
19
20 @ThreadSafe
21 public final class LoadAverage {
22
23
24 private static Thread loadAvgThread = null;
25
26 private static double[] loadAverages = new double[] { -1d, -1d, -1d };
27 private static final double[] EXP_WEIGHT = new double[] {
28
29 Math.exp(-5d / 60d), Math.exp(-5d / 300d), Math.exp(-5d / 900d) };
30
31 private LoadAverage() {
32 }
33
34 public static double[] queryLoadAverage(int nelem) {
35 synchronized (loadAverages) {
36 return Arrays.copyOf(loadAverages, nelem);
37 }
38 }
39
40 public static synchronized void stopDaemon() {
41 if (loadAvgThread != null) {
42 loadAvgThread.interrupt();
43 loadAvgThread = null;
44 }
45 }
46
47 public static synchronized void startDaemon() {
48 if (loadAvgThread != null) {
49 return;
50 }
51 loadAvgThread = new Thread("OSHI Load Average daemon") {
52 @Override
53 public void run() {
54
55 Pair<Long, Long> nonIdlePair = LoadAverage.queryNonIdleTicks();
56 long nonIdleTicks0 = nonIdlePair.getA();
57 long nonIdleBase0 = nonIdlePair.getB();
58 long nonIdleTicks;
59 long nonIdleBase;
60
61
62 long initNanos = System.nanoTime();
63 long delay;
64
65
66 double runningProcesses;
67 long queueLength;
68
69 try {
70 Thread.sleep(2500L);
71 } catch (InterruptedException e) {
72 Thread.currentThread().interrupt();
73 }
74 while (!Thread.currentThread().isInterrupted()) {
75
76 nonIdlePair = LoadAverage.queryNonIdleTicks();
77 nonIdleTicks = nonIdlePair.getA() - nonIdleTicks0;
78 nonIdleBase = nonIdlePair.getB() - nonIdleBase0;
79 if (nonIdleBase > 0 && nonIdleTicks > 0) {
80 runningProcesses = (double) nonIdleTicks / nonIdleBase;
81 } else {
82 runningProcesses = 0d;
83 }
84 nonIdleTicks0 = nonIdlePair.getA();
85 nonIdleBase0 = nonIdlePair.getB();
86
87 queueLength = SystemInformation.queryProcessorQueueLength()
88 .getOrDefault(ProcessorQueueLengthProperty.PROCESSORQUEUELENGTH, 0L);
89
90 synchronized (loadAverages) {
91
92 if (loadAverages[0] < 0d) {
93 Arrays.fill(loadAverages, runningProcesses);
94 }
95
96 for (int i = 0; i < loadAverages.length; i++) {
97 loadAverages[i] *= EXP_WEIGHT[i];
98 loadAverages[i] += (runningProcesses + queueLength) * (1d - EXP_WEIGHT[i]);
99 }
100 }
101
102 delay = 5000L - (System.nanoTime() - initNanos) % 5_000_000_000L / 1_000_000;
103 if (delay < 500L) {
104 delay += 5000L;
105 }
106 try {
107 Thread.sleep(delay);
108 } catch (InterruptedException e) {
109 Thread.currentThread().interrupt();
110 }
111 }
112 }
113 };
114 loadAvgThread.setDaemon(true);
115 loadAvgThread.start();
116 }
117
118 private static Pair<Long, Long> queryNonIdleTicks() {
119 Pair<List<String>, Map<IdleProcessorTimeProperty, List<Long>>> idleValues = ProcessInformation
120 .queryIdleProcessCounters();
121 List<String> instances = idleValues.getA();
122 Map<IdleProcessorTimeProperty, List<Long>> valueMap = idleValues.getB();
123 List<Long> proctimeTicks = valueMap.get(IdleProcessorTimeProperty.PERCENTPROCESSORTIME);
124 List<Long> proctimeBase = valueMap.get(IdleProcessorTimeProperty.ELAPSEDTIME);
125 long nonIdleTicks = 0L;
126 long nonIdleBase = 0L;
127 for (int i = 0; i < instances.size(); i++) {
128 if ("_Total".equals(instances.get(i))) {
129 nonIdleTicks += proctimeTicks.get(i);
130 nonIdleBase += proctimeBase.get(i);
131 } else if ("Idle".equals(instances.get(i))) {
132 nonIdleTicks -= proctimeTicks.get(i);
133 }
134 }
135 return new Pair<>(nonIdleTicks, nonIdleBase);
136 }
137 }