Il 06/02/2013 10:19, iMe ha scritto:
>
> But it would postpone the need of solving this right now.
> Maybe later on, when things evolves, we can go back to only one version.
>
I think this is a wise advice.
Also, in the meanwhile we have experimented more (also thanks to the
help of Paul), and discovered that the initial figure of a 50% was
highly overestimated because of the way the test explicitly caused
contention: even when using a single thread to do the loop, the second
thread print loop was still over contending the resource, causing a
delay that wasn't due to pure computation in the other thread.
The final figure is about 10% slowdown with lock/unlock, which is not
negligible, but bearable.
Since that, I have removed a "caution" lock that I added to every "="
Item class C++ operator overload , which are the vast majority in the
engine (the assign() doing double lock with copy and explicitly
one-sided lock copies are just around in the number of 10 or less ), and
that should shape down the figure yet, but I didn't retest atm (and
there may be some place where that leads to crash and requires an
explicit lock, will have to check). However, with that shaped down, the
difference should be something about 5% or less.
Also, in the meanwhile I removed the "Autoexpression" statement and
simplified the tree model. Let me explain:
There are 3 categories of treestep (the PSteps, or atomic VM operations,
which directly represent script constructs):
- Expressions
- Statements
- Syntactic Trees.
The difference between expressions and statements is that an expression
were BOUND to create exactly one value out of its arity; that is, it
MUST take N elements from the stack and then ADD exactly one.
Statements and trees were bound to LEAVE THE STACK as they found it. So,
for instance, the while statement removed the extra element its
expression left on the stack (the true/false item that controls the loop).
Syntactic trees were basically vectors of statements.
The autoexpression was a statement composed of exactly one expression;
so, for instance, this while loop:
while a < 10
printl(a)
a++
end
had a syntree per child, composed of two autoexpression statements, one
being the call expression and the other being the a++
This was fair and nice, but to cut the long story short, I discovered
that it was a bad idea when it comes to dynamic code. You'd like to add
trees to trees, or if you simply have an expression in your hands and
want to add it to a tree, you don't want to have to wrap it in an
autoexpression, and if you have an autoexpression statement around, you
might want to have its expression set directly as a while selector... in
short, it was a hell, not for the engine code itself, but for the
scripters to use the dynamic code approaches.
So, I changed the approach and removed the autoexpression. Now EVERY
TREESTEP is bound to leave a value on the stack, as if it was an
expression; removing it is a duty left to its parent TreeStep, or to the
topmost process code when the process terminates.
This allows to set everything everywhere. For instance, you could set a
treestep as the while selector. Since there is a "exit from step with
value" operator, this can be actually meaningful.
As a result, the ubiquitous extra and non light autoexpression statement
disappeared. This alone brought an improvement of about 15% performance
on raw loops; so, the 10% figure caused by the MT lock is
overcompensated. Not that removing it completely makes no sense, but at
least it looks less of a stretch now.
As a sidenote, the removal of autoexpression is a great help in rules,
which are bound to intercept the result of expressions in their code.
Formerly, autoexpression had to be configured differently if it was in a
interactive compiler or in a rule to yield the exit value of its
expression somewhere (that somewhere was the old "A" register), but now
the rule can just peek the expression value left on the stack, checking
it before discarding it. This should make rules much more easier and
faster to run.
Gian.