0

I'm hoping one of you can assist me with diagnosing a stack trace of a web service call. I am in the process of trying to figure out what is causing high CPU usage on our web services, so I have taken a few memory dumps when the CPU is spiking higher than 80%. After running through the dump files (and picking off the easy fixes) I am left with one that is particularly interesting.

bcryptPrimitives!accumulate+54 
bcryptPrimitives!create_modulus+200 
bcryptPrimitives!create_modulus_select_arithmetic+2d 
bcryptPrimitives!rsa_import+254 
bcryptPrimitives!MSCryptImportKeyPair+132 
bcrypt!BCryptImportKeyPair+179 
rsaenh!LocalPopulateBCryptPublicKey+206 
rsaenh!CPImportKey+346 
cryptsp!CryptImportKey+163 
clr!StrongNameTokenFromPublicKey+1a5 
clr!CAssemblyName::SetProperty+218 
clr!BaseAssemblySpec::CreateFusionName+32b 
clr!BaseAssemblySpec::GetFileOrDisplayName+4e 
clr!AssemblyNameNative::ToString+164 
[[HelperMethodFrame_1OBJ] (System.Reflection.AssemblyName.nToString)] System.Reflection.AssemblyName.nToString() 
mscorlib_ni!System.Reflection.AssemblyName.get_FullName()+9 
RazorEngine.Compilation.CompilerServiceBase.CurrentDomain_AssemblyResolve(System.Object, System.ResolveEventArgs)+124 
mscorlib_ni!System.AppDomain.OnAssemblyResolveEvent(System.Reflection.RuntimeAssembly, System.String)+a4 
clr!CallDescrWorkerInternal+83 
clr!CallDescrWorkerWithHandler+4a 
clr!MethodDescCallSite::CallTargetWorker+251 
clr!AppDomain::RaiseAssemblyResolveEvent+d6860 
[[GCFrame]] 
clr!AppDomain::TryResolveAssembly+82 
clr!AppDomain::PostBindResolveAssembly+d1 
clr!`AppDomain::BindAssemblySpec'::`1'::catch$5+d7 
MSVCR120_CLR0400!CallSettingFrame+20 
MSVCR120_CLR0400!_CxxCallCatchBlock+f5 
ntdll!RcConsolidateFrames+3 
clr!AppDomain::BindAssemblySpec+ef7 
clr!AssemblySpec::LoadDomainAssembly+1ec 
clr!AssemblySpec::LoadAssembly+1b 
clr!AssemblyNative::Load+304 
[[HelperMethodFrame_PROTECTOBJ] (System.Reflection.RuntimeAssembly._nLoad)] System.Reflection.RuntimeAssembly._nLoad(System.Reflection.AssemblyName, System.String, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMarkByRef, IntPtr, Boolean, Boolean, Boolean) 
mscorlib_ni!System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(System.Reflection.AssemblyName, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMark ByRef, IntPtr, Boolean, Boolean, Boolean)+d2 
mscorlib_ni!System.Reflection.Assembly.Load(System.Reflection.AssemblyName)+3b 
System_Xml_ni!System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type, System.String, System.Xml.Serialization.XmlSerializerImplementation ByRef)+1a6 
System_Xml_ni!System.Xml.Serialization.XmlSerializer.FromMappings(System.Xml.Serialization.XmlMapping[], System.Type)+59 
System_ServiceModel_ni!System.ServiceModel.Description.XmlSerializerOperationBehavior+Reflector+SerializerGenerationContext.GenerateSerializers()+dd 
System_ServiceModel_ni!System.ServiceModel.Description.XmlSerializerOperationBehavior+Reflector+SerializerGenerationContext.GetSerializer(Int32)+74 
System_ServiceModel_ni!System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.AddHeadersToMessage(System.ServiceModel.Channels.Message, System.ServiceModel.Description.MessageDescription, System.Object[], Boolean)+be 
System_ServiceModel_ni!System.ServiceModel.Dispatcher.OperationFormatter.SerializeRequest(System.ServiceModel.Channels.MessageVersion, System.Object[])+e2 
System_ServiceModel_ni!System.ServiceModel.Dispatcher.ProxyOperationRuntime.BeforeRequest(System.ServiceModel.Dispatcher.ProxyRpc ByRef)+1d1 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannel.PrepareCall(System.ServiceModel.Dispatcher.ProxyOperationRuntime, Boolean, System.ServiceModel.Dispatcher.ProxyRpc ByRef)+85 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannel.Call(System.String, Boolean, System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[], System.TimeSpan)+27f 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage, System.ServiceModel.Dispatcher.ProxyOperationRuntime)+6c 
System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)+133 
mscorlib_ni!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)+1f4 
clr!CTPMethodTable__CallTargetHelper3+12 
clr!CallTargetWorker2+74 
clr!CTPMethodTable::OnCall+1fb 
clr!TransparentProxyStub_CrossContextPatchLabel+a 
[[TPMethodFrame] (x.Server.WebReferences.x.x.Save)] x.Server.WebReferences.xxx.xxxServiceSoap.Save() 

Our architecture is simple: We have a desktop client, which communicates via WCF to our services. A few of our service calls will then push data through to another system via web services. The stack trace above represents just such a call - from our service to another service.

I am receiving a first chance exception when loading the XmlSerializer (from my research done, this is intended behavior given that if the generated assembly is not found, it will generate one and continue). However, we appear to be receiving this exception for every web service call made. I was under the impression that once the assembly has been generated, it would no longer throw a first chance exception?)

Is this normal behavior for a web service call? To me it appears as though we are generating this assembly every time - which then in turns raises the AssemblyResolveEvent - which in turn then executes the RazorEngine.Compilation resolve event... which at this point is completely unnecessary..

Any thoughts and ideas?

Thanks in advance

  • 1) What is the exact exception being thrown in your first chance exception? 2) Are you using [pre-generated `XmlSerializer` DLLs](https://msdn.microsoft.com/en-us/library/Ee704594.aspx)? – dbc Jul 19 '15 at 04:54

1 Answers1

0

It appears from your traceback that the the method that is taking all the time is not the method that generates and loads dynamically created XmlSerializer DLLs. Instead the method taking the time is the method that tries to load pre-generated XmlSerializer DLLs.

To see this, check the reference source from XmlSerializer.FromMappings:

    public static XmlSerializer[] FromMappings(XmlMapping[] mappings, Type type) {
        if (mappings == null || mappings.Length == 0) return new XmlSerializer[0];
        XmlSerializerImplementation contract = null;
        Assembly assembly = type == null ? null : TempAssembly.LoadGeneratedAssembly(type, null, out contract);
        TempAssembly tempAssembly = null;
        if (assembly == null) {
            if (XmlMapping.IsShallow(mappings)) {
                return new XmlSerializer[0];
            }
            else {                    
                if (type == null) {
                    tempAssembly = new TempAssembly(mappings, new Type[] { type }, null, null, null);
                    XmlSerializer[] serializers = new XmlSerializer[mappings.Length];

                    contract = tempAssembly.Contract;

                    for (int i = 0; i < serializers.Length; i++) {
                        serializers[i] = (XmlSerializer)contract.TypedSerializers[mappings[i].Key];
                        serializers[i].SetTempAssembly(tempAssembly, mappings[i]);
                    }

                    return serializers;
                }
                else {
                    // Use XmlSerializer cache when the type is not null.
                    return GetSerializersFromCache(mappings, type);
                }
            }
        }
        else {
            XmlSerializer[] serializers = new XmlSerializer[mappings.Length];
            for (int i = 0; i < serializers.Length; i++)
                serializers[i] = (XmlSerializer)contract.TypedSerializers[mappings[i].Key];
            return serializers;
        }
    }

Which calls TempAssembly.LoadGeneratedAssembly:

    /// <devdoc>
    ///    <para>
    ///    Attempts to load pre-generated serialization assembly.
    ///    </para>
    /// </devdoc>
    internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract) 

Loading of run-time XmlSerializer DLLs happens inside GetSerializersFromCache which, as the name suggests, are cached.

If XmlSerializer.FromMappings is taking substantial amounts of CPU time on every call in this specific traceback, perhaps you have some obsolete pre-compiled .XmlSerializers.dll files that you have left on your server (on disk or in the GAC) and need to be cleaned out? On every call .Net could be trying to load them, then finding that version numbers or signatures are mismatched, then throwing an exception, consuming significant CPU time in doing so. Or, if the DLLs are not obsolete, perhaps there is an architecture mismatch?

Community
  • 1
  • 1
dbc
  • 104,963
  • 20
  • 228
  • 340