ScalingAggregates derives rolling ratios from completed in-memory records for autoscaler hints. ttftRatio compares mean TTFT in the newer half vs the older half (by completion time); 1.0 means no skew. recentFallbackRate is the fraction of completed requests in the newer half that recorded a fallbac
()
| 80 | // ttftRatio compares mean TTFT in the newer half vs the older half (by completion time); 1.0 means no skew. |
| 81 | // recentFallbackRate is the fraction of completed requests in the newer half that recorded a fallback. |
| 82 | func (e *MemoryEngine) ScalingAggregates() (ttftRatio float64, recentFallbackRate float64) { |
| 83 | e.mu.Lock() |
| 84 | defer e.mu.Unlock() |
| 85 | |
| 86 | type sample struct { |
| 87 | end time.Time |
| 88 | ttftMs int64 |
| 89 | fallback bool |
| 90 | } |
| 91 | samples := make([]sample, 0, len(e.records)) |
| 92 | for _, rec := range e.records { |
| 93 | if rec.endTime.IsZero() || rec.startTime.IsZero() { |
| 94 | continue |
| 95 | } |
| 96 | var ttft int64 |
| 97 | if !rec.firstTokenTime.IsZero() { |
| 98 | ttft = rec.firstTokenTime.Sub(rec.startTime).Milliseconds() |
| 99 | } else { |
| 100 | ttft = rec.endTime.Sub(rec.startTime).Milliseconds() |
| 101 | } |
| 102 | if ttft < 0 { |
| 103 | ttft = 0 |
| 104 | } |
| 105 | samples = append(samples, sample{end: rec.endTime, ttftMs: ttft, fallback: rec.fallback}) |
| 106 | } |
| 107 | if len(samples) < 4 { |
| 108 | return 1.0, 0 |
| 109 | } |
| 110 | sort.Slice(samples, func(i, j int) bool { return samples[i].end.Before(samples[j].end) }) |
| 111 | mid := len(samples) / 2 |
| 112 | var oldSum, newSum int64 |
| 113 | oldC := mid |
| 114 | newC := len(samples) - mid |
| 115 | for i := 0; i < mid; i++ { |
| 116 | oldSum += samples[i].ttftMs |
| 117 | } |
| 118 | for i := mid; i < len(samples); i++ { |
| 119 | newSum += samples[i].ttftMs |
| 120 | } |
| 121 | if oldC == 0 || newC == 0 { |
| 122 | return 1.0, 0 |
| 123 | } |
| 124 | oldAvg := float64(oldSum) / float64(oldC) |
| 125 | newAvg := float64(newSum) / float64(newC) |
| 126 | if oldAvg < 1 { |
| 127 | oldAvg = 1 |
| 128 | } |
| 129 | ttftRatio = newAvg / oldAvg |
| 130 | |
| 131 | var fbRecent int |
| 132 | for i := mid; i < len(samples); i++ { |
| 133 | if samples[i].fallback { |
| 134 | fbRecent++ |
| 135 | } |
| 136 | } |
| 137 | recentFallbackRate = float64(fbRecent) / float64(newC) |
| 138 | return ttftRatio, recentFallbackRate |
| 139 | } |
no outgoing calls