Advanced programming


There are basically two different techniques for investigating an error or an undesirable behavior of ACComponents:

Influencing

A debugger is hooked into the running process and breakpoints are set at codes where one suspects the error. The advantage of this methodology is that you can observe the program flow, heap and stack step by step. The disadvantage is that all threads are stopped and this is not desirable in productive operation and even dangerous in time-critical systems. 

You can do debugging with three different tools, which will be discussed later:

 

Not influencing ("Print debugging")

Non-influencing methods mean that the cause of the error can be found in the program code on the basis of the memory or object status and traces. The advantage of this methodology is that the process continues. The disadvantage is that the search for the program error is more time-consuming. Object states can be viewed in iPlus using the following three tools:


We recommend Microsoft Visual Studio® for developing your own assemblies and for debugging your program code in the development phase. Since the installation of Visual Studio requires a larger hard disk space and the internet is often blocked in production environments, we recommend the use of dnSpy for production environments. 

If you have created your project according to our sample projects, you can start the *.client.exe directly from Visual Studio and the debugger is immediately active. If you only compiled your assembly and added it to the iPlus installation directory, you have to attach the debugger to the running process.


dnSpy is predestined for debugging in production environments because the installation is very slim.

Proceed as follows to debug the iPlus service or an iPlus*.client.exe:

  1. Start dnSpy with administration rights so that you can also debug the iPlus-service (gip.iplus.service.exe).
  2. Load the required assemblies from the iPlus installation directory by going to the menu item "File->Open" and selecting the appropriate files.
  3. Then open the menu item "Debug->Attach to Process" and select the process you want to debug:

 

  1. In the assembly explorer (left half of the screen) navigate to a method in which you want to set the breakpoint. dnSpy decompiles the IL code and shows you the method in the right code window.
  2. Set the breakpoint with a click of the mouse.

WinDbg is suitable for examining program crashes that have not been catched by the iPlus runtime and have been output in the log file. This scenario can occur

1. Such program crashes are logged using Windows Error Reporting. Look for WER entries in the Windows event viewer that provide information about the dump file created:  

 

2. Then start WinDbg (x64 version) and open the complete memory dump file created by WER, which is usually saved with the ending * .hdmp. The small dump file provides information about the call stack, but you cannot use it to diagnose the entire heap (all objects). If you cannot find the complete memory dump file, you must set the DumpType key to "2 = Full" in the registry and then wait again until the error occurs and WER has created the dump.

3. So that you can see legible callstacks and objects in WinDbg, you must first set the symbol paths where the pdb files are located. To do this, enter the "Symfix command":

.symfix D:\vbIPlus\bin

 4. So that WinDbg can debug .NET applications, the SOS extensions must be loaded (https://docs.microsoft.com/en-us/dotnet/framework/tools/sos-dll-sos-debugging-extension). To do this, enter the "cordll command":

.cordll -ve -u -l

 5. Finally, have the call stack output of all threads with the "EEStackcommand :

!EEStack

 

 

The SOS extensions offer a variety of commands to analyze problems. The main ones are 

  • "!DumpStackObjects"
  • "!DumpHeap"
  • "!DumpObj" and
  • "!DumpMT".

More on this at:

https://docs.microsoft.com/en-us/dotnet/framework/tools/sos-dll-sos-debugging-extension

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-managed-code


With the component explorer you can read and change the network-compatible properties of ACComponent instances (static or dynamic). 

  1. Select an instance in the visualization or process control.
  2. Use the context menu to open the component explorer under menu item "Tools->Component-Explorer".
  3. Press the "Search" button.
  4. In the list on the left select the appropriate instance from which you want to see the properties.
  5. You can read or change the property values ​​in the Value column in the right list.

You cannot see or change local properties with the Component Explorer. You can do this either using the iplus development environment or using the diagnostics dialog:


With the diagnostics dialog you can display all property values ​​of an ACComponent instance.

  1. Select  an instance in the  visualization  or  process control.
  2. Use the context menu to open the diagnostics dialog under the menu item "Tools->Open xxx in diagnostics dialog".
  3. If you open the diagnostics dialog on a client, the ACComponent instances are available as proxy objects. In this case, the diagnostics dialog shows the status of the proxy object as well as the real object (server side).

The diagnostics dialog only shows properties that have been published with the ACPropertyInfo attribute class  or points (references and lists) that have been published with the ACPoint attribute classes. Local and private fields or configuration properties, however, are not. To output this as well, overwrite the method DumpPropertyList:

 

Use the AppendChild() method to add additional field values. In the example above, the local field _SubscribedToWorkCycle was added, which is displayed in the diagnostics dialog as follows:

 


With the debugging techniques listed above and the output of object states during runtime, program errors can be found out, but they are not of any help with performance problems.

Use the component gip.core.autocomponent.RuntimeDump to investigate performance problems that you add as an instance in an application tree. RuntimeDump may only be instantiated once when an iPlus service is started. Therefore, we recommend adding the instance in the service project with the ACIdentifer "VBDump":

Show VBDump in the visualization so that you can execute the following commands via the context menu:

 

Dump CPU usage

This command creates a file with the name "UsageCPU_YYYYMMDD_hhmmss.txt" in the temporary directory (%USERPROFILE%\AppData\Local\Temp) where the message log is also stored. Here is an example file:

This file outputs statistics about all threads that were created with the "gip.core.datamodel.ACThread" class. Therefore, you should only use the ACThread class for thread programming.

  • In the <<< SUMMARY >>> section, the threads are output according to percentage usage.
  • In the <<< DETAILS >>> section, the "Top 20" events that took up the most CPU time are output per thread.
  • Below this, the statistics of all delegate queues are output.
  • In section <<< THREAD-STATES >>> the thread states are output.
  • In the <<< MAPPING MANAGED-Id to NATIVE-Id >>> section, the mapping between the managed thread ID and the "native thread ID" is output. This is useful if you have  observed the behavior of the thread usage with the Process Explorer and you want to match the corresponding .NET thread.

 

Dump Performancelog

This command creates a file with the name "PerfLog_YYYYMMDD_hhmmss.txt" in the temporary directory (%USERPROFILE%\AppData\Local\Temp) where the message log is also stored. Here is an example file:

This file contains usage statistics for all instances that have status-dependent methods. Status-dependent methods are called cyclically by activation via "PABase .SubscribeToProjectWorkCycle()". The execution time of a status-dependent method is logged and output in this performance log.

  • In the <<< SUMMARY >>> section, the status-dependent methods are output according to percentage use.
  • In the <<< DETAILS >>> section, the "Top 20" events that took the most CPU time are output for each method.

 

Enable/Disable Performance-logging

This enables or disables performance logging. To activate it permanently when the service starts,  add the PerfLogConfiguration section in the App.Config file.

 

Dump Delegate-Queues

This command creates a file with the name "DelegateQueue_YYYYMMDD_hhmmss.txt" in the temporary directory (%USERPROFILE%\AppData\Local\Temp) where the message log is also stored. Here is an example file:

This file contains statistics on the status and the degree of utilization of all delegate queues.

 

Restart Delegate-Queue

This command removes all entries from all delegate queues and starts the processing threads again.

 

Dump all subscribed components

This command creates a file with the name "SubscribedComp_YYYYMMDD_hhmmss.txt" in the temporary directory (%USERPROFILE%\AppData\Local\Temp) where the message log is also stored. This file lists all instances whose status-dependent methods are called cyclically because they were activated using "PABase .SubscribeToProjectWorkCycle()".

 

Full Dump

Create an empty text file called "Invoke_Dump.txt" in the iPlus installation directory or in the directory where the iPlus service is executed.

The iPlus service starts to output all application trees including the iPlus application tree in the temporary directory. An XML file with the name "RuntimeDump_ProcId_yyyyMMdd_HHmmss.xml" is created. The XML file contains all instances including all property values ​​and private fields as it is also displayed in the diagnostics dialog.

In addition,  the current call stack of all threads is output in the  message log.

This dump is advantageous if the entire iPlus service hangs and you can no longer send commands to the service from the client. This state only occurs in the rarest of cases, when a specially developed assembly is used that was not programmed thread-safe.

Don't forget to delete the "Invoke_Dump.txt" file from the directory after the XML file has been created!

Here is an example file: