View Javadoc
1   /*
2    * Copyright 2019-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.mac;
6   
7   import static oshi.util.Memoizer.defaultExpiration;
8   import static oshi.util.Memoizer.memoize;
9   
10  import java.util.function.Supplier;
11  
12  import org.slf4j.Logger;
13  import org.slf4j.LoggerFactory;
14  
15  import com.sun.jna.Native;
16  import com.sun.jna.platform.mac.SystemB;
17  
18  import oshi.annotation.concurrent.ThreadSafe;
19  import oshi.hardware.common.AbstractVirtualMemory;
20  import oshi.jna.ByRef.CloseableIntByReference;
21  import oshi.jna.Struct.CloseableVMStatistics;
22  import oshi.jna.Struct.CloseableXswUsage;
23  import oshi.util.ParseUtil;
24  import oshi.util.platform.mac.SysctlUtil;
25  import oshi.util.tuples.Pair;
26  
27  /**
28   * Memory obtained by host_statistics (vm_stat) and sysctl.
29   */
30  @ThreadSafe
31  final class MacVirtualMemory extends AbstractVirtualMemory {
32  
33      private static final Logger LOG = LoggerFactory.getLogger(MacVirtualMemory.class);
34  
35      private final MacGlobalMemory global;
36  
37      private final Supplier<Pair<Long, Long>> usedTotal = memoize(MacVirtualMemory::querySwapUsage, defaultExpiration());
38  
39      private final Supplier<Pair<Long, Long>> inOut = memoize(MacVirtualMemory::queryVmStat, defaultExpiration());
40  
41      /**
42       * Constructor for MacVirtualMemory.
43       *
44       * @param macGlobalMemory The parent global memory class instantiating this
45       */
46      MacVirtualMemory(MacGlobalMemory macGlobalMemory) {
47          this.global = macGlobalMemory;
48      }
49  
50      @Override
51      public long getSwapUsed() {
52          return usedTotal.get().getA();
53      }
54  
55      @Override
56      public long getSwapTotal() {
57          return usedTotal.get().getB();
58      }
59  
60      @Override
61      public long getVirtualMax() {
62          return this.global.getTotal() + getSwapTotal();
63      }
64  
65      @Override
66      public long getVirtualInUse() {
67          return this.global.getTotal() - this.global.getAvailable() + getSwapUsed();
68      }
69  
70      @Override
71      public long getSwapPagesIn() {
72          return inOut.get().getA();
73      }
74  
75      @Override
76      public long getSwapPagesOut() {
77          return inOut.get().getB();
78      }
79  
80      private static Pair<Long, Long> querySwapUsage() {
81          long swapUsed = 0L;
82          long swapTotal = 0L;
83          try (CloseableXswUsage xswUsage = new CloseableXswUsage()) {
84              if (SysctlUtil.sysctl("vm.swapusage", xswUsage)) {
85                  swapUsed = xswUsage.xsu_used;
86                  swapTotal = xswUsage.xsu_total;
87              }
88          }
89          return new Pair<>(swapUsed, swapTotal);
90      }
91  
92      private static Pair<Long, Long> queryVmStat() {
93          long swapPagesIn = 0L;
94          long swapPagesOut = 0L;
95          try (CloseableVMStatistics vmStats = new CloseableVMStatistics();
96                  CloseableIntByReference size = new CloseableIntByReference(vmStats.size() / SystemB.INT_SIZE)) {
97              if (0 == SystemB.INSTANCE.host_statistics(SystemB.INSTANCE.mach_host_self(), SystemB.HOST_VM_INFO, vmStats,
98                      size)) {
99                  swapPagesIn = ParseUtil.unsignedIntToLong(vmStats.pageins);
100                 swapPagesOut = ParseUtil.unsignedIntToLong(vmStats.pageouts);
101             } else {
102                 LOG.error("Failed to get host VM info. Error code: {}", Native.getLastError());
103             }
104         }
105         return new Pair<>(swapPagesIn, swapPagesOut);
106     }
107 }