sysfs.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package sysfs
  15. import (
  16. "fmt"
  17. "io/ioutil"
  18. "os"
  19. "path"
  20. "strconv"
  21. "strings"
  22. )
  23. const (
  24. blockDir = "/sys/block"
  25. cacheDir = "/sys/devices/system/cpu/cpu"
  26. netDir = "/sys/class/net"
  27. dmiDir = "/sys/class/dmi"
  28. ppcDevTree = "/proc/device-tree"
  29. s390xDevTree = "/etc" // s390/s390x changes
  30. )
  31. type CacheInfo struct {
  32. // size in bytes
  33. Size uint64
  34. // cache type - instruction, data, unified
  35. Type string
  36. // distance from cpus in a multi-level hierarchy
  37. Level int
  38. // number of cpus that can access this cache.
  39. Cpus int
  40. }
  41. // Abstracts the lowest level calls to sysfs.
  42. type SysFs interface {
  43. // Get directory information for available block devices.
  44. GetBlockDevices() ([]os.FileInfo, error)
  45. // Get Size of a given block device.
  46. GetBlockDeviceSize(string) (string, error)
  47. // Get scheduler type for the block device.
  48. GetBlockDeviceScheduler(string) (string, error)
  49. // Get device major:minor number string.
  50. GetBlockDeviceNumbers(string) (string, error)
  51. GetNetworkDevices() ([]os.FileInfo, error)
  52. GetNetworkAddress(string) (string, error)
  53. GetNetworkMtu(string) (string, error)
  54. GetNetworkSpeed(string) (string, error)
  55. GetNetworkStatValue(dev string, stat string) (uint64, error)
  56. // Get directory information for available caches accessible to given cpu.
  57. GetCaches(id int) ([]os.FileInfo, error)
  58. // Get information for a cache accessible from the given cpu.
  59. GetCacheInfo(cpu int, cache string) (CacheInfo, error)
  60. GetSystemUUID() (string, error)
  61. }
  62. type realSysFs struct{}
  63. func NewRealSysFs() SysFs {
  64. return &realSysFs{}
  65. }
  66. func (self *realSysFs) GetBlockDevices() ([]os.FileInfo, error) {
  67. return ioutil.ReadDir(blockDir)
  68. }
  69. func (self *realSysFs) GetBlockDeviceNumbers(name string) (string, error) {
  70. dev, err := ioutil.ReadFile(path.Join(blockDir, name, "/dev"))
  71. if err != nil {
  72. return "", err
  73. }
  74. return string(dev), nil
  75. }
  76. func (self *realSysFs) GetBlockDeviceScheduler(name string) (string, error) {
  77. sched, err := ioutil.ReadFile(path.Join(blockDir, name, "/queue/scheduler"))
  78. if err != nil {
  79. return "", err
  80. }
  81. return string(sched), nil
  82. }
  83. func (self *realSysFs) GetBlockDeviceSize(name string) (string, error) {
  84. size, err := ioutil.ReadFile(path.Join(blockDir, name, "/size"))
  85. if err != nil {
  86. return "", err
  87. }
  88. return string(size), nil
  89. }
  90. func (self *realSysFs) GetNetworkDevices() ([]os.FileInfo, error) {
  91. files, err := ioutil.ReadDir(netDir)
  92. if err != nil {
  93. return nil, err
  94. }
  95. // Filter out non-directory & non-symlink files
  96. var dirs []os.FileInfo
  97. for _, f := range files {
  98. if f.Mode()|os.ModeSymlink != 0 {
  99. f, err = os.Stat(path.Join(netDir, f.Name()))
  100. if err != nil {
  101. continue
  102. }
  103. }
  104. if f.IsDir() {
  105. dirs = append(dirs, f)
  106. }
  107. }
  108. return dirs, nil
  109. }
  110. func (self *realSysFs) GetNetworkAddress(name string) (string, error) {
  111. address, err := ioutil.ReadFile(path.Join(netDir, name, "/address"))
  112. if err != nil {
  113. return "", err
  114. }
  115. return string(address), nil
  116. }
  117. func (self *realSysFs) GetNetworkMtu(name string) (string, error) {
  118. mtu, err := ioutil.ReadFile(path.Join(netDir, name, "/mtu"))
  119. if err != nil {
  120. return "", err
  121. }
  122. return string(mtu), nil
  123. }
  124. func (self *realSysFs) GetNetworkSpeed(name string) (string, error) {
  125. speed, err := ioutil.ReadFile(path.Join(netDir, name, "/speed"))
  126. if err != nil {
  127. return "", err
  128. }
  129. return string(speed), nil
  130. }
  131. func (self *realSysFs) GetNetworkStatValue(dev string, stat string) (uint64, error) {
  132. statPath := path.Join(netDir, dev, "/statistics", stat)
  133. out, err := ioutil.ReadFile(statPath)
  134. if err != nil {
  135. return 0, fmt.Errorf("failed to read stat from %q for device %q", statPath, dev)
  136. }
  137. var s uint64
  138. n, err := fmt.Sscanf(string(out), "%d", &s)
  139. if err != nil || n != 1 {
  140. return 0, fmt.Errorf("could not parse value from %q for file %s", string(out), statPath)
  141. }
  142. return s, nil
  143. }
  144. func (self *realSysFs) GetCaches(id int) ([]os.FileInfo, error) {
  145. cpuPath := fmt.Sprintf("%s%d/cache", cacheDir, id)
  146. return ioutil.ReadDir(cpuPath)
  147. }
  148. func bitCount(i uint64) (count int) {
  149. for i != 0 {
  150. if i&1 == 1 {
  151. count++
  152. }
  153. i >>= 1
  154. }
  155. return
  156. }
  157. func getCpuCount(cache string) (count int, err error) {
  158. out, err := ioutil.ReadFile(path.Join(cache, "/shared_cpu_map"))
  159. if err != nil {
  160. return 0, err
  161. }
  162. masks := strings.Split(string(out), ",")
  163. for _, mask := range masks {
  164. // convert hex string to uint64
  165. m, err := strconv.ParseUint(strings.TrimSpace(mask), 16, 64)
  166. if err != nil {
  167. return 0, fmt.Errorf("failed to parse cpu map %q: %v", string(out), err)
  168. }
  169. count += bitCount(m)
  170. }
  171. return
  172. }
  173. func (self *realSysFs) GetCacheInfo(id int, name string) (CacheInfo, error) {
  174. cachePath := fmt.Sprintf("%s%d/cache/%s", cacheDir, id, name)
  175. out, err := ioutil.ReadFile(path.Join(cachePath, "/size"))
  176. if err != nil {
  177. return CacheInfo{}, err
  178. }
  179. var size uint64
  180. n, err := fmt.Sscanf(string(out), "%dK", &size)
  181. if err != nil || n != 1 {
  182. return CacheInfo{}, err
  183. }
  184. // convert to bytes
  185. size = size * 1024
  186. out, err = ioutil.ReadFile(path.Join(cachePath, "/level"))
  187. if err != nil {
  188. return CacheInfo{}, err
  189. }
  190. var level int
  191. n, err = fmt.Sscanf(string(out), "%d", &level)
  192. if err != nil || n != 1 {
  193. return CacheInfo{}, err
  194. }
  195. out, err = ioutil.ReadFile(path.Join(cachePath, "/type"))
  196. if err != nil {
  197. return CacheInfo{}, err
  198. }
  199. cacheType := strings.TrimSpace(string(out))
  200. cpuCount, err := getCpuCount(cachePath)
  201. if err != nil {
  202. return CacheInfo{}, err
  203. }
  204. return CacheInfo{
  205. Size: size,
  206. Level: level,
  207. Type: cacheType,
  208. Cpus: cpuCount,
  209. }, nil
  210. }
  211. func (self *realSysFs) GetSystemUUID() (string, error) {
  212. if id, err := ioutil.ReadFile(path.Join(dmiDir, "id", "product_uuid")); err == nil {
  213. return strings.TrimSpace(string(id)), nil
  214. } else if id, err = ioutil.ReadFile(path.Join(ppcDevTree, "system-id")); err == nil {
  215. return strings.TrimSpace(string(id)), nil
  216. } else if id, err = ioutil.ReadFile(path.Join(ppcDevTree, "vm,uuid")); err == nil {
  217. return strings.TrimSpace(string(id)), nil
  218. } else if id, err = ioutil.ReadFile(path.Join(s390xDevTree, "machine-id")); err == nil {
  219. return strings.TrimSpace(string(id)), nil
  220. } else {
  221. return "", err
  222. }
  223. }