stats.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package cache
  2. import (
  3. "fmt"
  4. "sync/atomic"
  5. "time"
  6. )
  7. // Stats is statistics about performance of a cache.
  8. type Stats struct {
  9. HitCount uint64
  10. MissCount uint64
  11. LoadSuccessCount uint64
  12. LoadErrorCount uint64
  13. TotalLoadTime time.Duration
  14. EvictionCount uint64
  15. }
  16. // RequestCount returns a total of HitCount and MissCount.
  17. func (s *Stats) RequestCount() uint64 {
  18. return s.HitCount + s.MissCount
  19. }
  20. // HitRate returns the ratio of cache requests which were hits.
  21. func (s *Stats) HitRate() float64 {
  22. total := s.RequestCount()
  23. if total == 0 {
  24. return 1.0
  25. }
  26. return float64(s.HitCount) / float64(total)
  27. }
  28. // MissRate returns the ratio of cache requests which were misses.
  29. func (s *Stats) MissRate() float64 {
  30. total := s.RequestCount()
  31. if total == 0 {
  32. return 0.0
  33. }
  34. return float64(s.MissCount) / float64(total)
  35. }
  36. // LoadErrorRate returns the ratio of cache loading attempts which returned errors.
  37. func (s *Stats) LoadErrorRate() float64 {
  38. total := s.LoadSuccessCount + s.LoadErrorCount
  39. if total == 0 {
  40. return 0.0
  41. }
  42. return float64(s.LoadErrorCount) / float64(total)
  43. }
  44. // AverageLoadPenalty returns the average time spent loading new values.
  45. func (s *Stats) AverageLoadPenalty() time.Duration {
  46. total := s.LoadSuccessCount + s.LoadErrorCount
  47. if total == 0 {
  48. return 0.0
  49. }
  50. return s.TotalLoadTime / time.Duration(total)
  51. }
  52. // String returns a string representation of this statistics.
  53. func (s *Stats) String() string {
  54. return fmt.Sprintf("hits: %d, misses: %d, successes: %d, errors: %d, time: %s, evictions: %d",
  55. s.HitCount, s.MissCount, s.LoadSuccessCount, s.LoadErrorCount, s.TotalLoadTime, s.EvictionCount)
  56. }
  57. // StatsCounter accumulates statistics of a cache.
  58. type StatsCounter interface {
  59. // RecordHits records cache hits.
  60. RecordHits(count uint64)
  61. // RecordMisses records cache misses.
  62. RecordMisses(count uint64)
  63. // RecordLoadSuccess records successful load of a new entry.
  64. RecordLoadSuccess(loadTime time.Duration)
  65. // RecordLoadError records failed load of a new entry.
  66. RecordLoadError(loadTime time.Duration)
  67. // RecordEviction records eviction of an entry from the cache.
  68. RecordEviction()
  69. // Snapshot writes snapshot of this counter values to the given Stats pointer.
  70. Snapshot(*Stats)
  71. }
  72. // statsCounter is a simple implementation of StatsCounter.
  73. type statsCounter struct {
  74. Stats
  75. }
  76. // RecordHits increases HitCount atomically.
  77. func (s *statsCounter) RecordHits(count uint64) {
  78. atomic.AddUint64(&s.Stats.HitCount, count)
  79. }
  80. // RecordMisses increases MissCount atomically.
  81. func (s *statsCounter) RecordMisses(count uint64) {
  82. atomic.AddUint64(&s.Stats.MissCount, count)
  83. }
  84. // RecordLoadSuccess increases LoadSuccessCount atomically.
  85. func (s *statsCounter) RecordLoadSuccess(loadTime time.Duration) {
  86. atomic.AddUint64(&s.Stats.LoadSuccessCount, 1)
  87. atomic.AddInt64((*int64)(&s.Stats.TotalLoadTime), int64(loadTime))
  88. }
  89. // RecordLoadError increases LoadErrorCount atomically.
  90. func (s *statsCounter) RecordLoadError(loadTime time.Duration) {
  91. atomic.AddUint64(&s.Stats.LoadErrorCount, 1)
  92. atomic.AddInt64((*int64)(&s.Stats.TotalLoadTime), int64(loadTime))
  93. }
  94. // RecordEviction increases EvictionCount atomically.
  95. func (s *statsCounter) RecordEviction() {
  96. atomic.AddUint64(&s.Stats.EvictionCount, 1)
  97. }
  98. // Snapshot copies current stats to t.
  99. func (s *statsCounter) Snapshot(t *Stats) {
  100. t.HitCount = atomic.LoadUint64(&s.HitCount)
  101. t.MissCount = atomic.LoadUint64(&s.MissCount)
  102. t.LoadSuccessCount = atomic.LoadUint64(&s.LoadSuccessCount)
  103. t.LoadErrorCount = atomic.LoadUint64(&s.LoadErrorCount)
  104. t.TotalLoadTime = time.Duration(atomic.LoadInt64((*int64)(&s.TotalLoadTime)))
  105. t.EvictionCount = atomic.LoadUint64(&s.EvictionCount)
  106. }