View Javadoc
1   /*
2    * Copyright 2020-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.linux;
6   
7   import java.util.ArrayList;
8   import java.util.List;
9   
10  import oshi.annotation.concurrent.Immutable;
11  import oshi.hardware.GraphicsCard;
12  import oshi.hardware.common.AbstractGraphicsCard;
13  import oshi.util.Constants;
14  import oshi.util.ExecutingCommand;
15  import oshi.util.ParseUtil;
16  import oshi.util.tuples.Pair;
17  
18  /**
19   * Graphics card info obtained by lshw
20   */
21  @Immutable
22  final class LinuxGraphicsCard extends AbstractGraphicsCard {
23  
24      /**
25       * Constructor for LinuxGraphicsCard
26       *
27       * @param name        The name
28       * @param deviceId    The device ID
29       * @param vendor      The vendor
30       * @param versionInfo The version info
31       * @param vram        The VRAM
32       */
33      LinuxGraphicsCard(String name, String deviceId, String vendor, String versionInfo, long vram) {
34          super(name, deviceId, vendor, versionInfo, vram);
35      }
36  
37      /**
38       * public method used by {@link oshi.hardware.common.AbstractHardwareAbstractionLayer} to access the graphics cards.
39       *
40       * @return List of {@link oshi.hardware.platform.linux.LinuxGraphicsCard} objects.
41       */
42      public static List<GraphicsCard> getGraphicsCards() {
43          List<GraphicsCard> cardList = getGraphicsCardsFromLspci();
44          if (cardList.isEmpty()) {
45              cardList = getGraphicsCardsFromLshw();
46          }
47          return cardList;
48      }
49  
50      // Faster, use as primary
51      private static List<GraphicsCard> getGraphicsCardsFromLspci() {
52          List<GraphicsCard> cardList = new ArrayList<>();
53          // Machine readable version
54          List<String> lspci = ExecutingCommand.runNative("lspci -vnnm");
55          String name = Constants.UNKNOWN;
56          String deviceId = Constants.UNKNOWN;
57          String vendor = Constants.UNKNOWN;
58          List<String> versionInfoList = new ArrayList<>();
59          boolean found = false;
60          String lookupDevice = null;
61          for (String line : lspci) {
62              String[] split = line.trim().split(":", 2);
63              String prefix = split[0];
64              // Skip until line contains "VGA"
65              if (prefix.equals("Class") && line.contains("VGA")) {
66                  found = true;
67              } else if (prefix.equals("Device") && !found && split.length > 1) {
68                  lookupDevice = split[1].trim();
69              }
70              if (found) {
71                  if (split.length < 2) {
72                      // Save previous card
73                      cardList.add(new LinuxGraphicsCard(name, deviceId, vendor,
74                              versionInfoList.isEmpty() ? Constants.UNKNOWN : String.join(", ", versionInfoList),
75                              queryLspciMemorySize(lookupDevice)));
76                      versionInfoList.clear();
77                      found = false;
78                  } else {
79                      if (prefix.equals("Device")) {
80                          Pair<String, String> pair = ParseUtil.parseLspciMachineReadable(split[1].trim());
81                          if (pair != null) {
82                              name = pair.getA();
83                              deviceId = "0x" + pair.getB();
84                          }
85                      } else if (prefix.equals("Vendor")) {
86                          Pair<String, String> pair = ParseUtil.parseLspciMachineReadable(split[1].trim());
87                          if (pair != null) {
88                              vendor = pair.getA() + " (0x" + pair.getB() + ")";
89                          } else {
90                              vendor = split[1].trim();
91                          }
92                      } else if (prefix.equals("Rev:")) {
93                          versionInfoList.add(line.trim());
94                      }
95                  }
96              }
97          }
98          // If we haven't yet written the last card do so now
99          if (found) {
100             cardList.add(new LinuxGraphicsCard(name, deviceId, vendor,
101                     versionInfoList.isEmpty() ? Constants.UNKNOWN : String.join(", ", versionInfoList),
102                     queryLspciMemorySize(lookupDevice)));
103         }
104         return cardList;
105     }
106 
107     private static long queryLspciMemorySize(String lookupDevice) {
108         long vram = 0L;
109         // Lookup memory
110         // Human readable version, includes memory
111         List<String> lspciMem = ExecutingCommand.runNative("lspci -v -s " + lookupDevice);
112         for (String mem : lspciMem) {
113             if (mem.contains(" prefetchable")) {
114                 vram += ParseUtil.parseLspciMemorySize(mem);
115             }
116         }
117         return vram;
118     }
119 
120     // Slower, use as backup
121     private static List<GraphicsCard> getGraphicsCardsFromLshw() {
122         List<GraphicsCard> cardList = new ArrayList<>();
123         List<String> lshw = ExecutingCommand.runNative("lshw -C display");
124         String name = Constants.UNKNOWN;
125         String deviceId = Constants.UNKNOWN;
126         String vendor = Constants.UNKNOWN;
127         List<String> versionInfoList = new ArrayList<>();
128         long vram = 0;
129         int cardNum = 0;
130         for (String line : lshw) {
131             String[] split = line.trim().split(":");
132             if (split[0].startsWith("*-display")) {
133                 // Save previous card
134                 if (cardNum++ > 0) {
135                     cardList.add(new LinuxGraphicsCard(name, deviceId, vendor,
136                             versionInfoList.isEmpty() ? Constants.UNKNOWN : String.join(", ", versionInfoList), vram));
137                     versionInfoList.clear();
138                 }
139             } else if (split.length == 2) {
140                 String prefix = split[0];
141                 if (prefix.equals("product")) {
142                     name = split[1].trim();
143                 } else if (prefix.equals("vendor")) {
144                     vendor = split[1].trim();
145                 } else if (prefix.equals("version")) {
146                     versionInfoList.add(line.trim());
147                 } else if (prefix.startsWith("resources")) {
148                     vram = ParseUtil.parseLshwResourceString(split[1].trim());
149                 }
150             }
151         }
152         cardList.add(new LinuxGraphicsCard(name, deviceId, vendor,
153                 versionInfoList.isEmpty() ? Constants.UNKNOWN : String.join(", ", versionInfoList), vram));
154         return cardList;
155     }
156 }