1
2
3
4
5 package oshi.util.platform.windows;
6
7 import java.util.Locale;
8
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11
12 import com.sun.jna.platform.win32.BaseTSD.DWORD_PTR;
13 import com.sun.jna.platform.win32.Pdh;
14 import com.sun.jna.platform.win32.PdhMsg;
15 import com.sun.jna.platform.win32.VersionHelpers;
16 import com.sun.jna.platform.win32.WinDef.DWORD;
17 import com.sun.jna.platform.win32.WinDef.DWORDByReference;
18 import com.sun.jna.platform.win32.WinError;
19 import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
20
21 import oshi.annotation.concurrent.Immutable;
22 import oshi.annotation.concurrent.ThreadSafe;
23 import oshi.jna.ByRef.CloseableLONGLONGByReference;
24 import oshi.jna.Struct.CloseablePdhRawCounter;
25 import oshi.util.FormatUtil;
26 import oshi.util.ParseUtil;
27 import oshi.util.Util;
28
29
30
31
32
33 @ThreadSafe
34 public final class PerfDataUtil {
35
36 private static final Logger LOG = LoggerFactory.getLogger(PerfDataUtil.class);
37
38 private static final DWORD_PTR PZERO = new DWORD_PTR(0);
39 private static final DWORDByReference PDH_FMT_RAW = new DWORDByReference(new DWORD(Pdh.PDH_FMT_RAW));
40 private static final Pdh PDH = Pdh.INSTANCE;
41
42 private static final boolean IS_VISTA_OR_GREATER = VersionHelpers.IsWindowsVistaOrGreater();
43
44
45
46
47 @Immutable
48 public static class PerfCounter {
49 private final String object;
50 private final String instance;
51 private final String counter;
52 private final boolean baseCounter;
53
54 public PerfCounter(String objectName, String instanceName, String counterName) {
55 this.object = objectName;
56 this.instance = instanceName;
57 int baseIdx = counterName.indexOf("_Base");
58 if (baseIdx > 0) {
59 this.counter = counterName.substring(0, baseIdx);
60 this.baseCounter = true;
61 } else {
62 this.counter = counterName;
63 this.baseCounter = false;
64 }
65 }
66
67
68
69
70 public String getObject() {
71 return object;
72 }
73
74
75
76
77 public String getInstance() {
78 return instance;
79 }
80
81
82
83
84 public String getCounter() {
85 return counter;
86 }
87
88
89
90
91 public boolean isBaseCounter() {
92 return baseCounter;
93 }
94
95
96
97
98
99
100 public String getCounterPath() {
101 StringBuilder sb = new StringBuilder();
102 sb.append('\\').append(object);
103 if (instance != null) {
104 sb.append('(').append(instance).append(')');
105 }
106 sb.append('\\').append(counter);
107 return sb.toString();
108 }
109 }
110
111 private PerfDataUtil() {
112 }
113
114
115
116
117
118
119
120
121
122 public static PerfCounter createCounter(String object, String instance, String counter) {
123 return new PerfCounter(object, instance, counter);
124 }
125
126
127
128
129
130
131
132 public static long updateQueryTimestamp(HANDLEByReference query) {
133 try (CloseableLONGLONGByReference pllTimeStamp = new CloseableLONGLONGByReference()) {
134 int ret = IS_VISTA_OR_GREATER ? PDH.PdhCollectQueryDataWithTime(query.getValue(), pllTimeStamp)
135 : PDH.PdhCollectQueryData(query.getValue());
136
137 int retries = 0;
138 while (ret == PdhMsg.PDH_NO_DATA && retries++ < 3) {
139
140 Util.sleep(1 << retries);
141 ret = IS_VISTA_OR_GREATER ? PDH.PdhCollectQueryDataWithTime(query.getValue(), pllTimeStamp)
142 : PDH.PdhCollectQueryData(query.getValue());
143 }
144 if (ret != WinError.ERROR_SUCCESS) {
145 if (LOG.isWarnEnabled()) {
146 LOG.warn("Failed to update counter. Error code: {}",
147 String.format(Locale.ROOT, FormatUtil.formatError(ret)));
148 }
149 return 0L;
150 }
151
152 return IS_VISTA_OR_GREATER ? ParseUtil.filetimeToUtcMs(pllTimeStamp.getValue().longValue(), true)
153 : System.currentTimeMillis();
154 }
155 }
156
157
158
159
160
161
162
163 public static boolean openQuery(HANDLEByReference q) {
164 int ret = PDH.PdhOpenQuery(null, PZERO, q);
165 if (ret != WinError.ERROR_SUCCESS) {
166 if (LOG.isErrorEnabled()) {
167 LOG.error("Failed to open PDH Query. Error code: {}",
168 String.format(Locale.ROOT, FormatUtil.formatError(ret)));
169 }
170 return false;
171 }
172 return true;
173 }
174
175
176
177
178
179
180
181 public static boolean closeQuery(HANDLEByReference q) {
182 return WinError.ERROR_SUCCESS == PDH.PdhCloseQuery(q.getValue());
183 }
184
185
186
187
188
189
190
191 public static long queryCounter(HANDLEByReference counter) {
192 try (CloseablePdhRawCounter counterValue = new CloseablePdhRawCounter()) {
193 int ret = PDH.PdhGetRawCounterValue(counter.getValue(), PDH_FMT_RAW, counterValue);
194 if (ret != WinError.ERROR_SUCCESS) {
195 if (LOG.isWarnEnabled()) {
196 LOG.warn("Failed to get counter. Error code: {}",
197 String.format(Locale.ROOT, FormatUtil.formatError(ret)));
198 }
199 return ret;
200 }
201 return counterValue.FirstValue;
202 }
203 }
204
205
206
207
208
209
210
211 public static long querySecondCounter(HANDLEByReference counter) {
212 try (CloseablePdhRawCounter counterValue = new CloseablePdhRawCounter()) {
213 int ret = PDH.PdhGetRawCounterValue(counter.getValue(), PDH_FMT_RAW, counterValue);
214 if (ret != WinError.ERROR_SUCCESS) {
215 if (LOG.isWarnEnabled()) {
216 LOG.warn("Failed to get counter. Error code: {}",
217 String.format(Locale.ROOT, FormatUtil.formatError(ret)));
218 }
219 return ret;
220 }
221 return counterValue.SecondValue;
222 }
223 }
224
225
226
227
228
229
230
231
232
233
234 public static boolean addCounter(HANDLEByReference query, String path, HANDLEByReference p) {
235 int ret = IS_VISTA_OR_GREATER ? PDH.PdhAddEnglishCounter(query.getValue(), path, PZERO, p)
236 : PDH.PdhAddCounter(query.getValue(), path, PZERO, p);
237 if (ret != WinError.ERROR_SUCCESS) {
238 if (LOG.isWarnEnabled()) {
239 LOG.warn("Failed to add PDH Counter: {}, Error code: {}", path,
240 String.format(Locale.ROOT, FormatUtil.formatError(ret)));
241 }
242 return false;
243 }
244 return true;
245 }
246
247
248
249
250
251
252
253 public static boolean removeCounter(HANDLEByReference p) {
254 return WinError.ERROR_SUCCESS == PDH.PdhRemoveCounter(p.getValue());
255 }
256 }