user372724
user372724

Reputation:

Some questions on DLR call site caching

Kindly correct me if my understanding about DLR operation resolving methodology is wrong

DLR has something call as call site caching. Given "a+b" (where a and b are both integers), the first time it will not be able to understand the +(plus) operator as wellas the operand. So it will resolve the operands and then the operators and will cache in level 1 after building a proper rule.

Next time onwards, if a similar kind of match is found (where the operand are of type integers and operator is of type +), it will look into the cache and will return the result and henceforth the performance will be enhanced.

If this understanding of mine is correct(if you fell that I am incorrect in the basic understanding kindly rectify that), I have the below questions for which I am looking answers

    a) What kind of operations happen in level 1 , level 2 
    and level 3 call site caching in general
     ( i mean plus, minus..what kind)

    b) DLR caches those results. Where it stores..i mean the cache location

    c) How it makes the rules.. any algorithm.. if so could you please specify(any link or your own answer)

    d) Sometime back i read somewhere that in level 1 caching , DLR has 10 rules,
 level 2 it has 20 or something(may be) while level 3 has 100. 
If a new operation comes, then I makes a new rule. Are these rules(level 1 , 2 ,3) predefined?

    e) Where these rules are kept?

    f) Instead of passing two integers (a and b in the example), 
        if we pass two strings or one string and one integer, 
       whether it will form a new rule?

Thanks

Upvotes: 3

Views: 987

Answers (1)

Dino Viehland
Dino Viehland

Reputation: 6486

a) If I understand this correctly currently all of the levels work effectively the same - they run a delegate which tests the arguments which matter for the rule and then either performs an operation or notes the failure (the failure is noted by either setting a value on the call site or doing a tail call to the update method). Therefore every rule works like:

   public object Rule(object x, object y) {
       if(x is int && y is int) {
             return (int)x + (int)y;
       }
       CallSiteOps.SetNotMatched(site);
       return null;
    }

And a delegate to this method is used in the L0, L1, and L2 caches. But the behavior here could change (and did change many times during development). For example at one point in time the L2 cache was a tree based upon the type of the arguments.

b) The L0 cache and the L1 caches are stored on the CallSite object. The L0 cache is a single delegate which is always the 1st thing to run. Initially this is set to a delegate which just updates the site for the 1st time. Additional calls attempt to perform the last operation the call site saw.

The L1 cache includes the last 10 actions the call site saw. If the L0 cache fails all the delegates in the L1 cache will be tried.

The L2 cache lives on the CallSiteBinder. The CallSiteBinder should be shared across multiple call sites. For example there should generally be one and only one additiona call site binder for the language assuming all additions are the same. If the L0 and L1 all of the available rules in the L2 cache will be searched. Currently the upper limit for the L2 cache is 128.

c) Rules can ultimately be produced in 2 ways. The general solution is to create a DynamicMetaObject which includes both the expression tree of the operation to be performed as well as the restrictions (the test) which determines if it's applicable. This is something like:

public DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg) {
  return new DynamicMetaObject(
       Expression.Add(Expression.Convert(target, typeof(int)), Expression.Convert(arg, typeof(int))),
       BindingRestrictions.GetTypeRestriction(target, typeof(int)).Merge(
           BindingRestrictions.GetTypeRestriction(arg,  typeof(int))
       )
  );
}

This creates the rule which adds two integers. This isn't really correct because if you get something other than integers it'll loop infinitely - so usually you do a bunch of type checks, produce the addition for the things you can handle, and then produce an error if you can't handle the addition.

The other way to make a rule is provide the delegate directly. This is more advanced and enables some advanced optimizations to avoid compiling code all of the time. To do this you override BindDelegate on CallSiteBinder, inspect the arguments, and provide a delegate which looks like the Rule method I typed above.

d) Answered in b)

e) I believe this is the same question as b)

f) If you put the appropriate restrictions on then yes (which you're forced to do for the standard binders). Because the restrictions will fail because you don't have two ints the DLR will probe the caches and when it doesn't find a rule it'll call the binder to produce a new rule. That new rule will come back w/ a new set of restrictions, will be installed in the L0, L1, and L2 caches, and then will perform the operation for strings from then on out.

Upvotes: 4

Related Questions