ƒ-- title: libProfile -- author: Gavin Stewart -- desc: v1.0 TIC-80 profiling library -- script: lua -- input: keyboard function scanline(lineNum) profile:start('scanline') profile:stop('scanline') end function OVR () profile:start('OVR') profile:stop('OVR') profile:update(14, 1) end function TIC () profile:start('TIC') cls(0) profile:stop('TIC') end -- Profile tool for TIC-80/lua -- Copyright (c) 2018 Gavin Stewart -- Licensed under the terms of the -- MIT License here: -- https://opensource.org/licenses/MIT profile = { -- Private variables version = '1.0', data = {}, frame = 0, output = { text = '', calc = {}, calcFrames = 0, calcRam = 0, calcTime = 0, frames = 0, period = 1, -- in frames pause = false, }, shade = { state = 'hide', -- show|hide offset = 0, } } -- Profile public methods -- profile:start(name) -- @param name <= 13 chars function profile:start (name) name=string.sub(name,1,13) if not self.data[name] then self.data[name]={} self.data[name].acc = 0 self.data[name].count = 0 end self.data[name].start=time() end -- profile:stop(name) -- @param name <= 13 chars function profile:stop (name) name=string.sub(name,1,13) if not self.data[name] or not self.data[name].start then self.data[name]={} self.data[name].acc = 0 self.data[name].count = 0 trace('profile:stop called before start for: '..name.."\n") return end self.data[name].acc = self.data[name].acc + time() - self.data[name].start self.data[name].count = self.data[name].count + 1 end -- profile:update(fgColour, bgColour) -- Call once per frame from end of -- TIC() or OVR(). Press ` key to -- see output on screen. -- @param fgColour Optional palatte -- index else defaults to 15 -- @param bgColour Optional palatte -- index else defaults to 0 function profile:update (fgColour, bgColour) fgColour = fgColour or 15 bgColour = bgColour or 0 self.frame = self.frame + 1 -- Show or hide with ` key if keyp(44,0,30) then if self.shade.state == 'show' then self.shade.state = 'hide' self.output.pause = false else self.shade.state = 'show' end end -- Pause output with p key (while show) if keyp(16,0,30) then if self.shade.state == 'show' then if self.output.pause == true then self.output.pause = false else self.output.pause = true end end end -- Less output.period with [ key if keyp(39,0,7) then if self.shade.state == 'show' then self.output.period = self.output.period - 1 if self.output.period < 1 then self.output.period = 1 end end end -- More output.period with ] key if keyp(40,0,7) then if self.shade.state == 'show' then self.output.period = self.output.period + 1 if self.output.period > 999 then self.output.period = 999 end end end profile:updateText() -- Send output text to trace() -- even if output not shown to screen. if keyp(20,0,30) then trace(self.output.text, fgColour) end -- Shade up or down local _, outputLines = self.output.text:gsub('\n', '\n') if self.shade.state == 'show' and self.shade.offset < 0 then self.shade.offset = self.shade.offset + 2 elseif self.shade.state=='hide' and self.shade.offset >= -6*outputLines then self.shade.offset = self.shade.offset - 2 end -- Display output print(self.output.text, 1, self.shade.offset+1, bgColour, true) print(self.output.text, 0, self.shade.offset, fgColour, true) end -- Profile private methods. -- Use acc(umulated) time and call -- count to build calc table in acc -- order. function profile:updateCalc() self.output.calc={} self.output.calcTime = time()/1000 self.output.calcFrames = self.output.frames self.output.calcRam=collectgarbage('count') -- Calculate sum of scanline+Ovr+Tic self.data['scnln+OVR+TIC'] = { acc = 0, count = 0, } for i, n in pairs({'scanline', 'OVR', 'TIC'}) do if self.data[n] then self.data['scnln+OVR+TIC'].acc = self.data['scnln+OVR+TIC'].acc + self.data[n].acc self.data['scnln+OVR+TIC'].count = self.data['scnln+OVR+TIC'].count + self.data[n].count end end -- Build calc table, order by acc for name in pairs(self.data) do table.insert(self.output.calc, {name=name, acc=self.data[name].acc, count=self.data[name].count}) -- Zero acc and count self.data[name].acc = 0 self.data[name].count = 0 end function compAcc(a,b) return(a.acc > b.acc) end table.sort(self.output.calc, compAcc) end -- Build up output.text from -- calc table. function profile:updateText() -- Recalculate at period intervals if self.output.pause==false then self.output.frames = self.output.frames+1 if self.output.frames >= self.output.period then profile:updateCalc() self.output.frames = 0 end else self.data = {} self.output.frames = 0 end -- Header local pauseState if self.output.pause == true and self.frame%60 > 30 then pauseState = ' ' else pauseState = ':' end self.output.text = string.format( "Profile v%3s (C)2018 Gavin Stewart\n", self.version).. "----------------------------------------\n" local now = time()/1000 self.output.text = self.output.text .. string.format( "%02.0f:%05.2f %3dfrms | %02.0f%1s%05.2f %10.1fKB\n", now//60%100, now%60, self.output.period, self.output.calcTime//60%100, pauseState, self.output.calcTime%60, self.output.calcRam ) -- Profile table self.output.text = self.output.text .. "--------+--------+-------+--------------\n".. " calls | totl ms| ms/frm| name \n".. "--------+--------+-------+--------------\n" -- Output ordered calc table for i, t in ipairs(self.output.calc) do self.output.text = self.output.text .. string.format( "%7d | %6.1f |%6.2f | %-13s \n", t.count, t.acc, t.acc / self.output.calcFrames, t.name) end -- Help footer self.output.text = self.output.text .. "--------+--------+-------+--------------\n".. " ` show [] +-frms (p)ause (t)race\n" end 0 D$404mNJN…L04e$ÐFHuqaY}ÎÒ},…•¡mª,Òª™mÂÊÚÔ^ÞîÖ‚ GIF89aðˆw!ÿ NETSCAPE2.0!ùÿ,ðˆ‡ÚÔ^ D$4ÿ  Áƒ 4(�!Á„#*|q¡Ä‹32ò­cÈ¥i;ŽÝûõk’ µª^ùü¸Ûí¨«ÿ»må¡V#—f*~qÞõ§?¿Çù´+}ùKï'Ôoú~üþïY·W^ú˜~O�ÆB˜*Qƒ(_ø=à‚vèᇠ†(âˆ$–hâ‰(¦¨â‡ ±æÜ‹>­'c‹0ª7£‹1Ò˜#Ž6êØ#�7ÖäŽBú8¤�V˜ä’Æ×¤]O&(¥’QRéä•Pb9%“ZZ™å—[VÉ%˜^†ÙåŠh¦©æšl¶éæ›pÆ Ü�Íňž�/ )c‡Ðýèj†ÉÕ\P}¢hR[‚~DOÜmUS…É—˜fXYFiž»]eÕp‹¾Ø§r¨­E©P+ågƒ¼‰¶æ¦’úÑn˜‰ÿª[k6Ùy¡Vö[žÌe¶n‡–úlI1öÛ¤¦—§l~µb�VhÔŠ´Y¯�ݤ+­¼úVÜ­¦]6Óƒ!ñUì¬t ZÕ¢Ö>‹›‚=Ûn°q9º\t‘‹o²�á‹)¡ÞÑÖ׸¾J•T€6Ep�Âækð½jš4YlY>&Û´e^˜¡©YÚG¦F 6YŸNªi8,ƒ‰ù_ÈW޼¥š,£ºŸÆ&#,çÍ8笳ˆ…6 gÏ; häÐ@]dÑH­4‘LûÙô‘Pý´ÔHª|¦Õ?<¦™c=[×W‡�µØ\—�ñÖg‹)§Ín²½¢ÛAÇ-÷ÜtÇ-W¢(]„·CŠZÿ´Fzæ]7š_®¿{ãŠ^wÜesb +¨§ÌYPÍV¬‹Qe¾çà�5Úá„�w2Oloú.ÞÖ} ¾:©ªÒ¢e)H�k+½™�Þ_½’e¹Äž{s¤•D0¹0=¾|¸\Q îò¥ç®[qâúZ«ï�*�M;¯wwß#9[ö¦£~0ú¸å…ÜÀ⪟Ûyg¯0÷¨*è5…bäßÊgêJÉ$Àˆ<¨dþÙOÇHvÀÏHDB< ÇðGÁ Zð‚zÓÙßN´A ¾jjIáÒœF¨…°„T3áU(ÂV�liƒaeÀFC³¡m†6ôÚÙ´¦Ãöð‡2\›Îÿà–""zðˆHLb›žÃ¸ÏÝ…gÐqVEŽB¼¾I±$!JÜœ¸rEÙuω.�¤2#««TĈ*ã„(s°4^êwc”Hì¼Ø(g!çn’yÔ¶ å9y±å�Há—W:³+s�ÈU¯:�äÆG—ù5쌛ÉéÔ¢©Ò�j:{Ìdh°#¼H¡+™›”¬©¹CZR2©C£mÔ•©T>ðW%i°U2;¨£˜¶ÖµÃÕ²_¸„$‹Î"�ÄÍQŽÀ$Ý쌙»ô˜Ç’zTuÊ3H>‚Çaäs ËjøÀÅlcÝt‰ÈT3¶™óIr ‚ ¨@�ìœäT’^˜0ó=1‹…ÒbÁÈÿ·~&…ƒ'Ñ¢ý’*ú¼K˜R#z\ 8@ÆVrL�[…(mÙ§Qö|“ ™UÈâ S¢ íÖ1[‡H�þŽ3’„%ç`õîf¼¥¥©<|Ò&WmlhºÚÉœN–ÕcOk\%žY)å“}Î kWC&”˜‘«©kGŠFts¿dbµÖóÌûÝl›6숾™¡pªdœe% ˆÎ²²ó;� ‡ä¤)šòSú¤¢1ëŠEd21£JDIQÍ(U>9”)„uª`­™GÄ~ÊmÊú#c+Rn)Öo–=žOKJ¼t´”Æ» a�Ø¢’R~†Ýé.ŧSY®ö³¨u¤odCÙ©ÿŒµO¥jÂ6+XÝÞ+˜…u¤/¯YÛ”Á5eÞlÙËf&NåžM¬l�ç’Š+X<Ýs˜xͧ^³kÝÊù•]¥.¦¾õØ�&Ö^¼EædËÞôÚ˳‡o®`{Ú^fÖ[î�ßáKÓ˾ÖX÷•ï\ð‹P¡ Õ9ý5)#]{<úŽÔ–˜é—€ÁrÛüÚ×·þ noö[ køƒÀ#ï„Ùª?·‘ÖÎ�.sÏšbµ­x�î¤ÙˆgLã{gû$QŽ=˜ÂŸ�…(ü±�W8dùÈEΡ {ÈÃ%;ylÜô¡ ›e VùÉË…Ó‰Q´eoÚøË`öÝ>jؾ]‡Ì‡ÌàÏÌÜÇåÿ¨5z‹k´V_F©÷r�Š*ËNBÎZÃ�3ŸA9_ÖSœ‘œØ£,Ãè^¾g¤Gâ�¨€:×—Hï-Q)¬T÷Òyº�v³Œ¦9ÍÆ‘‡¿ÛR( Ù.‘ú3öƒÞŽQû› §0§Ž£\J¿lšÛ;³de¹;H��×f%I©—¾^ÖI;U�VÁ–ê·ð0J`²“6`ô?uv[‘ uZ<@þé%ÔPÊÇj–å£Ì‡�ÁV+XÃ<Ä.ÓûÞøÎ·¾÷Íï~ûû߸ÀNð‚üàO¸ÂÎð†;üá�¸Ä'NñŠ[üâϸÆ7ÎñŽ{üã ¹ÈGNò’›üä(LO¹ÊWÎò–»üå0�¹ÌgNóšÛüæ8ϹÎwÎóžûüç@ºÐ‡Nô¢ýèHOºÒ—Îô¦;ýéP�ºÔ§Nõª[ýêXϺַÎõ®= ;