PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label code-generation. Show all posts
Showing posts with label code-generation. Show all posts

Tuesday, November 1, 2022

[FIXED] Why is my System.Linq.Expressions code-gen slow at runtime and how can I make it faster?

 November 01, 2022     c#, code-generation, generics, lambda, performance     No comments   

Issue

I am trying to implement a function that returns functions that calculate the vectors' scalar product. It should be implemented via generics, but it seems possible only by generating code in the run time. Read several docs about code generation by building expression trees and this is what I have written so far:

public static Func<T[], T[], T> GetVectorMultiplyFunction<T>()
    where T : struct
{
    ParameterExpression first  = Expression.Parameter(typeof(T[]), "first" );
    ParameterExpression second = Expression.Parameter(typeof(T[]), "second");
    ParameterExpression result = Expression.Parameter(typeof(T)  , "result");
    ParameterExpression index  = Expression.Parameter(typeof(int), "index" );

    LabelTarget label = Expression.Label(typeof(T));

    BlockExpression block = Expression.Block(
        new[] { result, index },
        Expression.Assign( result, Expression.Constant(0) ),
        Expression.Assign( index , Expression.Constant(0) ),

        Expression.Loop(
            Expression.IfThenElse(
                Expression.LessThan( index, Expression.ArrayLength( first ) ),
                Expression.Block(
                    Expression.AddAssign( result, Expression.Multiply( Expression.ArrayIndex( first, index ), Expression.ArrayIndex( second, index ) ) ),
                    Expression.Increment( index )
                ),
                Expression.Break( label, result )
            ),
            label
        )
    );

    return Expression
        .Lambda<Func<T[], T[], T>>( block, first, second )
        .Compile();
} 

This builds without problem but takes forever to run tests. I have a hard time wrapping my head around the subject. So I don't know what exactly went wrong.

This is a piece of tests that this method is used:

[Test]
public void GetVectorMultiplyFunctionReturnsFunctionForLong()
{
    var first = new long[] { 1L, 2L, 3L };
    var second = new long[] { 2L, 2L, 2L };
    var expected = 1L * 2L + 2L * 2L + 3L * 2L;
    var func = CodeGeneration.GetVectorMultiplyFunction<long>();
    var actual = func(first, second);
    Assert.AreEqual(expected, actual);
}

Solution

After some debugging in Linqpad, the problem isn't that your dynamic method is "slow" (it isn't), the problem is that the method contains an infinite-loop that never exits.


From what I can tell, your GetVectorMultiplyFunction method is meant to do something like this, if it were written in C# directly:

static T[] VectorMultiply<T>( T[] first, T[] second )
    where T : struct
{
    T     result = default(T);
    Int32 index  = 0;
    
    while( true )
    {
        if( index < first.Length )
        {
            result += first[index] * second[index];
            index++;
        }
        else
        {
            return result;
        }
    }
}

...however there's a few major bugs in your code:

  • ParameterExpression result = Expression.Parameter(typeof(T)  , "result");
    ParameterExpression index  = Expression.Parameter(typeof(int), "index" );
    
    • These two lines should use Expression.Variable, not Expression.Parameter as result and index are not method parameters, but method locals.
  • Expression.Assign( result, Expression.Constant(0) )
    
    • This doesn't work because result is typed as T, but Expression.Constant(0) is typed as Int32 (because the 0 literal is an Int32 literal.
    • Change it to use default(T), like so:
      Expression.Assign( result, Expression.Constant( default(T) ) ),
      
  • LabelTarget label = Expression.Label(typeof(T));
    
    • Change the above to this:
      LabelTarget breakLabel = Expression.Label("break");
      
  • Here's the main bug and the cause of the infinite-loop:

    Expression.Increment( index )
    

    The above does increment index, but it doesn't reassign the incremented value back to the index local, so it's the same thing as doing this in C#:

    while( true ) {
        if( index < first.Length )
        {
            result += first[index]  * second[index];
            index + 1;       // <-- *DANGER, WILL ROBINSON!*
        }
        else
        {
            break;
        }
    }
    
    • See the problem? Doing index + 1 never actually increases index, so index < first.Length is always true so the while loop never stops.
    • The fix is to change it to index += 1 (or ++index or index++) like so:
      Expression.PostIncrementAssign( index )
      
  • The last issue is that your outermost Expression.Block's last expression should be the result local, which is equivalent to doing return result; in C#.

    • So immediately after the Expression.Loop() call inside your Expression.Block( variables, expressions ) call-site, just add result as another parameter.
    • I'll confess that I still don't yet fully understand how the breakLabel = Expression.Label("break"); expression works or what it even does, but it works for me...
  • I've also added calls to Console.WriteLine(String, Object) as a quick substitute for the lack of step-through debugger support in dynamic-methods - that's how I noticed that index was always 0.

    • Screenshot proof:

This code works for me in .NET 6:

public static Func<T[], T[], T> GetVectorMultiplyFunction<T>()
    where T : struct
{
    var writeLineMethod = typeof(Console).GetMethod( nameof(Console.WriteLine), new[] { typeof(String), typeof(Object) })!; // print-style debugging ugh // `public static void WriteLine(string format, object? arg0)`
    
    ParameterExpression first  = Expression.Parameter( type: typeof(T[])  , name: "first"  );
    ParameterExpression second = Expression.Parameter( type: typeof(T[])  , name: "second" );
    ParameterExpression result = Expression.Variable ( type: typeof(T)    , name: "result" );
    ParameterExpression index  = Expression.Variable ( type: typeof(Int32), name: "index"  );
    
    LabelTarget breakLabel = Expression.Label("break");
    
    BlockExpression block = Expression.Block(
        variables  : new[] { result, index },
        expressions: new Expression[]
        {
            Expression.Assign( result, Expression.Constant( default(T) ) ),
            Expression.Assign( index , Expression.Constant(          0 ) ),
            
            Expression.Loop(
                body: Expression.Block(
                    Expression.IfThenElse(
                        test  : Expression.LessThan( index, Expression.ArrayLength( first ) ),
                        ifTrue: Expression.Block(
                            Expression.AddAssign( result, Expression.Multiply( Expression.ArrayIndex( first, index ), Expression.ArrayIndex( second, index) ) ),
                            Expression.PostIncrementAssign( index ),
                            
                            Expression.Call( writeLineMethod, Expression.Constant( "result: {0}" ), Expression.Convert( result, typeof(Object) ) ),
                            Expression.Call( writeLineMethod, Expression.Constant( "index : {0}" ), Expression.Convert( index , typeof(Object) ) )
                        ),
                        ifFalse: Expression.Break( breakLabel )
                    )
                ),
                @break: breakLabel
            ),
            result
        }
    );
    
    Func<T[],T[],T> f = Expression
        .Lambda< Func<T[],T[],T> >( block, first, second )
        .Compile();
    
    return f;
}

Here's a screenshot of the func returning the correct expected result, as well as the Console.WriteLine output with the logged values of result and index. The method runs instantly (and the Expression.Lambda<>(...).Compile() call only took 0.5ms on my machine too):

enter image description here



Answered By - Dai
Answer Checked By - Robin (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Wednesday, May 18, 2022

[FIXED] How can tweaks to existing methods in an auto-generated C# partial class be persisted?

 May 18, 2022     c#, code-generation, overriding, partial, sealed     No comments   

Issue

I am working with Visual Studio Coded UI Tests, and wish to persist tweaks to the generated code.

The code is generated as a partial class in UIMap.cs and UIMap.Designer.cs, and so I know one solution would be to create a method with a slightly different name, such as myMethod_persist in UIMap.cs and use this instead of myMethod in UIMap.Designer.cs, which will be overwritten every time the source is regenerated.

This however seems very messy, and so what I'd prefer, is to instead override myMethod in UIMap.cs. This way the interface is not complicated with lots of gumph, and I don't have to remember to change every instance of myMethod in calling code to myMethod_persist

Unfortunately when it comes to C# I'm a bit of a noob, and don't even know if this is possible.

Basically what I want is this:

[UIMap.Designer.cs]
partial class myClass
{
    public override void myMethod( int a ){ somethingHorrible(int a); };
}

[UIMap.cs]
partial class myClass
{
    public sealed override void myMethod( int a ){ somethingNice(int a); };
}

But I know that the sealed and override keywords are usually used with derived subclasses classes, not partial classes. Is this possible? If not then what would be my best alternatives?


Solution

If you have no control over the auto-generation itself (ie. a framework or 3rd party generator) your options are somewhat limited. The two approaches that come to mind are to modify the generated code--which as you noted is not practical for changes that are significant and perhaps accumulating over time--and/or to create a derived class and use that instead of using the auto-generated class directly (assuming you control the code which would be using them, which seems likely).

A derived class (inheriting the auto-generated class) would be able to use override or new in the method declarations you want to replace. However, there are a lot of caveats to this approach as well. You can only "override" a method that was delcared as virtual in the base class (or was itself an override of another underlying virtual base, etc). You can also replace a method with a "new" one in the derived class, but the other code in the base class will not know about your "new" version and will not call it (whereas they will call your "override" because they know the method to be virtual). There are also issues of accessiblity; your derived class won't have access to private members of the base class.

But for some set of things you want to do it could work. In some cases you might have to tweak the auto-generated code slightly such as adding the keyword "virtual" or changing "private" members to "protected" so that you can access them from your derived class.

Added: Of course, you can also add new members to the original generated class in your own permanent file for the same partial class, and this code would have access to the class's private members. That can be another way to give your derived class access to the private members, such as by creating a protected property to wrap access to a private member field. If you didn't need to make changes to existing methods you wouldn't necessarily need to create a derived class, but your example talked about wanting to "override" methods from the auto-generated code, so presumably they already exist there.

Also note that a Designer file--such as for a Form or UserControl--does not usally get completely overwritten, so cautious changes outside the core generated code (eg. not inside the "Windows Form Designer generated code" region) can be made (and are persisted). For example, it is sometimes necessary to add a call to your own custom clean-up method in the Dispose(...) method in the Designer file.



Answered By - Rob Parker
Answer Checked By - Senaida (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Friday, April 22, 2022

[FIXED] How to bake a plugin controller without scaffolding in cakephp 2.3

 April 22, 2022     cakephp, cakephp-2.3, code-generation, php, plugins     No comments   

Issue

When I bake my plugin controller, it always generate with scaffolding.

class MyController extends PluginAppController {

/**
 * Scaffold
 *
 * @var mixed
 */
        public $scaffold;

}

Anyone help me to bake plugin without scaffolding.


Solution

From your main app directory in the command line enter

  1. cake bake controller -p <pluginname>
  2. select the controller you're baking
  3. Answer the scaffolding question with default (no)

    Would you like to use dynamic scaffolding? (y/n)
    [n] >



Answered By - mk97
Answer Checked By - Cary Denson (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home
View mobile version

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing