L
Larry Nixon
I was tasked to build a .NET/C# server-side application that'd answer
calls from a modem bank & allow Zmodem uploads. I was given Sax's
SaxComm8 ActiveX component (already paid for & not much else out there
handles Zmodem; also, new Sax.NET framework STILL doesn't offer Zmodem
support yet).
With the help of VS.Net, I got the Interop & AxInterop DLL's generated
& working & thought all was well. That is, until I saw it under load.
Memory was cool, but CPU usage was at 50% with only 1 instance...&
that's WITH Hyperthreading (99% without)!
I then compiled the Sax component into an old Win32 app to test its
performance against .NET & it was a pig as well. But only half as bad
(w/Hyperthreading: 25%; w/o: 50%). So my next task was to attempt to
trim off as much of the 25% overage as was possible, seeing as I
needed to support 8 lines per server (& never a problem on our old
UNIX server running an ANSI C equilavent).
Anyway, after reading Mr. Nick Wienholt's recommendation for a few
other folks suffering similar performance problems here, I decided to
attempt to remove the run-time security checks/"stack walk" by using
the "SuppressUnmanagedCodeSecurityAttribute" attribute on the class
definitions &/or methods that are called frequently within the
generated Interop assemblies/"ActiveX wrappers" (which is supposed to
move the check into link/JIT time, which is supposed to pep things up
a bit).
Of course, this couldn't be straight forward. As Nick puts it: "A
painful exercise that would be trivial if the AxImp utility had an
'/unsafe' option &/or equivalent like the TlbImp utility does". So, I
had to disassemble these assemblies with the ILDASM utility, add the
attribute manually, & then reassemble the DLLs with the ILASM utility.
Here's how it went:
1.) Used ILDasm to generate MSIL source code for the assembly.
C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Bin>
ILDASM .\Interop.SaxComm8.dll /out=.\Interop.SaxComm8.il
ILDASM .\AxInterop.SaxComm8.dll /out=.\AxInterop.SaxComm8.il
This step also produced a RES file since resources were found in the
assembly (which I needed to include later).
2.) Modified the MSIL code with text editor in the "CLASS MEMBERS
DECLARATION" section by adding:
.custom instance void [mscorlib]
System.Security.SuppressUnmanagedCodeSecurityAttribute::.ctor() =
( 01 00 00 00 )
....in every ".class", ".method", ".event", & ".property" I could
(initially, just to see if performance was improved at all).
3.) Recompiled the MSIL using the ILASM compiler. Since a RES file
was generated, it was compiled back into the assembly during this step
using the /resource option on ILASM.
C:\WINNT\Microsoft.NET\Framework\v1.1.4322>
ILASM /DLL /resource=.\Interop.SaxComm8.res
/key=.\EfileReceiver.snk .\Interop.SaxComm8.il
ILASM /DLL /resource=.\AxInterop.SaxComm8.res
/key=.\EfileReceiver.snk .\AxInterop.SaxComm8.il
And...nothing. Bumpkiss. No improvement in speed &/or CPU usage
what-so-ever.
So my question: What am I doing wrong?
Any help in this area is/will be much appreciated. Especially since
there's not much documentation out there dealing with this stuff (IL
attribute tweaks, ActiveX interop, Zmodem & .NET,...was I set up to
fail or what!?!). Thanks.
- Larry
calls from a modem bank & allow Zmodem uploads. I was given Sax's
SaxComm8 ActiveX component (already paid for & not much else out there
handles Zmodem; also, new Sax.NET framework STILL doesn't offer Zmodem
support yet).
With the help of VS.Net, I got the Interop & AxInterop DLL's generated
& working & thought all was well. That is, until I saw it under load.
Memory was cool, but CPU usage was at 50% with only 1 instance...&
that's WITH Hyperthreading (99% without)!
I then compiled the Sax component into an old Win32 app to test its
performance against .NET & it was a pig as well. But only half as bad
(w/Hyperthreading: 25%; w/o: 50%). So my next task was to attempt to
trim off as much of the 25% overage as was possible, seeing as I
needed to support 8 lines per server (& never a problem on our old
UNIX server running an ANSI C equilavent).
Anyway, after reading Mr. Nick Wienholt's recommendation for a few
other folks suffering similar performance problems here, I decided to
attempt to remove the run-time security checks/"stack walk" by using
the "SuppressUnmanagedCodeSecurityAttribute" attribute on the class
definitions &/or methods that are called frequently within the
generated Interop assemblies/"ActiveX wrappers" (which is supposed to
move the check into link/JIT time, which is supposed to pep things up
a bit).
Of course, this couldn't be straight forward. As Nick puts it: "A
painful exercise that would be trivial if the AxImp utility had an
'/unsafe' option &/or equivalent like the TlbImp utility does". So, I
had to disassemble these assemblies with the ILDASM utility, add the
attribute manually, & then reassemble the DLLs with the ILASM utility.
Here's how it went:
1.) Used ILDasm to generate MSIL source code for the assembly.
C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Bin>
ILDASM .\Interop.SaxComm8.dll /out=.\Interop.SaxComm8.il
ILDASM .\AxInterop.SaxComm8.dll /out=.\AxInterop.SaxComm8.il
This step also produced a RES file since resources were found in the
assembly (which I needed to include later).
2.) Modified the MSIL code with text editor in the "CLASS MEMBERS
DECLARATION" section by adding:
.custom instance void [mscorlib]
System.Security.SuppressUnmanagedCodeSecurityAttribute::.ctor() =
( 01 00 00 00 )
....in every ".class", ".method", ".event", & ".property" I could
(initially, just to see if performance was improved at all).
3.) Recompiled the MSIL using the ILASM compiler. Since a RES file
was generated, it was compiled back into the assembly during this step
using the /resource option on ILASM.
C:\WINNT\Microsoft.NET\Framework\v1.1.4322>
ILASM /DLL /resource=.\Interop.SaxComm8.res
/key=.\EfileReceiver.snk .\Interop.SaxComm8.il
ILASM /DLL /resource=.\AxInterop.SaxComm8.res
/key=.\EfileReceiver.snk .\AxInterop.SaxComm8.il
And...nothing. Bumpkiss. No improvement in speed &/or CPU usage
what-so-ever.
So my question: What am I doing wrong?
Any help in this area is/will be much appreciated. Especially since
there's not much documentation out there dealing with this stuff (IL
attribute tweaks, ActiveX interop, Zmodem & .NET,...was I set up to
fail or what!?!). Thanks.
- Larry