conversion.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // Copyright 2015 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 v2
  15. import (
  16. "fmt"
  17. "time"
  18. "k8s.io/klog/v2"
  19. v1 "github.com/google/cadvisor/info/v1"
  20. )
  21. func machineFsStatsFromV1(fsStats []v1.FsStats) []MachineFsStats {
  22. var result []MachineFsStats
  23. for i := range fsStats {
  24. stat := fsStats[i]
  25. readDuration := time.Millisecond * time.Duration(stat.ReadTime)
  26. writeDuration := time.Millisecond * time.Duration(stat.WriteTime)
  27. ioDuration := time.Millisecond * time.Duration(stat.IoTime)
  28. weightedDuration := time.Millisecond * time.Duration(stat.WeightedIoTime)
  29. machineFsStat := MachineFsStats{
  30. Device: stat.Device,
  31. Type: stat.Type,
  32. Capacity: &stat.Limit,
  33. Usage: &stat.Usage,
  34. Available: &stat.Available,
  35. DiskStats: DiskStats{
  36. ReadsCompleted: &stat.ReadsCompleted,
  37. ReadsMerged: &stat.ReadsMerged,
  38. SectorsRead: &stat.SectorsRead,
  39. ReadDuration: &readDuration,
  40. WritesCompleted: &stat.WritesCompleted,
  41. WritesMerged: &stat.WritesMerged,
  42. SectorsWritten: &stat.SectorsWritten,
  43. WriteDuration: &writeDuration,
  44. IoInProgress: &stat.IoInProgress,
  45. IoDuration: &ioDuration,
  46. WeightedIoDuration: &weightedDuration,
  47. },
  48. }
  49. if stat.HasInodes {
  50. machineFsStat.InodesFree = &stat.InodesFree
  51. }
  52. result = append(result, machineFsStat)
  53. }
  54. return result
  55. }
  56. func MachineStatsFromV1(cont *v1.ContainerInfo) []MachineStats {
  57. var stats []MachineStats
  58. var last *v1.ContainerStats
  59. for i := range cont.Stats {
  60. val := cont.Stats[i]
  61. stat := MachineStats{
  62. Timestamp: val.Timestamp,
  63. }
  64. if cont.Spec.HasCpu {
  65. stat.Cpu = &val.Cpu
  66. cpuInst, err := InstCpuStats(last, val)
  67. if err != nil {
  68. klog.Warningf("Could not get instant cpu stats: %v", err)
  69. } else {
  70. stat.CpuInst = cpuInst
  71. }
  72. last = val
  73. }
  74. if cont.Spec.HasMemory {
  75. stat.Memory = &val.Memory
  76. }
  77. if cont.Spec.HasNetwork {
  78. stat.Network = &NetworkStats{
  79. // FIXME: Use reflection instead.
  80. Tcp: TcpStat(val.Network.Tcp),
  81. Tcp6: TcpStat(val.Network.Tcp6),
  82. Interfaces: val.Network.Interfaces,
  83. }
  84. }
  85. if cont.Spec.HasFilesystem {
  86. stat.Filesystem = machineFsStatsFromV1(val.Filesystem)
  87. }
  88. // TODO(rjnagal): Handle load stats.
  89. stats = append(stats, stat)
  90. }
  91. return stats
  92. }
  93. func ContainerStatsFromV1(containerName string, spec *v1.ContainerSpec, stats []*v1.ContainerStats) []*ContainerStats {
  94. newStats := make([]*ContainerStats, 0, len(stats))
  95. var last *v1.ContainerStats
  96. for _, val := range stats {
  97. stat := &ContainerStats{
  98. Timestamp: val.Timestamp,
  99. ReferencedMemory: val.ReferencedMemory,
  100. }
  101. if spec.HasCpu {
  102. stat.Cpu = &val.Cpu
  103. cpuInst, err := InstCpuStats(last, val)
  104. if err != nil {
  105. klog.Warningf("Could not get instant cpu stats: %v", err)
  106. } else {
  107. stat.CpuInst = cpuInst
  108. }
  109. last = val
  110. }
  111. if spec.HasMemory {
  112. stat.Memory = &val.Memory
  113. }
  114. if spec.HasHugetlb {
  115. stat.Hugetlb = &val.Hugetlb
  116. }
  117. if spec.HasNetwork {
  118. // TODO: Handle TcpStats
  119. stat.Network = &NetworkStats{
  120. Tcp: TcpStat(val.Network.Tcp),
  121. Tcp6: TcpStat(val.Network.Tcp6),
  122. Interfaces: val.Network.Interfaces,
  123. }
  124. }
  125. if spec.HasProcesses {
  126. stat.Processes = &val.Processes
  127. }
  128. if spec.HasFilesystem {
  129. if len(val.Filesystem) == 1 {
  130. stat.Filesystem = &FilesystemStats{
  131. TotalUsageBytes: &val.Filesystem[0].Usage,
  132. BaseUsageBytes: &val.Filesystem[0].BaseUsage,
  133. InodeUsage: &val.Filesystem[0].Inodes,
  134. }
  135. } else if len(val.Filesystem) > 1 && containerName != "/" {
  136. // Cannot handle multiple devices per container.
  137. klog.V(4).Infof("failed to handle multiple devices for container %s. Skipping Filesystem stats", containerName)
  138. }
  139. }
  140. if spec.HasDiskIo {
  141. stat.DiskIo = &val.DiskIo
  142. }
  143. if spec.HasCustomMetrics {
  144. stat.CustomMetrics = val.CustomMetrics
  145. }
  146. if len(val.Accelerators) > 0 {
  147. stat.Accelerators = val.Accelerators
  148. }
  149. if len(val.PerfStats) > 0 {
  150. stat.PerfStats = val.PerfStats
  151. }
  152. if len(val.PerfUncoreStats) > 0 {
  153. stat.PerfUncoreStats = val.PerfUncoreStats
  154. }
  155. if len(val.Resctrl.MemoryBandwidth) > 0 || len(val.Resctrl.Cache) > 0 {
  156. stat.Resctrl = val.Resctrl
  157. }
  158. // TODO(rjnagal): Handle load stats.
  159. newStats = append(newStats, stat)
  160. }
  161. return newStats
  162. }
  163. func DeprecatedStatsFromV1(cont *v1.ContainerInfo) []DeprecatedContainerStats {
  164. stats := make([]DeprecatedContainerStats, 0, len(cont.Stats))
  165. var last *v1.ContainerStats
  166. for _, val := range cont.Stats {
  167. stat := DeprecatedContainerStats{
  168. Timestamp: val.Timestamp,
  169. HasCpu: cont.Spec.HasCpu,
  170. HasMemory: cont.Spec.HasMemory,
  171. HasHugetlb: cont.Spec.HasHugetlb,
  172. HasNetwork: cont.Spec.HasNetwork,
  173. HasFilesystem: cont.Spec.HasFilesystem,
  174. HasDiskIo: cont.Spec.HasDiskIo,
  175. HasCustomMetrics: cont.Spec.HasCustomMetrics,
  176. ReferencedMemory: val.ReferencedMemory,
  177. }
  178. if stat.HasCpu {
  179. stat.Cpu = val.Cpu
  180. cpuInst, err := InstCpuStats(last, val)
  181. if err != nil {
  182. klog.Warningf("Could not get instant cpu stats: %v", err)
  183. } else {
  184. stat.CpuInst = cpuInst
  185. }
  186. last = val
  187. }
  188. if stat.HasMemory {
  189. stat.Memory = val.Memory
  190. }
  191. if stat.HasHugetlb {
  192. stat.Hugetlb = val.Hugetlb
  193. }
  194. if stat.HasNetwork {
  195. stat.Network.Interfaces = val.Network.Interfaces
  196. }
  197. if stat.HasProcesses {
  198. stat.Processes = val.Processes
  199. }
  200. if stat.HasFilesystem {
  201. stat.Filesystem = val.Filesystem
  202. }
  203. if stat.HasDiskIo {
  204. stat.DiskIo = val.DiskIo
  205. }
  206. if stat.HasCustomMetrics {
  207. stat.CustomMetrics = val.CustomMetrics
  208. }
  209. if len(val.PerfStats) > 0 {
  210. stat.PerfStats = val.PerfStats
  211. }
  212. if len(val.PerfUncoreStats) > 0 {
  213. stat.PerfUncoreStats = val.PerfUncoreStats
  214. }
  215. if len(val.Resctrl.MemoryBandwidth) > 0 || len(val.Resctrl.Cache) > 0 {
  216. stat.Resctrl = val.Resctrl
  217. }
  218. // TODO(rjnagal): Handle load stats.
  219. stats = append(stats, stat)
  220. }
  221. return stats
  222. }
  223. func InstCpuStats(last, cur *v1.ContainerStats) (*CpuInstStats, error) {
  224. if last == nil {
  225. return nil, nil
  226. }
  227. if !cur.Timestamp.After(last.Timestamp) {
  228. return nil, fmt.Errorf("container stats move backwards in time")
  229. }
  230. if len(last.Cpu.Usage.PerCpu) != len(cur.Cpu.Usage.PerCpu) {
  231. return nil, fmt.Errorf("different number of cpus")
  232. }
  233. timeDelta := cur.Timestamp.Sub(last.Timestamp)
  234. // Nanoseconds to gain precision and avoid having zero seconds if the
  235. // difference between the timestamps is just under a second
  236. timeDeltaNs := uint64(timeDelta.Nanoseconds())
  237. convertToRate := func(lastValue, curValue uint64) (uint64, error) {
  238. if curValue < lastValue {
  239. return 0, fmt.Errorf("cumulative stats decrease")
  240. }
  241. valueDelta := curValue - lastValue
  242. // Use float64 to keep precision
  243. return uint64(float64(valueDelta) / float64(timeDeltaNs) * 1e9), nil
  244. }
  245. total, err := convertToRate(last.Cpu.Usage.Total, cur.Cpu.Usage.Total)
  246. if err != nil {
  247. return nil, err
  248. }
  249. percpu := make([]uint64, len(last.Cpu.Usage.PerCpu))
  250. for i := range percpu {
  251. var err error
  252. percpu[i], err = convertToRate(last.Cpu.Usage.PerCpu[i], cur.Cpu.Usage.PerCpu[i])
  253. if err != nil {
  254. return nil, err
  255. }
  256. }
  257. user, err := convertToRate(last.Cpu.Usage.User, cur.Cpu.Usage.User)
  258. if err != nil {
  259. return nil, err
  260. }
  261. system, err := convertToRate(last.Cpu.Usage.System, cur.Cpu.Usage.System)
  262. if err != nil {
  263. return nil, err
  264. }
  265. return &CpuInstStats{
  266. Usage: CpuInstUsage{
  267. Total: total,
  268. PerCpu: percpu,
  269. User: user,
  270. System: system,
  271. },
  272. }, nil
  273. }
  274. // Get V2 container spec from v1 container info.
  275. func ContainerSpecFromV1(specV1 *v1.ContainerSpec, aliases []string, namespace string) ContainerSpec {
  276. specV2 := ContainerSpec{
  277. CreationTime: specV1.CreationTime,
  278. HasCpu: specV1.HasCpu,
  279. HasMemory: specV1.HasMemory,
  280. HasHugetlb: specV1.HasHugetlb,
  281. HasFilesystem: specV1.HasFilesystem,
  282. HasNetwork: specV1.HasNetwork,
  283. HasProcesses: specV1.HasProcesses,
  284. HasDiskIo: specV1.HasDiskIo,
  285. HasCustomMetrics: specV1.HasCustomMetrics,
  286. Image: specV1.Image,
  287. Labels: specV1.Labels,
  288. Envs: specV1.Envs,
  289. }
  290. if specV1.HasCpu {
  291. specV2.Cpu.Limit = specV1.Cpu.Limit
  292. specV2.Cpu.MaxLimit = specV1.Cpu.MaxLimit
  293. specV2.Cpu.Mask = specV1.Cpu.Mask
  294. }
  295. if specV1.HasMemory {
  296. specV2.Memory.Limit = specV1.Memory.Limit
  297. specV2.Memory.Reservation = specV1.Memory.Reservation
  298. specV2.Memory.SwapLimit = specV1.Memory.SwapLimit
  299. }
  300. if specV1.HasCustomMetrics {
  301. specV2.CustomMetrics = specV1.CustomMetrics
  302. }
  303. specV2.Aliases = aliases
  304. specV2.Namespace = namespace
  305. return specV2
  306. }