<enebo[m]>
I dno't recall how 15 as starting length in createByteList in lexer came about
<lopex>
yeah, but it might be many small strings too
<enebo[m]>
I am really just wondering how much we overcommit here and it looks like 80% of the time
<enebo[m]>
but bytelist has a cost if you start to small and the string is larger
<enebo[m]>
lopex: I increased this from 6 to 15 at the same time I stopped intern some ident strings
<enebo[m]>
I feel this would only reduce number of grows by 1 in strings > 15
<enebo[m]>
which is 20% of the strings
<enebo[m]>
going to use science! well be a little hacky and consider strings created during a rails app start
<enebo[m]>
OMGZ I forgot bytelist is does not use a scaling factor
<lopex>
enebo[m]: change it to some larger arbitrary value
<lopex>
so the chance of misinterpreting gets lower
<enebo[m]>
buffer.append(c); // O_o
<enebo[m]>
this might be significant
<enebo[m]>
StringTerm and no doubt HeredocTerm calls append(byte) n times for a n length() string which will call grow(1) n times
<enebo[m]>
so my default of 15 hid the cost by making 80% of all things fit by default
<enebo[m]>
OTOH this never shows up in profiling I guess we will see
<enebo[m]>
This also could explain how poor oj dump speed is using ByteList as the backing store
<enebo[m]>
I thought it was just because of constant bounds checking but if it has no scaling factor I am dump a 15k json file with 15k System.arraycopys
<lopex>
I'm only getting more stupid as I age wrt those things
<enebo[m]>
I dumped all str lengths made and it is fascinating how small most strings are
<enebo[m]>
I guess Ruby encourages interpolation enough where each fragment is generally small
<lopex>
otoh, did we see any perf bump once java moved to compact strings ?
<enebo[m]>
gem list is unaffected by just making the array a lot larger but I don't like this and rails will definitely make a lot more strings
<enebo[m]>
anyways I will play with this tomorrow
<enebo[m]>
add in a scaling factor and maybe also do inlined CR calc instead of walking the string a second time
<headius[m]>
Is that a heap histogram or an allocation profile?
<enebo[m]>
the latter I have thought about in the past but I will talk to Kevin before I attempt it
<enebo[m]>
it is stringterm bytelist sizes
<enebo[m]>
I made the histogram looking at only that
<headius[m]>
But this is from a heap snapshot, yes? live objects?
<enebo[m]>
only other thing which is doing this is heredoc itself which will typically be larger strings
<enebo[m]>
this is from rails s and killing it
<enebo[m]>
I made this from printlns
<headius[m]>
Okay so it is all allocations
<enebo[m]>
all allocations of normal strings in stringterm
<enebo[m]>
so very specific thing
<headius[m]>
I believe RubyString imposes a growth factor when growing the ByteList
<headius[m]>
So that end of things may be better
<headius[m]>
1.5x or something
<enebo[m]>
yeah and this has nothing to do with RubyString and happens before it ever is actually a string
<enebo[m]>
it is the parser reading strings in the lexer and not even the only path just the most common one
<enebo[m]>
dinner though...this is unneeded churn even if I cannot measure much
<headius[m]>
Yeah, I was just wondering if we should be looking harder at ByteList in other allocation profiles too
<enebo[m]>
possibly
<enebo[m]>
I am definitely going to look around
<enebo[m]>
anything which does an append directly is a suspect
<enebo[m]>
what the hell
<enebo[m]>
there is a growth factor in here
<lopex>
I wonder, since ralloc in java is new and copy it sohuld be quite easily localized by tools by this pattern
<enebo[m]>
I am seriously confused now
<enebo[m]>
newSize >> 1
<lopex>
this way we could learns about reallocs
<lopex>
is it not ?
<enebo[m]>
lopex: I was super confused I did not see the newSize + (newSize >> 1) so everything I said above is not an issue from a growth factor issue
jrafanie has joined #jruby
jrafanie has quit [Client Quit]
<enebo[m]>
The choice of 15 may be a bad default though for StringTerm strings
<headius[m]>
Yeah
<lopex>
enebo[m]: where would you see that ?
<lopex>
I'm confused
<enebo[m]>
in grow()
<headius[m]>
StringBuffer defaults to 16
<enebo[m]>
it could be where the number came from
<headius[m]>
But it's also only used if someone plans to mutate
<headius[m]>
Could be
<enebo[m]>
I bet I just did the histogram befoer but for gem list
<enebo[m]>
80% requires no grow() so that is pretty nice
<headius[m]>
Right-sizing some of these BLs could give us free memory reduction
<enebo[m]>
well that was why I was looking
<lopex>
headius[m]: also aggressive cow could trigger more barriers
<enebo[m]>
but I don't want to trafe-off any percieved startup for that
<lopex>
since those like ampty strings for diffferent encodings might be accessed
<enebo[m]>
especially since memory problems are not actually in the heap at all right now
<lopex>
potentially changed
<enebo[m]>
so far most memory improvementsd have no effect on startup so I just want to continue the trend
<enebo[m]>
when I say most I express doubt in that measuring wall clock is a bit noisy
<lopex>
and all that bit flipping in flags
<enebo[m]>
but after all the changes if anything we may be a tiny bit faster
<lopex>
it's a mess
<enebo[m]>
anyways dinner for reals now
<lopex>
headius[m]: and all those potentiall leaks for arrays we talked about years ago
<headius[m]>
Yeah
<lopex>
I think it's the first cow we shoudl get rid of
<lopex>
it could help gc
<headius[m]>
It wouldn't be too difficult to remove copy on write and try some things out
* rtyler
waves
<lopex>
what things ?
<headius[m]>
Yeah possibly
<lopex>
just remove the cow
<headius[m]>
I'm sure we're screwing up some object age metrics by keeping these backing arrays around
<headius[m]>
I mean things likely to hit arrays hard, like any typical Ruby application. Just see how bad the allocation curve looks, if it looks bad at all
<lopex>
but it's hard to measure
<lopex>
well, impossible
<lopex>
like hmm
<lopex>
imagine a pathological benchmark
<headius[m]>
Why impossible? If the heap is significantly bigger, that tells us something. If applications run slower or faster, that tells us something too
<lopex>
fill an array with some distinct objects
<lopex>
make a slice
<lopex>
operate on them
<headius[m]>
Primary concern for me is always real applications versus synthetic benchmarks. Obviously we can show a performance hit for things like heavy array slicing
<lopex>
yeah I know
<headius[m]>
I guess the corollary to this is that I have no idea how common it is too heavily slice up an array
<headius[m]>
That is always been the case we bring up when we discussed removing copy on write, but do we really know it's a problem?
<headius[m]>
Only we and MRI do COW for Array
<lopex>
no standard metrics
<lopex>
er, no data I mean
<lopex>
and mri does more now
<headius[m]>
Yeah
<lopex>
since it packs small strings in unions
<lopex>
so it's like 4x improvements just on allocations
<lopex>
that extra 1x was on java meta data :P
<lopex>
but mri in single alloc can to whle string indeed
<lopex>
*do
<lopex>
I forgot at what state their gc is
<lopex>
but hat surely helps
<lopex>
headius[m]: btw I'm running a semimportant production jruby app on a docker now
<lopex>
so I'd be interested on a state of those images
<headius[m]>
We could pack very small strings into the header
<lopex>
like longs ?
<lopex>
or/and unsave ?
<lopex>
*fe
<headius[m]>
Yeah
<lopex>
we have lots of int though without unsafe
<lopex>
er
<lopex>
hash only I guess
<lopex>
and flags
<lopex>
wuld we know how aligned RubyString fields are on comon platforms ?