Wednesday, March 30, 2016

WCF maxes CPU when waiting on _TransparantProxyStub_CrossContext function during call

Leave a Comment

I'm getting heavy CPU usage when making calls to Cisco's AXL SOAP API using WCF. I start by creating a service model clientbase using generated classes from wsdl. I'm using basichttpbinding and transfermode as buffered. When executing a call, the CPU maxes out, and a CPU profile shows that 96% of CPU time is at _TransparentProxyStub_CrossContext@0 from clr.dll that is called after calls such as base.Channel.getPhone(request);. More correctly, the call maxes out the CPU core that the process is running on.

Here's a snip of the client creation from the wsdl generate

[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public partial class AXLPortClient : System.ServiceModel.ClientBase<AxlNetClient.AXLPort>, AxlNetClient.AXLPort {      public AXLPortClient()     {     }      public AXLPortClient(string endpointConfigurationName) :              base(endpointConfigurationName)     {     }      ... 

This is how I create the client:

public class AxlClientFactory : IAxlClientFactory {     private const string AxlEndpointUrlFormat = "https://{0}:8443/axl/";      public AXLPortClient CreateClient(IUcClientSettings settings)     {         ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;         ServicePointManager.Expect100Continue = false;                                var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);         basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;          basicHttpBinding.MaxReceivedMessageSize = 20000000;         basicHttpBinding.MaxBufferSize = 20000000;         basicHttpBinding.MaxBufferPoolSize = 20000000;          basicHttpBinding.ReaderQuotas.MaxDepth = 32;         basicHttpBinding.ReaderQuotas.MaxArrayLength = 20000000;         basicHttpBinding.ReaderQuotas.MaxStringContentLength = 20000000;          basicHttpBinding.TransferMode = TransferMode.Buffered;         //basicHttpBinding.UseDefaultWebProxy = false;          var axlEndpointUrl = string.Format(AxlEndpointUrlFormat, settings.Server);         var endpointAddress = new EndpointAddress(axlEndpointUrl);         var axlClient = new AXLPortClient(basicHttpBinding, endpointAddress);         axlClient.ClientCredentials.UserName.UserName = settings.User;         axlClient.ClientCredentials.UserName.Password = settings.Password;         return axlClient;     } } 

The generated wsdl code for the AXL API is very large. Both initial and subsequent calls have the CPU issue, although subsequent calls are faster. Is there anything else I can do to debug this issue? Is there a way to reduce this high CPU usage?

Update

A bit more info with the bounty:

I've created the C# classes like so:

svcutil AXLAPI.wsdl AXLEnums.xsd AXLSoap.xsd /t:code /l:C# /o:Client.cs /n:*,AxlNetClient 

You have to download the wsdl for Cisco's AXL api from a call manager system. I'm using the 10.5 version of the API. I believe the a major slowdown is related to XML processing. The WSDL for the api is huge with the resulting classes making a 538406 lines of code!

Update 2

I've turned on WCF tracing with all levels. The largest time difference is in the process action activity between "A message was written" and "Sent a message over a channel" in which nearly a full minute passes between these two actions. Other activities (construct channel, open clientbase and close clientbase) all execute relatively fast.

Update 3

I've made two changes to the generated client classes. First, I removed the ServiceKnownTypeAttribute from all the operation contracts. Second, I removed the XmlIncludeAtribute from some of the serializable classes. These two changes reduced the file size of the generated client by more than 50% and had a small impact on test times (a reduction of about 10s on a 70s test result).

I also noticed that I have roughly 900 operation contracts for a single service interface and endpoint. This is due to the wsdl for the AXL API grouping all operations under a single namespace. I'm thinking about breaking this up, but that would mean creating multiple clientbases that would each implement a reduced interface and end up breaking everything that implements this wcf library.

Update 4

It looks like the number of operations is the central problem. I was able to separate out operations and interface definitions by verb (e.g. gets, adds, etc) into their own clientbase and interface (a very slow process using sublime text and regex as resharper and codemaid couldn't handle the large file that's still 250K+ lines). A test of the "Get" client with about 150 operations defined resulted in a 10 second execution for getPhone compared to a previous 60 second result. This is still a lot slower than it should be as simply crafting this operation in fiddler results in a 2 second execution. The solution will probably be reducing the operation count even more by trying to separate operations further. However, this adds a new problem of breaking all systems that used this library as a single client.

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment