View Javadoc
1   /*
2    * Copyright 2016-2024 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.windows;
6   
7   import static oshi.util.Memoizer.defaultExpiration;
8   import static oshi.util.Memoizer.memoize;
9   
10  import java.util.ArrayList;
11  import java.util.List;
12  import java.util.function.Supplier;
13  
14  import org.slf4j.Logger;
15  import org.slf4j.LoggerFactory;
16  
17  import com.sun.jna.platform.win32.Kernel32;
18  import com.sun.jna.platform.win32.Psapi;
19  import com.sun.jna.platform.win32.VersionHelpers;
20  import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult;
21  
22  import oshi.annotation.concurrent.ThreadSafe;
23  import oshi.driver.windows.wmi.Win32PhysicalMemory;
24  import oshi.driver.windows.wmi.Win32PhysicalMemory.PhysicalMemoryProperty;
25  import oshi.driver.windows.wmi.Win32PhysicalMemory.PhysicalMemoryPropertyWin8;
26  import oshi.hardware.PhysicalMemory;
27  import oshi.hardware.VirtualMemory;
28  import oshi.hardware.common.AbstractGlobalMemory;
29  import oshi.jna.Struct.CloseablePerformanceInformation;
30  import oshi.util.platform.windows.WmiUtil;
31  import oshi.util.tuples.Triplet;
32  
33  /**
34   * Memory obtained by Performance Info.
35   */
36  @ThreadSafe
37  final class WindowsGlobalMemory extends AbstractGlobalMemory {
38  
39      private static final Logger LOG = LoggerFactory.getLogger(WindowsGlobalMemory.class);
40  
41      private static final boolean IS_WINDOWS10_OR_GREATER = VersionHelpers.IsWindows10OrGreater();
42  
43      private final Supplier<Triplet<Long, Long, Long>> availTotalSize = memoize(WindowsGlobalMemory::readPerfInfo,
44              defaultExpiration());
45  
46      private final Supplier<VirtualMemory> vm = memoize(this::createVirtualMemory);
47  
48      @Override
49      public long getAvailable() {
50          return availTotalSize.get().getA();
51      }
52  
53      @Override
54      public long getTotal() {
55          return availTotalSize.get().getB();
56      }
57  
58      @Override
59      public long getPageSize() {
60          return availTotalSize.get().getC();
61      }
62  
63      @Override
64      public VirtualMemory getVirtualMemory() {
65          return vm.get();
66      }
67  
68      private VirtualMemory createVirtualMemory() {
69          return new WindowsVirtualMemory(this);
70      }
71  
72      @Override
73      public List<PhysicalMemory> getPhysicalMemory() {
74          List<PhysicalMemory> physicalMemoryList = new ArrayList<>();
75          if (IS_WINDOWS10_OR_GREATER) {
76              WmiResult<PhysicalMemoryProperty> bankMap = Win32PhysicalMemory.queryphysicalMemory();
77              for (int index = 0; index < bankMap.getResultCount(); index++) {
78                  String bankLabel = WmiUtil.getString(bankMap, PhysicalMemoryProperty.BANKLABEL, index);
79                  long capacity = WmiUtil.getUint64(bankMap, PhysicalMemoryProperty.CAPACITY, index);
80                  long speed = WmiUtil.getUint32(bankMap, PhysicalMemoryProperty.SPEED, index) * 1_000_000L;
81                  String manufacturer = WmiUtil.getString(bankMap, PhysicalMemoryProperty.MANUFACTURER, index);
82                  String memoryType = smBiosMemoryType(
83                          WmiUtil.getUint32(bankMap, PhysicalMemoryProperty.SMBIOSMEMORYTYPE, index));
84                  String partNumber = WmiUtil.getString(bankMap, PhysicalMemoryProperty.PARTNUMBER, index);
85                  String serialNumber = WmiUtil.getString(bankMap, PhysicalMemoryProperty.SERIALNUMBER, index);
86                  physicalMemoryList.add(new PhysicalMemory(bankLabel, capacity, speed, manufacturer, memoryType,
87                          partNumber, serialNumber));
88              }
89          } else {
90              WmiResult<PhysicalMemoryPropertyWin8> bankMap = Win32PhysicalMemory.queryphysicalMemoryWin8();
91              for (int index = 0; index < bankMap.getResultCount(); index++) {
92                  String bankLabel = WmiUtil.getString(bankMap, PhysicalMemoryPropertyWin8.BANKLABEL, index);
93                  long capacity = WmiUtil.getUint64(bankMap, PhysicalMemoryPropertyWin8.CAPACITY, index);
94                  long speed = WmiUtil.getUint32(bankMap, PhysicalMemoryPropertyWin8.SPEED, index) * 1_000_000L;
95                  String manufacturer = WmiUtil.getString(bankMap, PhysicalMemoryPropertyWin8.MANUFACTURER, index);
96                  String memoryType = memoryType(
97                          WmiUtil.getUint16(bankMap, PhysicalMemoryPropertyWin8.MEMORYTYPE, index));
98                  String partNumber = WmiUtil.getString(bankMap, PhysicalMemoryPropertyWin8.PARTNUMBER, index);
99                  String serialNumber = WmiUtil.getString(bankMap, PhysicalMemoryPropertyWin8.SERIALNUMBER, index);
100                 physicalMemoryList.add(new PhysicalMemory(bankLabel, capacity, speed, manufacturer, memoryType,
101                         partNumber, serialNumber));
102             }
103         }
104         return physicalMemoryList;
105     }
106 
107     /**
108      * Convert memory type number to a human readable string
109      *
110      * @param type The memory type
111      * @return A string describing the type
112      */
113     private static String memoryType(int type) {
114         // https://schemas.dmtf.org/wbem/cim-html/2.55.0/CIM_PhysicalMemory.html
115         switch (type) {
116         case 0:
117             return "Unknown";
118         case 1:
119             return "Other";
120         case 2:
121             return "DRAM";
122         case 3:
123             return "Synchronous DRAM";
124         case 4:
125             return "Cache DRAM";
126         case 5:
127             return "EDO";
128         case 6:
129             return "EDRAM";
130         case 7:
131             return "VRAM";
132         case 8:
133             return "SRAM";
134         case 9:
135             return "RAM";
136         case 10:
137             return "ROM";
138         case 11:
139             return "Flash";
140         case 12:
141             return "EEPROM";
142         case 13:
143             return "FEPROM";
144         case 14:
145             return "EPROM";
146         case 15:
147             return "CDRAM";
148         case 16:
149             return "3DRAM";
150         case 17:
151             return "SDRAM";
152         case 18:
153             return "SGRAM";
154         case 19:
155             return "RDRAM";
156         case 20:
157             return "DDR";
158         case 21:
159             return "DDR2";
160         case 22:
161             return "BRAM";
162         case 23:
163             return "DDR FB-DIMM";
164         default:
165             // values 24 and higher match SMBIOS types
166             return smBiosMemoryType(type);
167         }
168     }
169 
170     /**
171      * Convert SMBIOS type number to a human readable string
172      *
173      * @param type The SMBIOS type
174      * @return A string describing the type
175      */
176     private static String smBiosMemoryType(int type) {
177         // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf
178         // table 77
179         switch (type) {
180         case 0x01:
181             return "Other";
182         case 0x03:
183             return "DRAM";
184         case 0x04:
185             return "EDRAM";
186         case 0x05:
187             return "VRAM";
188         case 0x06:
189             return "SRAM";
190         case 0x07:
191             return "RAM";
192         case 0x08:
193             return "ROM";
194         case 0x09:
195             return "FLASH";
196         case 0x0A:
197             return "EEPROM";
198         case 0x0B:
199             return "FEPROM";
200         case 0x0C:
201             return "EPROM";
202         case 0x0D:
203             return "CDRAM";
204         case 0x0E:
205             return "3DRAM";
206         case 0x0F:
207             return "SDRAM";
208         case 0x10:
209             return "SGRAM";
210         case 0x11:
211             return "RDRAM";
212         case 0x12:
213             return "DDR";
214         case 0x13:
215             return "DDR2";
216         case 0x14:
217             return "DDR2 FB-DIMM";
218         case 0x18:
219             return "DDR3";
220         case 0x19:
221             return "FBD2";
222         case 0x1A:
223             return "DDR4";
224         case 0x1B:
225             return "LPDDR";
226         case 0x1C:
227             return "LPDDR2";
228         case 0x1D:
229             return "LPDDR3";
230         case 0x1E:
231             return "LPDDR4";
232         case 0x1F:
233             return "Logical non-volatile device";
234         case 0x20:
235             return "HBM";
236         case 0x21:
237             return "HBM2";
238         case 0x22:
239             return "DDR5";
240         case 0x23:
241             return "LPDDR5";
242         case 0x24:
243             return "HBM3";
244         case 0x02:
245         default:
246             return "Unknown";
247         }
248     }
249 
250     private static Triplet<Long, Long, Long> readPerfInfo() {
251         try (CloseablePerformanceInformation performanceInfo = new CloseablePerformanceInformation()) {
252             if (!Psapi.INSTANCE.GetPerformanceInfo(performanceInfo, performanceInfo.size())) {
253                 LOG.error("Failed to get Performance Info. Error code: {}", Kernel32.INSTANCE.GetLastError());
254                 return new Triplet<>(0L, 0L, 4098L);
255             }
256             long pageSize = performanceInfo.PageSize.longValue();
257             long memAvailable = pageSize * performanceInfo.PhysicalAvailable.longValue();
258             long memTotal = pageSize * performanceInfo.PhysicalTotal.longValue();
259             return new Triplet<>(memAvailable, memTotal, pageSize);
260         }
261     }
262 }