View Javadoc
1   /*
2    * Copyright 2019-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.linux;
6   
7   import static oshi.util.Memoizer.defaultExpiration;
8   import static oshi.util.Memoizer.memoize;
9   
10  import java.util.List;
11  import java.util.function.Supplier;
12  
13  import oshi.annotation.concurrent.ThreadSafe;
14  import oshi.hardware.common.AbstractVirtualMemory;
15  import oshi.util.FileUtil;
16  import oshi.util.ParseUtil;
17  import oshi.util.platform.linux.ProcPath;
18  import oshi.util.tuples.Pair;
19  import oshi.util.tuples.Triplet;
20  
21  /**
22   * Memory obtained by /proc/meminfo and /proc/vmstat
23   */
24  @ThreadSafe
25  final class LinuxVirtualMemory extends AbstractVirtualMemory {
26  
27      private final LinuxGlobalMemory global;
28  
29      private final Supplier<Triplet<Long, Long, Long>> usedTotalCommitLim = memoize(LinuxVirtualMemory::queryMemInfo,
30              defaultExpiration());
31  
32      private final Supplier<Pair<Long, Long>> inOut = memoize(LinuxVirtualMemory::queryVmStat, defaultExpiration());
33  
34      /**
35       * Constructor for LinuxVirtualMemory.
36       *
37       * @param linuxGlobalMemory The parent global memory class instantiating this
38       */
39      LinuxVirtualMemory(LinuxGlobalMemory linuxGlobalMemory) {
40          this.global = linuxGlobalMemory;
41      }
42  
43      @Override
44      public long getSwapUsed() {
45          return usedTotalCommitLim.get().getA();
46      }
47  
48      @Override
49      public long getSwapTotal() {
50          return usedTotalCommitLim.get().getB();
51      }
52  
53      @Override
54      public long getVirtualMax() {
55          return usedTotalCommitLim.get().getC();
56      }
57  
58      @Override
59      public long getVirtualInUse() {
60          return this.global.getTotal() - this.global.getAvailable() + getSwapUsed();
61      }
62  
63      @Override
64      public long getSwapPagesIn() {
65          return inOut.get().getA();
66      }
67  
68      @Override
69      public long getSwapPagesOut() {
70          return inOut.get().getB();
71      }
72  
73      private static Triplet<Long, Long, Long> queryMemInfo() {
74          long swapFree = 0L;
75          long swapTotal = 0L;
76          long commitLimit = 0L;
77  
78          List<String> procMemInfo = FileUtil.readFile(ProcPath.MEMINFO);
79          for (String checkLine : procMemInfo) {
80              String[] memorySplit = ParseUtil.whitespaces.split(checkLine);
81              if (memorySplit.length > 1) {
82                  switch (memorySplit[0]) {
83                  case "SwapTotal:":
84                      swapTotal = parseMeminfo(memorySplit);
85                      break;
86                  case "SwapFree:":
87                      swapFree = parseMeminfo(memorySplit);
88                      break;
89                  case "CommitLimit:":
90                      commitLimit = parseMeminfo(memorySplit);
91                      break;
92                  default:
93                      // do nothing with other lines
94                      break;
95                  }
96              }
97          }
98          return new Triplet<>(swapTotal - swapFree, swapTotal, commitLimit);
99      }
100 
101     private static Pair<Long, Long> queryVmStat() {
102         long swapPagesIn = 0L;
103         long swapPagesOut = 0L;
104         List<String> procVmStat = FileUtil.readFile(ProcPath.VMSTAT);
105         for (String checkLine : procVmStat) {
106             String[] memorySplit = ParseUtil.whitespaces.split(checkLine);
107             if (memorySplit.length > 1) {
108                 switch (memorySplit[0]) {
109                 case "pswpin":
110                     swapPagesIn = ParseUtil.parseLongOrDefault(memorySplit[1], 0L);
111                     break;
112                 case "pswpout":
113                     swapPagesOut = ParseUtil.parseLongOrDefault(memorySplit[1], 0L);
114                     break;
115                 default:
116                     // do nothing with other lines
117                     break;
118                 }
119             }
120         }
121         return new Pair<>(swapPagesIn, swapPagesOut);
122     }
123 
124     /**
125      * Parses lines from the display of /proc/meminfo
126      *
127      * @param memorySplit Array of Strings representing the 3 columns of /proc/meminfo
128      * @return value, multiplied by 1024 if kB is specified
129      */
130     private static long parseMeminfo(String[] memorySplit) {
131         if (memorySplit.length < 2) {
132             return 0L;
133         }
134         long memory = ParseUtil.parseLongOrDefault(memorySplit[1], 0L);
135         if (memorySplit.length > 2 && "kB".equals(memorySplit[2])) {
136             memory *= 1024;
137         }
138         return memory;
139     }
140 }