parse.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. // Copyright 2017 The Prometheus Authors
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. // you may not use this file except in compliance with the License.
  4. // You may obtain a copy of the License at
  5. //
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package xfs
  14. import (
  15. "bufio"
  16. "fmt"
  17. "io"
  18. "strings"
  19. "github.com/prometheus/procfs/internal/util"
  20. )
  21. // ParseStats parses a Stats from an input io.Reader, using the format
  22. // found in /proc/fs/xfs/stat.
  23. func ParseStats(r io.Reader) (*Stats, error) {
  24. const (
  25. // Fields parsed into stats structures.
  26. fieldExtentAlloc = "extent_alloc"
  27. fieldAbt = "abt"
  28. fieldBlkMap = "blk_map"
  29. fieldBmbt = "bmbt"
  30. fieldDir = "dir"
  31. fieldTrans = "trans"
  32. fieldIg = "ig"
  33. fieldLog = "log"
  34. fieldRw = "rw"
  35. fieldAttr = "attr"
  36. fieldIcluster = "icluster"
  37. fieldVnodes = "vnodes"
  38. fieldBuf = "buf"
  39. fieldXpc = "xpc"
  40. // Unimplemented at this time due to lack of documentation.
  41. fieldPushAil = "push_ail"
  42. fieldXstrat = "xstrat"
  43. fieldAbtb2 = "abtb2"
  44. fieldAbtc2 = "abtc2"
  45. fieldBmbt2 = "bmbt2"
  46. fieldIbt2 = "ibt2"
  47. fieldFibt2 = "fibt2"
  48. fieldQm = "qm"
  49. fieldDebug = "debug"
  50. )
  51. var xfss Stats
  52. s := bufio.NewScanner(r)
  53. for s.Scan() {
  54. // Expect at least a string label and a single integer value, ex:
  55. // - abt 0
  56. // - rw 1 2
  57. ss := strings.Fields(string(s.Bytes()))
  58. if len(ss) < 2 {
  59. continue
  60. }
  61. label := ss[0]
  62. // Extended precision counters are uint64 values.
  63. if label == fieldXpc {
  64. us, err := util.ParseUint64s(ss[1:])
  65. if err != nil {
  66. return nil, err
  67. }
  68. xfss.ExtendedPrecision, err = extendedPrecisionStats(us)
  69. if err != nil {
  70. return nil, err
  71. }
  72. continue
  73. }
  74. // All other counters are uint32 values.
  75. us, err := util.ParseUint32s(ss[1:])
  76. if err != nil {
  77. return nil, err
  78. }
  79. switch label {
  80. case fieldExtentAlloc:
  81. xfss.ExtentAllocation, err = extentAllocationStats(us)
  82. case fieldAbt:
  83. xfss.AllocationBTree, err = btreeStats(us)
  84. case fieldBlkMap:
  85. xfss.BlockMapping, err = blockMappingStats(us)
  86. case fieldBmbt:
  87. xfss.BlockMapBTree, err = btreeStats(us)
  88. case fieldDir:
  89. xfss.DirectoryOperation, err = directoryOperationStats(us)
  90. case fieldTrans:
  91. xfss.Transaction, err = transactionStats(us)
  92. case fieldIg:
  93. xfss.InodeOperation, err = inodeOperationStats(us)
  94. case fieldLog:
  95. xfss.LogOperation, err = logOperationStats(us)
  96. case fieldRw:
  97. xfss.ReadWrite, err = readWriteStats(us)
  98. case fieldAttr:
  99. xfss.AttributeOperation, err = attributeOperationStats(us)
  100. case fieldIcluster:
  101. xfss.InodeClustering, err = inodeClusteringStats(us)
  102. case fieldVnodes:
  103. xfss.Vnode, err = vnodeStats(us)
  104. case fieldBuf:
  105. xfss.Buffer, err = bufferStats(us)
  106. }
  107. if err != nil {
  108. return nil, err
  109. }
  110. }
  111. return &xfss, s.Err()
  112. }
  113. // extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s.
  114. func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) {
  115. if l := len(us); l != 4 {
  116. return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l)
  117. }
  118. return ExtentAllocationStats{
  119. ExtentsAllocated: us[0],
  120. BlocksAllocated: us[1],
  121. ExtentsFreed: us[2],
  122. BlocksFreed: us[3],
  123. }, nil
  124. }
  125. // btreeStats builds a BTreeStats from a slice of uint32s.
  126. func btreeStats(us []uint32) (BTreeStats, error) {
  127. if l := len(us); l != 4 {
  128. return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l)
  129. }
  130. return BTreeStats{
  131. Lookups: us[0],
  132. Compares: us[1],
  133. RecordsInserted: us[2],
  134. RecordsDeleted: us[3],
  135. }, nil
  136. }
  137. // BlockMappingStat builds a BlockMappingStats from a slice of uint32s.
  138. func blockMappingStats(us []uint32) (BlockMappingStats, error) {
  139. if l := len(us); l != 7 {
  140. return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l)
  141. }
  142. return BlockMappingStats{
  143. Reads: us[0],
  144. Writes: us[1],
  145. Unmaps: us[2],
  146. ExtentListInsertions: us[3],
  147. ExtentListDeletions: us[4],
  148. ExtentListLookups: us[5],
  149. ExtentListCompares: us[6],
  150. }, nil
  151. }
  152. // DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s.
  153. func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) {
  154. if l := len(us); l != 4 {
  155. return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l)
  156. }
  157. return DirectoryOperationStats{
  158. Lookups: us[0],
  159. Creates: us[1],
  160. Removes: us[2],
  161. Getdents: us[3],
  162. }, nil
  163. }
  164. // TransactionStats builds a TransactionStats from a slice of uint32s.
  165. func transactionStats(us []uint32) (TransactionStats, error) {
  166. if l := len(us); l != 3 {
  167. return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l)
  168. }
  169. return TransactionStats{
  170. Sync: us[0],
  171. Async: us[1],
  172. Empty: us[2],
  173. }, nil
  174. }
  175. // InodeOperationStats builds an InodeOperationStats from a slice of uint32s.
  176. func inodeOperationStats(us []uint32) (InodeOperationStats, error) {
  177. if l := len(us); l != 7 {
  178. return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l)
  179. }
  180. return InodeOperationStats{
  181. Attempts: us[0],
  182. Found: us[1],
  183. Recycle: us[2],
  184. Missed: us[3],
  185. Duplicate: us[4],
  186. Reclaims: us[5],
  187. AttributeChange: us[6],
  188. }, nil
  189. }
  190. // LogOperationStats builds a LogOperationStats from a slice of uint32s.
  191. func logOperationStats(us []uint32) (LogOperationStats, error) {
  192. if l := len(us); l != 5 {
  193. return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l)
  194. }
  195. return LogOperationStats{
  196. Writes: us[0],
  197. Blocks: us[1],
  198. NoInternalBuffers: us[2],
  199. Force: us[3],
  200. ForceSleep: us[4],
  201. }, nil
  202. }
  203. // ReadWriteStats builds a ReadWriteStats from a slice of uint32s.
  204. func readWriteStats(us []uint32) (ReadWriteStats, error) {
  205. if l := len(us); l != 2 {
  206. return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l)
  207. }
  208. return ReadWriteStats{
  209. Read: us[0],
  210. Write: us[1],
  211. }, nil
  212. }
  213. // AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s.
  214. func attributeOperationStats(us []uint32) (AttributeOperationStats, error) {
  215. if l := len(us); l != 4 {
  216. return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l)
  217. }
  218. return AttributeOperationStats{
  219. Get: us[0],
  220. Set: us[1],
  221. Remove: us[2],
  222. List: us[3],
  223. }, nil
  224. }
  225. // InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s.
  226. func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) {
  227. if l := len(us); l != 3 {
  228. return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l)
  229. }
  230. return InodeClusteringStats{
  231. Iflush: us[0],
  232. Flush: us[1],
  233. FlushInode: us[2],
  234. }, nil
  235. }
  236. // VnodeStats builds a VnodeStats from a slice of uint32s.
  237. func vnodeStats(us []uint32) (VnodeStats, error) {
  238. // The attribute "Free" appears to not be available on older XFS
  239. // stats versions. Therefore, 7 or 8 elements may appear in
  240. // this slice.
  241. l := len(us)
  242. if l != 7 && l != 8 {
  243. return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l)
  244. }
  245. s := VnodeStats{
  246. Active: us[0],
  247. Allocate: us[1],
  248. Get: us[2],
  249. Hold: us[3],
  250. Release: us[4],
  251. Reclaim: us[5],
  252. Remove: us[6],
  253. }
  254. // Skip adding free, unless it is present. The zero value will
  255. // be used in place of an actual count.
  256. if l == 7 {
  257. return s, nil
  258. }
  259. s.Free = us[7]
  260. return s, nil
  261. }
  262. // BufferStats builds a BufferStats from a slice of uint32s.
  263. func bufferStats(us []uint32) (BufferStats, error) {
  264. if l := len(us); l != 9 {
  265. return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l)
  266. }
  267. return BufferStats{
  268. Get: us[0],
  269. Create: us[1],
  270. GetLocked: us[2],
  271. GetLockedWaited: us[3],
  272. BusyLocked: us[4],
  273. MissLocked: us[5],
  274. PageRetries: us[6],
  275. PageFound: us[7],
  276. GetRead: us[8],
  277. }, nil
  278. }
  279. // ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s.
  280. func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) {
  281. if l := len(us); l != 3 {
  282. return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l)
  283. }
  284. return ExtendedPrecisionStats{
  285. FlushBytes: us[0],
  286. WriteBytes: us[1],
  287. ReadBytes: us[2],
  288. }, nil
  289. }