[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Help-smalltalk] the test test - a more detailed analysis of image c
From: |
Paolo Bonzini |
Subject: |
Re: [Help-smalltalk] the test test - a more detailed analysis of image contents |
Date: |
Mon, 20 Jul 2009 23:07:56 +0200 |
User-agent: |
Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20090513 Fedora/3.0-2.3.beta2.fc11 Lightning/1.0pre Thunderbird/3.0b2 |
Oops, hit send too early.
Let's see where they come from.
st> (c := b first allOwners) collect: [ :e | e class ]
(OrderedCollection Array Array Array Array Array Array Array Array Array
Array Array Array Array Array Array Array Array Array Array Array Array
Array Array Array Array Array Array Array Array Array Array Array Array
Array Array Array Array Array )
st> (d := c first allOwners) collect: [ :e | e class ]
(Iliad.LabelElement Array Array Array Array Array Array Array )
st> (e := d first allOwners first allOwners) collect: [ :e | e class ]
(Iliad.FormElement Array Array Array Array Array Array Array )
st> (f := e first allOwners first allOwners) collect: [ :e | e class ]
(Iliad.DivElement Array Array Array Array Array Array Array )
st> (g := f first allOwners first allOwners) collect: [ :e | e class ]
(BlockContext BlockContext BlockContext BlockContext Array Array )
st> g first method
[] in OnlineTester.OTFrageWidget>>contents
st> g second method
[] in OnlineTester.OTFrageWidget>>contents
st> g third method
[] in OnlineTester.OTFrageWidget>>contents
st> (h := g first allOwners) collect: [ :e | e class ]
(BlockClosure Array )
st> (i := h first allOwners) collect: [ :e | e class ]
(Iliad.Action Array Array )
st> (j := i first allOwners) collect: [ :e | e class ]
(MethodContext CallinProcess MethodContext MethodContext MethodContext
Association BlockClosure BlockClosure BlockClosure BlockClosure
BlockClosure BlockClosure MethodContext CallinProcess MethodContext Array )
Uh-oh. Quite a few owners, in particular:
st> (j at: 6)
'100058'->an Action
st> (k := (j at: 6) allOwners) collect: [ :e | e class ]
...
st> (k at: 8) class
Dictionary
st> (k at: 8) size
681
681 actions means that using a Dictionary for them was not bad (just a
LookupTable would save memory). Sorry Nicolas for your ActionRegistry. :-)
At least, the number of widgets is what you'd expect:
st> actions := (k at: 8) asArray
st> widgets := (IdentitySet withAll: (actions collect: [:e |e block
receiver]) asArray
st> widgets size
95
st> widgets first frage aufgabe test aufgaben inject: 0 into: [ :o :a |
o + a fragen size ]
95
... and tells us that the dictionary covered the Actions in a single
session as expected (there are 95*27 OTFrageWidgets, 95 per pupil). The
number of actions overall is also correct, so there is no leak here: it
should be roughly 2*number of answers per quiz (the AJAX request
rebuilds the tree and creates new actions), and we get
st> widgets first frage aufgabe test aufgaben inject: 0 into: [ :o :a |
o + (a fragen size * a antworten size * 2) ]
610
Probably sometimes (s)he tried different answers: :-)
st> (widgets collect: [:w| actions count: [:e | e block receiver == w]])
asBag
Bag(6:61 4:1 12:7 8:14 16:1 9:11 )
Again, this is for one pupil only. Indeed we have overall over 16000
actions (as pointed out by Stefan in his first analysis), and these had
better stay in the Dictionary.
Instead for the
st> ((Iliad.Element allSubclasses collect: [:e|e allInstances size])
st> fold: [:a :b|a+b])
64222
elements given the back-of-the-envelope analysis of OrderedCollection
and Dictionary usage, we are spending at least ~32 megabytes out of 90
(probably more like 40-50).
>> IDEAS: I would probably replace the children
OrderedCollection with a tail+next circular linked list
representation. At the beginning tail := nil, if it is not nil
the head is accessible with tail next. Inserting at the tail
is easy. All can be encapsulated into #childrenDo: of course,
and it saves a slot compared to head+tail+next. Consider that
the OrderedCollection also costs two slots (one slot for the OC
instance variable and one slot in the OC itself) so you'll save
memory for the empty OC slots (probably like 100 bytes per
element, totalling ~6 MB).
For the attributes dictionary, reusing the RBSmallDictionary
code should work well, or maybe lazy initalization would be
okay coupled with moving a few attributes out of the dictionary:
st> ((Dictionary allInstances select: [ :e | e size = 1 ])
collect: [ :e | e keys ]) asBag
Bag(Set ('class' ):15498 Set (#created ):1 Set ('for' ):16613
Set (#selectorsMap ):1 )
st> ((Dictionary allInstances select: [ :e | e size = 2 ])
collect: [ :e | e keys ]) asBag
Bag(Set (#expirySeconds #charset ):1 Set (#modified #created
):27 Set ('class' 'id' ):5166 )
st> ((Dictionary allInstances select: [ :e | e size = 3 ])
collect: [ :e | e keys ]) asBag
Bag(Set ('value' 'name' 'type' ):5166 )
st> ((Dictionary allInstances select: [ :e | e size = 4 ])
collect: [ :e | e keys ]) asBag
Bag(Set ('id' #value 'name' 'type' ):11447 )
st> ((Dictionary allInstances select: [ :e | e size = 5 ])
collect: [ :e | e keys ]) asBag
Bag(... Set ('accept-charset' 'class' 'method' 'action'
'onsubmit' ):5166 )
Again, the break-even point is very low. Even storing
5 attributes in all HTML elements including <br> would be
okay, since a Dictionary costs 4 words for flags+class+
size+object pointer, and 1 word for the tally. But of course
value/name/type would be stored only in an InputElement etc.,
only id+class+lazily initialized children would be in the
superclass. At this point, even using a special SmallDictionary
class might be premature optimization...
Since forms will be common in AJAX applications, saving
memory there is nice. Maybe accept-charset could be left into
attributes, but without the #ifAbsentPut: here:
beforePrintHtml [
<category: 'printing'>
self attributeAt: 'action' ifAbsentPut: [self url asString].
self attributeAt: 'method' ifAbsent: [self usePost].
self attributeAt: 'accept-charset'
ifAbsentPut: [self session charset].
...
]
since 99.99% it will be sane to use the default taken from the
session. Probably there are more such cases where #ifAbsentPut:
is used.
Strings are many (mostly from Action ids and from Swazoo's HTTP header
parser), but they consume little memory:
st> String allInstances inject: 0 into: [ :o :i | o + (i size + 7
bitAnd: -8) + 32 ]
347616
A final note regarding Swazoo,
st> a := OrderedCollection allInstances select: [:e | e size = 3 and: [
e first isString ]]
Shows some OrderedCollection ('application/json' ' text/javascript' '
*/*') indeed, but only 43.
Paolo
- Re: [Help-smalltalk] the test test - an experience report, (continued)
- Re: [Help-smalltalk] the test test - an experience report, Paolo Bonzini, 2009/07/17
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/20
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Stefan Schmiedl, 2009/07/20
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/20
- Message not available
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/20
- Message not available
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/21
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents,
Paolo Bonzini <=
- Message not available
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/21
- Message not available
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/21
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/21
- Message not available
- Re: [Help-smalltalk] the test test - a more detailed analysis of image contents, Paolo Bonzini, 2009/07/21
Re: [Help-smalltalk] the test test - an experience report, Stefan Schmiedl, 2009/07/22
Re: [Help-smalltalk] the test test - more data, Stefan Schmiedl, 2009/07/24