bitsetratio.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package aggregator
  2. import (
  3. "math"
  4. "sync"
  5. "time"
  6. )
  7. // bitSetRatioAggregator is a MetricAggregator which returns the fraction of
  8. // unique-timestamp samples in which a specific bit was set in the sample
  9. // value, treating the value as an integer bitmask. It is used to derive the
  10. // fraction of a window a GPU spent throttled for a specific reason from the
  11. // DCGM clock throttle reasons bitmask.
  12. type bitSetRatioAggregator struct {
  13. lock sync.Mutex
  14. labelValues []string
  15. bit uint64
  16. count int
  17. setCount int
  18. currentTime *time.Time
  19. currentSet bool
  20. }
  21. // BitSetRatio returns a MetricAggregatorFactory producing aggregators that
  22. // report the fraction of samples with the given bit set.
  23. func BitSetRatio(bit uint64) MetricAggregatorFactory {
  24. return func(labelValues []string) MetricAggregator {
  25. return &bitSetRatioAggregator{
  26. labelValues: labelValues,
  27. bit: bit,
  28. }
  29. }
  30. }
  31. func (a *bitSetRatioAggregator) AdditionInfo() map[string]string {
  32. return nil
  33. }
  34. func (a *bitSetRatioAggregator) LabelValues() []string {
  35. return a.labelValues
  36. }
  37. func (a *bitSetRatioAggregator) Update(value float64, timestamp time.Time, additionalInfo map[string]string) {
  38. a.lock.Lock()
  39. defer a.lock.Unlock()
  40. // NaN or negative values cannot be valid bitmasks; count the sample as
  41. // bit-clear rather than guessing
  42. set := !math.IsNaN(value) && value >= 0 && uint64(value)&a.bit != 0
  43. if a.currentTime == nil || !timestamp.Equal(*a.currentTime) {
  44. a.currentTime = &timestamp
  45. a.currentSet = false
  46. a.count++
  47. }
  48. if set && !a.currentSet {
  49. a.currentSet = true
  50. a.setCount++
  51. }
  52. }
  53. func (a *bitSetRatioAggregator) Value() []MetricValue {
  54. a.lock.Lock()
  55. defer a.lock.Unlock()
  56. if a.count == 0 {
  57. return []MetricValue{{Value: 0}}
  58. }
  59. return []MetricValue{
  60. {Value: float64(a.setCount) / float64(a.count)},
  61. }
  62. }