1 /*
2 * Copyright 2020-2022 The OSHI Project Contributors
3 * SPDX-License-Identifier: MIT
4 */
5 package oshi.driver.linux.proc;
6
7 import java.util.EnumMap;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11
12 import oshi.annotation.concurrent.ThreadSafe;
13 import oshi.util.FileUtil;
14 import oshi.util.ParseUtil;
15 import oshi.util.platform.linux.ProcPath;
16
17 /**
18 * Utility to read disk statistics from {@code /proc/diskstats}
19 */
20 @ThreadSafe
21 public final class DiskStats {
22
23 /**
24 * Enum corresponding to the fields in the output of {@code /proc/diskstats}
25 */
26 public enum IoStat {
27 /**
28 * The device major number.
29 */
30 MAJOR,
31 /**
32 * The device minor number.
33 */
34 MINOR,
35 /**
36 * The device name.
37 */
38 NAME,
39 /**
40 * The total number of reads completed successfully.
41 */
42 READS,
43 /**
44 * Reads which are adjacent to each other merged for efficiency.
45 */
46 READS_MERGED,
47 /**
48 * The total number of sectors read successfully.
49 */
50 READS_SECTOR,
51 /**
52 * The total number of milliseconds spent by all reads.
53 */
54 READS_MS,
55 /**
56 * The total number of writes completed successfully.
57 */
58 WRITES,
59 /**
60 * Writes which are adjacent to each other merged for efficiency.
61 */
62 WRITES_MERGED,
63 /**
64 * The total number of sectors written successfully.
65 */
66 WRITES_SECTOR,
67 /**
68 * The total number of milliseconds spent by all writes.
69 */
70 WRITES_MS,
71 /**
72 * Incremented as requests are given to appropriate struct request_queue and decremented as they finish.
73 */
74 IO_QUEUE_LENGTH,
75 /**
76 * The total number of milliseconds spent doing I/Os.
77 */
78 IO_MS,
79 /**
80 * Incremented at each I/O start, I/O completion, I/O merge, or read of these stats by the number of I/Os in
81 * progress {@link #IO_QUEUE_LENGTH} times the number of milliseconds spent doing I/O since the last update of
82 * this field.
83 */
84 IO_MS_WEIGHTED,
85 /**
86 * The total number of discards completed successfully.
87 */
88 DISCARDS,
89 /**
90 * Discards which are adjacent to each other merged for efficiency.
91 */
92 DISCARDS_MERGED,
93 /**
94 * The total number of sectors discarded successfully.
95 */
96 DISCARDS_SECTOR,
97 /**
98 * The total number of milliseconds spent by all discards.
99 */
100 DISCARDS_MS,
101 /**
102 * The total number of flush requests completed successfully.
103 */
104 FLUSHES,
105 /**
106 * The total number of milliseconds spent by all flush requests.
107 */
108 FLUSHES_MS;
109 }
110
111 private DiskStats() {
112 }
113
114 /**
115 * Reads the statistics in {@code /proc/diskstats} and returns the results.
116 *
117 * @return A map with each disk's name as the key, and an EnumMap as the value, where the numeric values in
118 * {@link IoStat} are mapped to a {@link Long} value.
119 */
120 public static Map<String, Map<IoStat, Long>> getDiskStats() {
121 Map<String, Map<IoStat, Long>> diskStatMap = new HashMap<>();
122 IoStat[] enumArray = IoStat.class.getEnumConstants();
123 List<String> diskStats = FileUtil.readFile(ProcPath.DISKSTATS);
124 for (String stat : diskStats) {
125 String[] split = ParseUtil.whitespaces.split(stat.trim());
126 Map<IoStat, Long> statMap = new EnumMap<>(IoStat.class);
127 String name = null;
128 for (int i = 0; i < enumArray.length && i < split.length; i++) {
129 if (enumArray[i] == IoStat.NAME) {
130 name = split[i];
131 } else {
132 statMap.put(enumArray[i], ParseUtil.parseLongOrDefault(split[i], 0L));
133 }
134 }
135 if (name != null) {
136 diskStatMap.put(name, statMap);
137 }
138 }
139 return diskStatMap;
140 }
141 }