Wednesday, December 19, 2012

MS Dynamics AX : Extension Framework


Description

The basic idea of extension framework is that Frameworks, and their Foundation components  must adhere to the Open-Closed principle. This principle states that “software entities should be open to extension, but closed to modification”  this means that extending framework classes should not require changes to the any framework artifacts (classes, tables, Enums,).
There implementation of extension consist of two main steps.

• Designing for extension.
• Design/implement extension classes.




Designing for extension

Designing for extension consist of following steps, 
• Step 1 – Create extension base and extension list classes
• Step 2 – Define delegates
• Step3 – Define initialize method and call from static constructor
• Step 4 – Instantiate and populate the extension list
• Step 5 – Raise the event

Step 1 – Create extension base and extension list classes

Create an abstract base class for extensions. This class will need to provide methods for initialization, event subscription, and accessing the instance of the class being extended. The initialize method of this class will call the subscribe method which must be implemented by the derived extension classes. This provides the mechanism for runtime event subscription and avoids requiring extensions to modify framework artifacts in the AOT.




Create a strongly typed list class. The list is populated at runtime with the current extensions.

Step 2 – Define delegates

Define delegates for extension points. As a general rule pre and post event delegates should be created.
Right click on the class being extended in the AOT. Select New > Delegate. Follow naming guidelines when specifying the delegate name.
  
Below are examples from the SubledgerJournalizer class of delegate signatures for journalizing and journalized event handlers.

 

Step3 – Define initialize method and call from static constructor

An initialize method can be used to instantiate the extension list object and to initialize the state of the object instance. This method should be called from the static constructor of the class that will be extended. In this example the SubledgerJournalizer.

 


Step 4 – Instantiate and populate the extension list

In the static constructor for the extension list class you can use the extension factory to find all the classes that extend your base extension class, instantiate each extension, initialize each extension, and add to the extension list. The below example uses the SourceDocumentExtensionFactory. A more generic extension factory, SysExtensionFactory, is available and should be used instead.

 

Step 5 – Raise the event

Last but not least the events must be raised at runtime. In this case the SubledgerJournalizer.journalize() method does this be calling the journalizing (pre) and journalized (post) event handlers. This will result in each registered subscriber’s event handler method being called.

 


Design/Implement extension classes

• Step 1 –  Implement concrete extension
• Step 2 –Implement event handler
• Step 3 – Implement subscribe() method in derived extension class(es)

Step 1 – Implement concrete extension


Each extension needs to implement a concrete class that derived from the abstract extension base class.
 

Step 2 – Implement event handler

All classes that derive from the abstract extension class will need to implement event handlers. The signature of the event handler must match that of the delegate.


Step 3 – Implement subscribe() method in derived extension class(es)


All classes that derive from the abstract extension class will need to provide an implementation for the subscribe method. This will be called at runtime when the extension is initialized. The implementation of this method will subscribe to the event is being raised by the class being extended.
 


Tuesday, December 11, 2012

Analyzing SQL execution plans in SQL Server Management Studio (SSMS)


Description

It is important that the trace is taken using a data set that has large record counts for the transactional tables the SQL statements are executed against.  The number of records in the tables will impact the SQL execution plans and theexecution times.

Create a trace 

Dynamics AX 2012 : Getting started with tracing


The trace must have the “Bind parameters” option selected in order to get the correct SQL statement from the trace to analyze.

Analyze the trace

Dynamics AX Trace Parser (Quick Trace tool)



Analyze the SQL execution plans

As part of analyzing the trace file it may be determined that a SQL statement has a high “Exclusive Average (ms)” or “Exclusive Total (ms)” and the execution plan should be analyzed.
  • As a general guideline any “Exclusive Average (ms)” greater than 10 ms should investigated.  Some exceptions would be insert and update statements that impact a large number of records, but even those statements should be investigate to ensure optimal execution plans are being achieved.
  • It may also be determined that the average time is not high but the query is executed a large number of times resulting in a high “Exclusive Total (ms)” and the SQL execution plan should be analyzed to ensure each call is as efficient as possible or the number of calls should be reduced if possible.
1. Select the SQL statement in Trace Parser that needs to be analyzed.
  • In the bottom code preview window copy the displayed SQL statement.


  • This is where it is important the “Bind parameters” option was used during the trace capture.  Otherwise, the SQL statement will not have valid parameters specified and will not be executable in SSMS.
2. Start SQL Server Management Studio
  • Connect to the AX database (usually AXDBDEV).
  • Create a new query.
  • Paste the SQL statement from the above trace into the query window.
3. Start analyzing
  • Select Query > Include Actual Execution Plan


  • Execute the query.
  • Select the Execution plan tab in the output window.

    • Analyze each table in the execution plan to verify the predicate and output list for the operation.
      • Hover over the table to view the operation details in the execution plan.

    •  Analyze index scans
      • Look at the predicate for the table being scanned. Determine whether an index exists that would provide an index seek and adjust the SQL statement to utilize that index.
      • SSMS may provide a recommendation to fix the issue, or it may be determined that no index exists to provide better performance.
      • In these cases additional fields may be needed on an existing index or a new index may be needed.
      • Scans may also be caused by a low number of records in the table.  Make sure the table has a larger number of records if it is expected to have large volume in a production environment.  If the table is a setup table it may not be an issue if the execution plan has a scan on that table when the record count is very small and will always be small.
    • Analyze index seeks
      • Look at the seek predicate for the table and determine if the only predicate for the index seek are the Partition field and/or the DataAreaId field.
      • In these cases the index seek will have the same performance as a scan and take into consideration the same updates that would be made to fix a scan operation.
    • Analyze key lookups
      • These are lookups to get additional fields from the record that are not part of the index used to select the record.
      • In some cases key lookups can change the SQL execution plan and may be an expensive operation.
      • Determine whether all the fields in the output list are needed to be returned and trim the return if possible.
      • If the lookup is causing performance issues determine whether an alternate index for the table contains the output list and whether the SQL statement can be adjusted to utilize that index, or determine whether index changes would fix the issue.
    • Items to consider:
      • Even though a new index or changes to an existing index may fix the scenario, consider whether the change can have negative impact on other scenarios.
      • New indexes or adding columns to existing indexs on high volume tables will slow down the write times in SQL and that has to be considered before making the change.
      • Consider whether marking any index columns as an included columns is better for the scenario.  This determination is based on the selectivity of the column and how likely it is to change.

Dynamics AX 2012 : Getting started with tracing



Install the trace parser
1. Go to where you get your daily builds and look in the retail\cd\msi\TraceParser folder
2. Double click onDynamics AX Trace Parser (Quick Trace tool the TraceParser.msi and be agreeable during the install

\\dyn\ax\build\main\<current build>\Retail\CD\msi\TraceParser\TraceParser.msi
\\dcsredfsa\red-ax-core-blds\main\<current build>\Retail\CD\msi\TraceParser\TraceParser.msi
\\dcsvedrep01\Builds\main\<current build>\Retail\CD\msi\TraceParser\TraceParser.msi
\\dcsidcgmasa01\hyd-ax-core-blds\main\<current build>\Retail\CD\msi\TraceParser\TraceParser.msi
Note that you do not need to reinstall each time you move builds. As long as you’re within a couple hundred build numbers of the current version the trace parser usually works.
Capture a trace
1. Launch your client as 'Administrator' by right clicking and perform the action you want to trace once without tracing on (to warm up the caches)
2. Open a developer workspace by pressing CTRL+SHIFT+W
3. Access the Tracing Cockpit through Tools->Development Tools->Tracing Cockpit
4. Review the Events tab for selected events and maximum file size
5. Click "Start Tracing" and specify a full path and name for the file.
6. Perform your scenario.
7. Click "Stop Tracing"

Alternative: Capture a trace via Perfmon (important if you want to profile startup)
1. Save the template file locally (click on link or copy from \\axperformance\lab\TracingTemplate\DynamicsAxTracing.xml)
2. Open perfmon
3. Expand 'Data Collector Sets'
4. Right-click 'User Defined' and select New->Data Collector Set
5. Give it a name such as 'Dynamics Ax Tracing' and leave 'Create from template' checked.
6. Click on 'Browse' and select the template file.
7. Specify a directory to save to.
8. Click Finish
9. Select the name that you have given in the left hand tree, and click on the Play button in the toolbar.
10. Perform  your scenario.
11. Click on the Stop button in the toolbar.

Analyze the trace
Dynamics AX Trace Parser (Quick Trace tooll)

If it doesn’t work - Make sure you have enough hard drive space to hold the trace.

Dynamics AX Trace Parser (Quick Trace tool)



Description

The AX Quick Trace tool provides the ability to capture a trace of the X++ code being executed without needing the Dynamics AX client. 


  • As soon as you start AX Quick Trace a new trace will start running.




  • After you have stopped the initial trace you can change the trace output location and start a new trace.






1. Start the trace parser.
  • If it’s the first time you run it, you will need to select File > Register Database. Type the name of a SQL server and the name of a new database *that does not yet exist* (not your AXDB) and click OK. The trace parser will create the database with that name and set up the tables it needs.
2. File > Import, pick the *.etl files you just captured or plan to analyze.
3. Start analyzing
  • All traces are stored in one file.  You will see the client trace (ax32.exe) and all the server traces (ax32Serv.exe) in the Session lookup.
    • The server session that is typically analyzed is the one with the largest Inclusive time, RPC count and Database calls.
    • The other server sessions are there for items such as security and batch processing.  These items are not always analyzed and can be considered as needed.
  • Select the AX32.exe session.
    • This trace shows you all the client side method calls.
    • Go to the X++/RPC tab.
You can include Name filters to target particular areas.  This filter allows wild carding, such as AssetProposal* that will show all methods that start with AssetProposal.
    • Reduce your RPC counts as much as possible.
In general RPC count reduction should be a primary target for improvement.  An RPC call is expensive and becomes a larger issue once latency is considered in a multi-machine and multi-site production environment where the tier calls become slower.
Remember, the guidance is no more than 8 RPC calls per user interaction.  A user interaction is a button click or a selection change, etc.
    • First sort by Exclusive RPC calls and see what’s causing issues.
Exclusive calls will show you all RPCs that the method generated only.
    • Then sort by inclusive RPC calls and see what’s causing issues.
Inclusive calls will show you all RPCs that the method generated and all the methods that were called by this method generated.
    • Then Exclusive duration, Inclusive duration, etc.
  • Select AX32Serv.exe session.  Remember to choose the one as noted above in the session description.
    • This trace shows you all the server side method calls and the SQL statements.
    • SQL server is the one piece that is not currently scalable.
That means that even though AOS scaling can improve performance, the SQL performance can’t be improved this way.
That is why it is important to look at your SQL counts and improve them as best as you can.
    • First go to the SQL tab.
Sort by count first and see which statements are called the most.
Make sure the queries are selecting data based on alternate keys to ensure the kernel record cache can be utilized where possible.
Keep in mind that aggregate queries are expensive and are not cached by the kernel.
    • Then go to the X++/RPC tab.
Follow a similar analysis pattern as noted for the client session above.
4. General items to consider
  • AX allows tier access to occur easily and without much restriction. This can cause issues with Client -> Server calls and Server -> Client calls.
  • Common system commands you will see in the traces:
ServerUtilLoad : The kernel is caching metadata.  If you see this it is more than likely that you are not analyzing a trace that was taken on a warm system.  The kernel is building the caches and if you run the same trace again the cache building should not occur.
ServerNext : The client issues a SQL statement.
ServerEvalFunc : The client calls a static method marked server or client references an object instantiated on the server.
ServerSetClassLoopDependencies : The client has a reference to an object on the server tier.  Every time the object is referenced an RPC will be encountered.
ClientSetClassLoopDependencies : The server has a reference to an object on the client tier.  Every time the object is referenced an RPC will be encountered.
  • If “your code” is in the top couple pages of data for any of the above analyzing metrics you should work to make it better.
  • If you see something that is not your code and appears wrong please ask the performance team to look at it or log a bug.
  • You can jump to the call stacks causing the calls.
  • Look for random ways to make your stuff faster.
Pull from caches instead of doing round trips.
Cut down on how many times the code is called. 
  • Code structuring to keep in mind.
Which tier is your code running on?
Which tier will your code be called from?
Which tier is the object on that your code is calling?
  • Overall, just look for bad code and fix it.