Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
EnTerr
Roku Guru

Re: Bandwidth

"RokuDale" wrote:
I don't believe it has anything to do with available memory.

"Before it crashes, things start taking a long time. Looking at my traces entries, things that normally take 10 to 20 ms start taking close to a second. Sometimes in my message loop, I will get 2 or 3 video position events queued at the same time. The video position events are set at 1 per second. That says that I didn't get control back to check the queues for quite awhile." <-- this sounds awfully like an interpreter gasping for memory and calling GC way too often.

Oh, only if RunGarbageCollector() would return the amount of free memory! But no, "you ain't gonna need that", said some bearded guru apparently. So instead of simply looking at that to diagnose memory issues, instead now we have to choose between bloodletting, emetics or boar-bile enema in attempts to improve the four humors.
0 Kudos
greubel
Visitor

Re: Bandwidth

Tried RMP across Wifi but it gets "connection dropped" and kills the video. Connected up to the LAN and it appears to work. Tried it once. Need to try it more. This brings up another question, I noticed the "Connection Dropped" message before with RMP and put some code in my channel to do more or less the same BUT I revised it just to keep track internally. I wanted to just capture the event with EnableLinkStatusEvent but it never triggers. So I had to poll it with GetLinkStatus(). When I get these, it reconnects usually between 5 to 30 seconds. The connection may come and go but as long as the video has enough data, it appears to play fine to the user. SO why put out the message in RMP and kill the video ?

Saw some forum posts for delay time in wait(msg) loops. Upped the delay to 10 ms to give more dead time and also added RunGarbageCollector() once a minute to see if it shows anything. The Garbage collector COUNTS bump up, 3 per minute. Spent a lot of time trying to figure out where these were coming from, no go. Also the time to "collect", runs anywhere from 50 to 120 ms normally. Except when it gets ready to crash, then they jump to 2 and 3 seconds and the counts are about the same as normal. My starting counts were 2059 and ended with 2137 when it crashed last.

Trying a test now with all my tracing off to see if it might squeek by. But without tracing it's harder to guess where the problem might be.

Need a memory allocation routine ! Does anyone know the actual memory allocation for an integer, string and the two array types ?
I think I figured out before, that a integer (32 bits) actually took 32 bytes of storage.
0 Kudos
RokuDale
Visitor

Re: Bandwidth

RMP doesn't use LinkStatusEvents, I found it too unreliable. I wait for for http errors from the player. I do not have any code in there yet that tries to auto-reconnect to the dlna server and continue running. I left that up to player firmware.
0 Kudos
RokuDale
Visitor

Re: Bandwidth

If you are actively trying to manage your memory usage, look through your code to see if you have variables that might be referencing objects, strings, etc. that you are no longer using. Set those variables to invalid. This will reduce reference counts and free the memory. Also if you are writing anything to you /tmp directory, you might need to clear that out as well.
I know that in RMP I put jpeg thumbnails there that I've extracted from exif data. Also album art data I've pulled off the net goes in there. Depending on how many photos you've looked at, that can fill up ram.
Don't know if that helps you out or not.
dale
0 Kudos
EnTerr
Roku Guru

Re: Bandwidth

"greubel" wrote:
... The Garbage collector COUNTS bump up, 3 per minute. Spent a lot of time trying to figure out where these were coming from, no go. Also the time to "collect", runs anywhere from 50 to 120 ms normally. Except when it gets ready to crash, then they jump to 2 and 3 seconds and the counts are about the same as normal. My starting counts were 2059 and ended with 2137 when it crashed last.

Well... you can try to interrupt it and in console do "bsc"... <ducks*>
capture that and "c"ontinue, then few minutes later repeat, sort and then diff the two, observe what's growing.

It keeps sounding like memory issue but it's not the number of instances that kills you. Last month i did, let me check... well, 2XS can fit somewhere within 250k-500k range of instances (a hodge-podge of strings, [] and {}'s) before croaking. But even one instance with unreasonable size can eat the memory. Plus, if tmp:/ is a tmpfs...

(*) i know. i am not sure Roku can survive listing 2k instances but desperate times call for desperate measures
0 Kudos
greubel
Visitor

Re: Bandwidth

RMP doesn't use LinkStatusEvents, I found it too unreliable. I wait for for http errors from the player. I do not have any code in there yet that tries to auto-reconnect to the dlna server and continue running. I left that up to player firmware.

In my msg loop, I just report the status of the connection if it changes to my trace. When the connection drops, the box will reconnect in 5 to 30 seconds and nobody will notice. But if you display a message and close the screen, the video player also closes. I don't know why they cascade the close event down to the video player. We should be able to create an ImageCanvas over the video player, display whatever and then close it.

Running second test without tracing. The first one worked.
UPDATE: second test failed.
0 Kudos
greubel
Visitor

Re: Bandwidth

This is starting to get me down ! Today, tried turning off all unnecessary network activity. No help.
Why does the Roku buffer up so much video ? After the movie started, I shut off the server and it still played for 10 minutes ! That's a lot of video buffers.

I did come up with a subroutine to display your memory allocations with totals.
Still a work in progress, need to define the actual size of each object type to get the total size used.
You can call it via eval( dump() ) or a subroutine before a planed crash.


Sub Dump()
g = GetGlobalAA()
Mem( g, 0, {} )
End Sub

Function Mem(g as object, lev as integer, p as object) as integer

l = string(lev*2," ")+"* "
if Type(g) = "roAssociativeArray"
for each n in g
v = g.Lookup( n )
t = Type( v )
if t = "roAssociativeArray"
z = 0
for each j in v
z = z + 1
end for
s = 32 * z
? l n " = " t z " Items"
mem( v, lev+1, p )
elseif t = "roArray"
s = 32 * v.Count()
? l n " = " t v.Count() " Items"
mem( v, lev+1, p )
elseif t = "String" or t = "roString"
s = Len(v)
? l n " = " t " " s " ["+v+"]"
elseif t = "ByteArray" or t = "roByteArray"
s = v.Count()
? l n " = " t " " s
elseif t = "Integer" or t = "roInteger" or t = "roInt"
s = 4
if n = invalid
? l t " [" v "]"
else
? l n " = " t " [" v.ToStr() "]"
end if
elseif t = "Boolean" or t = "roBoolean"
s = 4
if n = invalid
? l t " [" v "]"
else
? l n " = " t " [" v "]"
end if
elseif t = "Float" or t = "roFloat"
s = 4
? l n " = " t " [" v "]"
elseif t = "Double" or t = "roDouble"
s = 8
? l n " = " t " [" v "]"
elseif t = "Invalid" or t = "roInvalid"
s = 4
? l n " = " t
else
s = 0
? "* " n " Unknown type = " t
end if

if p.Lookup( t ) = invalid
p.AddReplace( t, 1 )
else
p.AddReplace( t, p.Lookup( t )+1 )
end if
if p.Lookup( "total" ) = invalid
p.AddReplace( "total", s )
else
p.AddReplace( "total", p.Lookup( "total" )+s )
end if
end for
else
for i=0 to g.Count()-1
v = g[i]
t = Type( v )
if t = "roAssociativeArray"
z = 0
for each n in v
z = z + 1
end for
s = 32 * z
? l i.ToStr() " = " t z " Items"
mem( v, lev+1, p )
elseif t = "roArray"
s = 32 * v.Count()
? l i.ToStr() " = " t v.Count() " Items"
mem( v, lev+1, p )
elseif t = "String" or t = "roString"
s = Len(v)
? l i.ToStr() " = " t s " ["+v+"]"
elseif t = "ByteArray" or t = "roByteArray"
s = v.Count()
? l i.ToStr() " = " t s
elseif t = "Integer" or t = "roInteger" or t = "roInt"
s = 4
? l i.ToStr() " = " t " [" v.ToStr() "]"
elseif t = "Boolean" or t = "roBoolean"
s = 4
? l i.ToStr() " = " t " [" v "]"
elseif t = "Float" or t = "roFloat"
s = 4
? l i.ToStr() " = " t " [" v "]"
elseif t = "Double" or t = "roDouble"
s = 8
? l i.ToStr() " = " t " [" v "]"
elseif t = "Invalid" or t = "roInvalid"
s = 4
? l i.ToStr() " = " t
else
s = 0
? "* " n " Unknown type = " t
end if

if p.Lookup( t ) = invalid
p.AddReplace( t, 1 )
else
p.AddReplace( t, p.Lookup( t )+1 )
end if
if p.Lookup( "total" ) = invalid
p.AddReplace( "total", s )
else
p.AddReplace( "total", p.Lookup( "total" )+s )
end if
end for
end if

if lev = 0
tot = p.Lookup("total")
p.Delete( "Total")
? "*"
items = 0
for each e in p
cnt = p.Lookup(e)
? e " = " cnt
items = items + cnt
end for
? "*"
? "Allocated " tot " bytes - total items " items
? "*"
end if
return lev

End Function
0 Kudos
EnTerr
Roku Guru

Re: Bandwidth

@greubel - hmm, how did you come with those sizes for the types?
I bet that intrinsic types (Invalid, Integer, ...) take different amount of space than boxed/proper objects (roInvalid, roInteger, ...).
Am also doubtful about roArray/roAA taking 32 bytes per each element, seems too much.

Btw the function will get into infinite loop if there are cycles (e.g. `h = {}: h.next = h`). Sometimes cyclic (graph) structures are useful but unfortunately there is no way to walk those in B/S because - survey says - one cannot check if 2 objects of any type are identical.
0 Kudos
greubel
Visitor

Re: Bandwidth

Since no one will define the allocation sizes. I'm allocating a number of the same object type and then doing a "bsc" to get the allocation by taking a best guess from the offsets between the memory addresses. Not a good method but it does give some idea.
0 Kudos
RokuMarkn
Visitor

Re: Bandwidth

The video player has a fixed size buffer, about 50-60 MB depending on the firmware and model. It keeps the buffer as full as possible to avoid rebuffering during brief network outages or slowdowns.

I've mentioned this previously, but I want to reiterate, that there is really no meaning to "amount of free memory" in a Linux system. After the system has been running for a while, all pages of memory contain something. Some of the pages are copies of data in Flash and can be discarded without loss of data, so when the system needs memory, it discards the contents of what it thinks is the page least likely to be needed again. As the system gets lower on memory, it needs to do this page reuse stuff more and more often until the system is thrashing, spending most of its time copying pages out of Flash and less time actually executing code. The point where the system becomes unusable is a fuzzy line somewhere down this road, although at some point it will become slow enough that the watchdog will trigger a reboot.

--Mark
0 Kudos