container_vastaitech_gpu_metrics.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright 2019 Yunion
  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 hostmetrics
  15. import (
  16. "fmt"
  17. "regexp"
  18. "strconv"
  19. "strings"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/onecloud/pkg/util/fileutils2"
  23. "yunion.io/x/onecloud/pkg/util/procutils"
  24. )
  25. type VastaitechGpuProcessMetrics struct {
  26. DevId string
  27. PciAddr string // Device Pci Addr
  28. Pid string // Process ID
  29. Enc float64
  30. Dec float64
  31. Gfx float64
  32. GfxMem float64
  33. GfxMemUsage float64
  34. }
  35. func GetVastaitechGpuProcessMetrics() ([]VastaitechGpuProcessMetrics, error) {
  36. outputFile := "/tmp/vasmi_pmon.csv"
  37. cmd := fmt.Sprintf("/usr/bin/vasmi pmon --outputformat=csv --outputfile=%s --loop 1", outputFile)
  38. out, err := procutils.NewRemoteCommandAsFarAsPossible("bash", "-c", cmd).Output()
  39. if err != nil {
  40. return nil, errors.Wrapf(err, "Execute %s failed: %s", cmd, out)
  41. }
  42. output, err := fileutils2.FileGetContents(outputFile)
  43. if err != nil {
  44. return nil, errors.Wrapf(err, "FileGetContents %s failed", outputFile)
  45. }
  46. return parseVastaitechGpuProcessMetrics(output), nil
  47. }
  48. /*
  49. LoopTimes,AIC,DevId,PCIe_Bus_Id,PID,VPID,Command,Container_Name,Enc,Dec,Gfx,Gfx_Mem,Gfx_Mem_Usage,Reserved_Mem
  50. 1,0,0,0000:18:00.0,3112054,388,android.hardware.graphics.allocator@2.0-service,va_androidxx,0,0,0,61.68MB,0.827308,0.00B
  51. */
  52. func parseVastaitechGpuProcessMetrics(gpuMetricsStr string) []VastaitechGpuProcessMetrics {
  53. gpuProcessMetrics := make([]VastaitechGpuProcessMetrics, 0)
  54. lines := strings.Split(gpuMetricsStr, "\n")
  55. for i := 1; i < len(lines); i++ {
  56. segs := strings.Split(lines[i], ",")
  57. segLens := len(segs)
  58. if segLens < 14 {
  59. continue
  60. }
  61. devId, pciAddr, pidStr := segs[2], segs[3], segs[4]
  62. if devId == "Null" {
  63. continue
  64. }
  65. gfxMemUsageStr, gfxMemStr, gfxStr, decStr, encStr := segs[segLens-2], segs[segLens-3], segs[segLens-4], segs[segLens-5], segs[segLens-6]
  66. gfxMemUsage, err := strconv.ParseFloat(gfxMemUsageStr, 64)
  67. if err != nil {
  68. log.Errorf("failed parse gfxMemUsageStr %s: %s", gfxMemUsageStr, err)
  69. }
  70. gfxMem, err := parseSizeToFloat64(gfxMemStr)
  71. if err != nil {
  72. log.Errorf("failed parse gfxMemStr %s: %s", gfxMemStr, err)
  73. continue
  74. }
  75. pciAddr = strings.ReplaceAll(pciAddr, ":", "_")
  76. gfxMem = gfxMem / 1024.0 / 1024.0
  77. gfx, err := strconv.ParseFloat(gfxStr, 64)
  78. if err != nil {
  79. log.Errorf("failed parse gfxStr %s: %s", gfxStr, err)
  80. }
  81. dec, err := strconv.ParseFloat(decStr, 64)
  82. if err != nil {
  83. log.Errorf("failed parse decStr %s: %s", decStr, err)
  84. }
  85. enc, err := strconv.ParseFloat(encStr, 64)
  86. if err != nil {
  87. log.Errorf("failed parse encStr %s: %s", encStr, err)
  88. }
  89. procMetrics := VastaitechGpuProcessMetrics{
  90. DevId: devId,
  91. PciAddr: pciAddr,
  92. Pid: pidStr,
  93. Gfx: gfx,
  94. GfxMem: gfxMem,
  95. GfxMemUsage: gfxMemUsage,
  96. Enc: enc,
  97. Dec: dec,
  98. }
  99. gpuProcessMetrics = append(gpuProcessMetrics, procMetrics)
  100. }
  101. return gpuProcessMetrics
  102. }
  103. // See: http://en.wikipedia.org/wiki/Binary_prefix
  104. const (
  105. // Decimal
  106. KB = 1000
  107. MB = 1000 * KB
  108. GB = 1000 * MB
  109. TB = 1000 * GB
  110. PB = 1000 * TB
  111. )
  112. type unitMap map[string]int64
  113. var (
  114. decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
  115. sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[iI]?[bB]?$`)
  116. )
  117. // Parses the human-readable size string into the amount it represents.
  118. func parseSizeToFloat64(sizeStr string) (float64, error) {
  119. matches := sizeRegex.FindStringSubmatch(sizeStr)
  120. if len(matches) != 4 {
  121. return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
  122. }
  123. size, err := strconv.ParseFloat(matches[1], 64)
  124. if err != nil {
  125. return -1, err
  126. }
  127. unitPrefix := strings.ToLower(matches[3])
  128. if mul, ok := decimalMap[unitPrefix]; ok {
  129. size *= float64(mul)
  130. }
  131. return size, nil
  132. }