|
| 1 | +--------------------------------------------------------------------------------------------------- |
| 2 | +-- addons monitor single addon data object |
| 3 | +--------------------------------------------------------------------------------------------------- |
| 4 | + |
| 5 | +local AMutils = _G.AddonsManagerStuff.AMutils |
| 6 | + |
| 7 | +local oAM = nil |
| 8 | + |
| 9 | +local AMdata = {} |
| 10 | + |
| 11 | +AMdata.sThisAddonName = "AddonsMonitor" |
| 12 | + |
| 13 | +AMdata.iDataRetentionSec = 120 |
| 14 | +AMdata.fTotalLoadTreshold = 0.01 |
| 15 | +AMdata.iTotalCallsTreshold = 10 |
| 16 | +AMdata.iMaxStatsTresholdShort = 5 |
| 17 | + |
| 18 | + |
| 19 | +--- public interface below --- |
| 20 | + |
| 21 | +function AMdata:new(sUniqueName, tAddonInfo, tHistory, tSessions) |
| 22 | + local o = {} |
| 23 | + setmetatable(o, self) |
| 24 | + self.__index = self |
| 25 | + |
| 26 | + oAM = _G.AddonsManagerStuff.oAM |
| 27 | + |
| 28 | + o:_init(sUniqueName, tAddonInfo, tHistory, tSessions) |
| 29 | + return o |
| 30 | +end |
| 31 | + |
| 32 | +function AMdata:UpdateStatsLive() |
| 33 | + if self.live.eStatus <= AMutils.eStatus.error then |
| 34 | + return |
| 35 | + end |
| 36 | + self:UpdateStats(Apollo.GetAddonInfo(self.sUniqueName)) |
| 37 | +end |
| 38 | + |
| 39 | +function AMdata:FinishDataCollection() |
| 40 | + self:SaveRemainingData() |
| 41 | +end |
| 42 | + |
| 43 | + |
| 44 | +--- private methods below --- |
| 45 | + |
| 46 | +function AMdata:_init(sUniqueName, tAddonInfo, tHistory, tSessions) |
| 47 | + self.tHistory = tHistory |
| 48 | + |
| 49 | + self.tSessions = tSessions -- that's just a reference from AMdataManager, do not modify |
| 50 | + |
| 51 | + self.sName = tAddonInfo.strName |
| 52 | + self.sUniqueName = sUniqueName |
| 53 | + self.sAuthor = tAddonInfo.strAuthor |
| 54 | + self.iApiVersion = tAddonInfo.nAPIVersion |
| 55 | + |
| 56 | + self.bIsThisAddon = (self.sThisAddonName == sUniqueName) |
| 57 | + self.bIsCarbine = tAddonInfo.bCarbine |
| 58 | + self.bHasConfig = tAddonInfo.bHasConfigure |
| 59 | + self.bIgnoreApiVersion = tAddonInfo.bIgnoreVersion |
| 60 | + |
| 61 | + self.tLastModified = {} |
| 62 | + self.tLastModified.iTimestamp = self:ConvertCrbDateToTS(tAddonInfo.strLastModified) |
| 63 | + self.tLastModified.sFormatted = os.date("%Y-%m-%d %H:%M", self.tLastModified.iTimestamp) |
| 64 | + |
| 65 | + self.live = {} |
| 66 | + self.live.ePreviousStatus = nil |
| 67 | + self.live.eStatus = nil |
| 68 | + |
| 69 | + self.live.bBelowTreshold = (self.tHistory.qLoadAvg == nil) |
| 70 | + |
| 71 | + self.short = {} |
| 72 | + self.short.qLoadHistory = AMutils:QueueInitMoved(self.tSessions.iTick) |
| 73 | + |
| 74 | + self.short.fLoadTotalMs = 0 |
| 75 | + self.short.fLoad10Ms = 0 |
| 76 | + |
| 77 | + self.fMaxLoadThisSecondMs = 0 |
| 78 | + self.fMaxMemoryKb = 0 |
| 79 | + self.fLoadTotalSec = 0 |
| 80 | + self.iCallsTotal = 0 |
| 81 | + |
| 82 | + self:UpdateStats(tAddonInfo) |
| 83 | +end |
| 84 | + |
| 85 | +function AMdata:UpdateStats(tAddonInfo) |
| 86 | + self:UpdateStatsCurrent(tAddonInfo) |
| 87 | + |
| 88 | + if not self.live.bBelowTreshold then |
| 89 | + self:UpdateStatsShortPeriod(tAddonInfo) |
| 90 | + self:UpdateStatsHistory() |
| 91 | + end |
| 92 | +end |
| 93 | + |
| 94 | +function AMdata:UpdateStatsCurrent(tAddonInfo) |
| 95 | + self.live.bStatusChanged = (self.live.eStatus ~= tAddonInfo.eStatus) |
| 96 | + self.live.eStatus = tAddonInfo.eStatus |
| 97 | + |
| 98 | + self.live.fLoadPerFrameMs = tAddonInfo.fCallTimePerFrame * 1000 |
| 99 | + self.live.fLoadPerSecondMs = tAddonInfo.fCallTimePerSecond * 1000 |
| 100 | + self.live.fCurrentMemoryKb = tAddonInfo.nMemoryUsage / 1024 |
| 101 | + |
| 102 | + if self.live.bBelowTreshold then |
| 103 | + if tAddonInfo.eStatus == AMutils.eStatus.ok and tAddonInfo.fTotalTime < self.fTotalLoadTreshold and tAddonInfo.nTotalCalls < self.iTotalCallsTreshold then |
| 104 | + return |
| 105 | + end |
| 106 | + |
| 107 | + self.short.qLoadHistory = AMutils:QueueInitMoved(self.tSessions.iTick) |
| 108 | + self.live.bBelowTreshold = false |
| 109 | + end |
| 110 | + |
| 111 | + if self.live.bStatusChanged and self.live.eStatus ~= AMutils.eStatus.ok and self.live.eStatus ~= AMutils.eStatus.off then |
| 112 | + AMutils:EventsPush(self.tHistory.qEvents, AMutils.eEvent.statusChange, self.tSessions.iTick, "status changed to " .. AMutils:GetStatusName(self.live.eStatus)) |
| 113 | + end |
| 114 | + |
| 115 | + self.live.tErrors = tAddonInfo.arErrors |
| 116 | + |
| 117 | + self.live.fLoadThisSecondMs = (tAddonInfo.fTotalTime - self.fLoadTotalSec) * 1000 |
| 118 | + self.live.iCallsThisSecond = tAddonInfo.nTotalCalls - self.iCallsTotal |
| 119 | + |
| 120 | + self.fLoadTotalSec = tAddonInfo.fTotalTime |
| 121 | + self.iCallsTotal = tAddonInfo.nTotalCalls |
| 122 | + self.fMaxTimeOfCallMs = tAddonInfo.fLongestCall * 1000 |
| 123 | +end |
| 124 | + |
| 125 | +function AMdata:UpdateStatsShortPeriod(tAddonInfo) |
| 126 | + if self.short.qLoadHistory.last >= self.iMaxStatsTresholdShort then |
| 127 | + local x = self.live.fLoadThisSecondMs |
| 128 | + if self.fMaxLoadThisSecondMs < x then self.fMaxLoadThisSecondMs = x end |
| 129 | + local x = self.live.fCurrentMemoryKb |
| 130 | + if self.fMaxMemoryKb < x then self.fMaxMemoryKb = x end |
| 131 | + end |
| 132 | + |
| 133 | + local iValuesCount = AMutils:QueueCount(self.short.qLoadHistory) |
| 134 | + |
| 135 | + self.short.fLoad10Ms = self.short.fLoad10Ms + self.live.fLoadThisSecondMs |
| 136 | + self.short.fLoadTotalMs = self.short.fLoadTotalMs + self.live.fLoadThisSecondMs |
| 137 | + |
| 138 | + if iValuesCount >= 10 then |
| 139 | + self.short.fLoad10Ms = self.short.fLoad10Ms - self.short.qLoadHistory[self.short.qLoadHistory.last - 9] |
| 140 | + end |
| 141 | + if iValuesCount == self.iDataRetentionSec then |
| 142 | + self.short.fLoadTotalMs = self.short.fLoadTotalMs - AMutils:QueueShift(self.short.qLoadHistory) |
| 143 | + end |
| 144 | + |
| 145 | + AMutils:QueuePush(self.short.qLoadHistory, self.live.fLoadThisSecondMs) |
| 146 | + |
| 147 | + if iValuesCount < 10 then |
| 148 | + self.short.fLoadAvg10Ms = self.short.fLoad10Ms / (iValuesCount + 1) |
| 149 | + else |
| 150 | + self.short.fLoadAvg10Ms = self.short.fLoad10Ms / 10 |
| 151 | + end |
| 152 | + self.short.fLoadAvgMs = self.short.fLoadTotalMs / AMutils:QueueCount(self.short.qLoadHistory) |
| 153 | +end |
| 154 | + |
| 155 | +function AMdata:UpdateStatsHistory() |
| 156 | + local iEndAt = self.tSessions.iTick |
| 157 | + if iEndAt % oAM.iHistoryGroupSeconds ~= 0 then |
| 158 | + return |
| 159 | + end |
| 160 | + |
| 161 | + if self.tHistory.qLoadAvg == nil then |
| 162 | + self.tHistory.qLoadAvg = AMutils:QueueInit() |
| 163 | + self.tHistory.qLoadMax = AMutils:QueueInit() |
| 164 | + end |
| 165 | + |
| 166 | + local iStartAt = iEndAt - 9 |
| 167 | + local fLoadSum = 0 |
| 168 | + local fLoadMax = 0 |
| 169 | + local iTotalSeconds = (iEndAt - iStartAt + 1) |
| 170 | + |
| 171 | + -- adding data remaining from the previous session |
| 172 | + if iStartAt < self.short.qLoadHistory.first then |
| 173 | + iStartAt = self.short.qLoadHistory.first |
| 174 | + iTotalSeconds = (iEndAt - iStartAt + 1) |
| 175 | + |
| 176 | + if #self.tHistory.tRemaining ~= 0 then |
| 177 | + for _, fTmpLoadCurrent in ipairs(self.tHistory.tRemaining) do |
| 178 | + fLoadSum = fLoadSum + fTmpLoadCurrent |
| 179 | + if fLoadMax < fTmpLoadCurrent then |
| 180 | + fLoadMax = fTmpLoadCurrent |
| 181 | + end |
| 182 | + iTotalSeconds = iTotalSeconds + 1 |
| 183 | + end |
| 184 | + end |
| 185 | + self.tHistory.tRemaining = {} |
| 186 | + end |
| 187 | + |
| 188 | + -- iTotalSeconds should always be 10 unless this is the very beginning of collecting data |
| 189 | + |
| 190 | + for i = iStartAt, iEndAt do |
| 191 | + local fLoadCurrent = self.short.qLoadHistory[i] |
| 192 | + fLoadSum = fLoadSum + fLoadCurrent |
| 193 | + if fLoadMax < fLoadCurrent then |
| 194 | + fLoadMax = fLoadCurrent |
| 195 | + end |
| 196 | + end |
| 197 | + |
| 198 | + --for i = 1, 10 do |
| 199 | + AMutils:QueuePush(self.tHistory.qLoadAvg, fLoadSum / iTotalSeconds) |
| 200 | + AMutils:QueuePush(self.tHistory.qLoadMax, fLoadMax) |
| 201 | + --end |
| 202 | + |
| 203 | + if AMutils:QueueCount(self.tHistory.qLoadAvg) > oAM.iHistoryCleanupAt then |
| 204 | + self.tSessions.bRequestCleanup = true |
| 205 | + end |
| 206 | +end |
| 207 | + |
| 208 | +function AMdata:SaveRemainingData() |
| 209 | + local iToSave = self.tSessions.iTick % oAM.iHistoryGroupSeconds |
| 210 | + if iToSave == 0 then |
| 211 | + return |
| 212 | + end |
| 213 | + |
| 214 | + local iEndAt = self.short.qLoadHistory.last |
| 215 | + local iStartAt = math.max(self.short.qLoadHistory.first, iEndAt - iToSave + 1) |
| 216 | + |
| 217 | + for i = iStartAt, iEndAt do |
| 218 | + table.insert(self.tHistory.tRemaining, self.short.qLoadHistory[i]) |
| 219 | + end |
| 220 | +end |
| 221 | + |
| 222 | +function AMdata:ConvertCrbDateToTS(sDate) |
| 223 | + local x = {} |
| 224 | + for s in string.gmatch(sDate, "%d+") do |
| 225 | + table.insert(x, s) |
| 226 | + end |
| 227 | + return os.time({year=x[3], month=x[1], day=x[2], hour=x[4], min=x[5]}) |
| 228 | +end |
| 229 | + |
| 230 | +_G.AddonsManagerStuff.AMdata = AMdata |
| 231 | + |
0 commit comments