Friday, May 28, 2004

A Great Smartphone "Getting Started" Guide (and it's free!!)

I recently got a new i-mate™ Smartphone2 to replace my reliable but aging Nokia 5110. I haven't done a lot of embedded development for Windows CE yet, so even with all the wizards and options in Visual Studio.NET, I wasn't 100% sure where to start. Luckily, I remembered Dr. Neil Roodyn's Smartphone site, and was very impressed with the quality of his "Getting Started with Smartphone Development" e-book available for download from his site.

While Apress has a great range of books on embedded development, I wanted a simple and quick get-me-going reference, and this one hit the spot.

Thursday, May 27, 2004

More On The New CLR Hosting Interface

In my previous "Five things I love about VS 2005 (from a performance perspective)" post, I briefly mentioned some of the new hosting interfaces in .NET 2.0. I've been digging into these interfaces a bit deeper for a piece I'm doing on Visual Studio 2005 that the Australian .NET MVPs are producing under the inspiration and guidance of Nick Randolph. Some of the more interesting interfaces that have been added include:

IHostMemoryManager


This interface, when implemented by the host, allows the host to control memory allocation requests. In .NET 1.1, memory requests are handled internally by the CLR, which calls directly into the Window's VirtualAlloc function when more heap space is required. The IGCHostControl interface that exists in .NET 1.x allowed the host to deny the CLR requests for memory allocation above a certain limit (see my book for a more detailed disucssion of this, including a sample implementation), but IGCHostControl has no ability to interact in a fine-grained manner with the CLR to govern memory allocation. The full interface definition for IHostMemoryManager is:

interface IHostMemoryManager : IUnknown
{
HRESULT CreateMalloc([in] BOOL fThreadSafe,
[out] IHostMalloc **ppMalloc);


HRESULT VirtualAlloc([in] void* pAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect,
[in] EMemoryCriticalLevel eCriticalLevel,
[out] void** ppMem);


HRESULT VirtualFree([in] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD dwFreeType);


HRESULT VirtualQuery([in] void * lpAddress,
[out] void* lpBuffer,
[in] SIZE_T dwLength,
[out] SIZE_T * pResult);


HRESULT VirtualProtect([in] void * lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flNewProtect,
[out] DWORD * pflOldProtect);


HRESULT GetMemoryLoad([out] DWORD* pMemoryLoad,
[out] SIZE_T *pAvailableBytes);


HRESULT RegisterMemoryNotificationCallback([in] ICLRMemoryNotificationCallback * pCallback);

}

For those familar with IDL, it is quite apparent the level of fine-grained control that it offers. I haven't build a sample host that implements this interface yet (stay tuned for this ...), but I'd imagine IHostControl.SetAppDomainManager would be the way to hook this interface up.

ICorSvcWorker



ICorSvcWorker, shown in full below, allows the CLR host to interact with the native image cache. As .NET matures and native images start to become significantly more optimized than their JIT equivalent, native images will become a bigger deal, and this interfaces allows the host much simpler control over native images compared to enumerating modules loaded in memory or using the poorly documented Zap APIs.

typedef enum

{
ScenarioDefault = 0x0, // No special scenario flags

ScenarioAll = 0x1, // All scenarios (used to indicate all configurations)

ScenarioDebug = 0x2, // Debuggable code

ScenarioDebugOptimize = 0x4, // Optimized code with debug infomration

ScenarioProfile = 0x8, // Used for profiling (enter/leave notifications)

ScenarioShared = 0x10, // Shared code

ScenarioTuningDataCollection = 0x20, // Used to gather IBC data

ScenarioLegacy = 0x40 // Follow hard dependencies only

} OptimizationScenario;



interface ICorSvcWorker : IUnknown

{
HRESULT OptimizeAssembly(
[in] BSTR pAssemblyName,
[in] BSTR pApplicationName,
[in] OptimizationScenario scenario,
[in] SAFEARRAY(BSTR) loadAlwaysList,
[in] SAFEARRAY(BSTR) loadSometimesList,
[in] SAFEARRAY(BSTR) loadNeverList,
//HostConfig hostConfig,
[out] BSTR *pNativeImageIdentity
);


HRESULT DeleteNativeImage(
[in] BSTR pAssemblyName,
[in] BSTR pNativeImage
);


HRESULT DisplayNativeImages(
[in] BSTR pAssemblyName
);


HRESULT GetCorSvcDependencies(
[in] BSTR pAssemblyName,
[out] ICorSvcDependencies **pCorSvcDependencies
);


HRESULT Stop(
);

}

Saturday, May 22, 2004

Instrumentation - My Constant Saviour

When I'm doing a development project, it is typically a 3 - 6 month engagement doing a custom application for some specialized task. The last one of these I did (which I finished last week) was a tool that converted vector images to raster images and also processed and extracted some specific data out of the vector images. After trialling a number of components, including Lead Tools (which performed quite badly), CorelDRAW 12 was settled upon. CorelDRAW has a rich automation interface, handled all the vector formats required (SVG and CGM up to v5), had great raster image production quality, and was pretty cheap (~AUS750).

As anyone who has done any automation will tell you, lots of things can go wrong when you are talking to another process. Anticipating this, I sprinkled my code with a plethora of Trace.WriteLine statements, about one for every 5 lines of code, and at least one per exception handler. On my last day on the project, the inevitable failure-that-only-occurs-in-production error occurred during a final test run, and the image conversion process stopped working. Everything appeared fine, but images where never being moved into the completed folder. Instead of panicking, or trying to get a debugger attached or installed on the production machine, I simply got the client to fire up DebugView off a USB memory stick, and we could immediately see that the line that wrote a log record to the database was failing due to some SQL Server log file issue. We changed the connection string in the configuration file, and did the test run with logging to a separate database.

End result: I got out of there on time, and the client was happy.

The morale of the story is use the best instrumentation strategy you can, and never trust a client or manager who says instrumentation isn't need. Microsoft's Enterprise Instrumentation Framework is great for server-side apps, but has a very weak deployment story that makes it unsuitable for client side applications. Log4NET looks good, but I haven't used it in a production app. More and more, I've grown tired of managers scratching themselves trying to decide between the various options, and I've stuck with the reliable, always-available Trace.WriteLine. With TraceListener-derived types, Trace.WriteLine scales from in-debugger output right up to enterprise solutions like Microsoft Operations Manager (MOM).

I owe many finish-the-project-on-time moments to this one method.

Sunday, May 16, 2004

Windows XP Service Pack 2 - Get on top of it now!

Last week I did a presentation for the .NET user group that I run with Dan Green in Sydney. I was surprised by the unhappiness of a lot of the attendees about the SP2, and the overall consensus of those that spoke up was that SP2 wasn't a Good Thing. Maybe those that loved SP2 were being real quiet, but the criticisms of the anti-SP2 crowd are certainly not without merit, so I though it would be worth addressing them. The main criticisms were:


  1. Too much code will be broken.

  2. Calling this upgrade a "Service Pack" is misleading.

  3. No one told me Windows was going to change like this.

  4. Its too big.



My reaction/ response was:

  1. Start testing your apps right now to avoid this. The company where I'm currently consulting isn't the most cutting-edge development house (they still ship some 16-bit apps), but we've gone through SP2 testing there. Is most cases, changing Windows Firewall settings will be sufficient to keep apps working correctly, and as these settings can be pushed out to all the Windows boxes in an enterprise using Group Policy, those who invest is some preparation will be fine. For home users, most firewall related breakages can be corrected by the user responding in the affirmative to the prompt that comes up from the firewall when an app starts or opens a port

  2. This is true to some extent, but many network admins (and particularly those that don't keep up with their profession and don't know about SP2) won't go out and install an "Option Pack" or "Security Upgrade". Calling it SP2 is more likely to get the software out onto more boxes, which is ultimately a good thing

  3. That's why I'm writing this, and that's why every Microsoft conference I've been to over the last six months has covered SP2. I think Microsoft are also considering some type of campaign to improve SP2 awareness, and for developers, keeping up with things like this is your job.

  4. I would expect SP2 to be on every CD that ships on a magazine cover in the free world. 280MB is too big for those on dial-up, but the CD will also be available from most Microsoft regional offices at some nominal postage cost. SP2 uses delta compression technology to make post-SP2 patches smaller, so this issue is addressed going forward.



The slide deck from my presentation is available on-line, and this contains a list of resources for those interested in checking out SP2.

Wednesday, May 12, 2004

Five things I love about VS 2005 (from a performance perspective)

Generics



Boxing was the scourge of value type performance, and in some of the tests I did
for Maximizing
.NET Performance
, the performance hit of boxing was well over an order of
magnitude.  Generics eliminate this problem, and this will be a huge win for all
.NET programmers lucky enough to use a language that exposes generics.


GC.AddMemoryPressure



In .NET 1.x, a type author had no effective way of telling the garbage collector
how much non-managed memory resources were kept alive by the presence of a
particular object.  Take a database connection.  Having one of these objects
around and open is a considerable drain on general system resources, and if they
are being leaked, we'd generally like to have more garbage collections to
prevent resource exhaustion.  The problem is that a database connection object
use only a couple of dozen bytes of managed memory, and will exert very little
pressure on the GC.  AddMemoryPressure can be used to give the CG a hint that a
particular object uses a lot more resources than its managed footprint would
indicate, and should be given special treatment when deciding on collection
frequncy.


.NET 2.0



As with every major release, many small imperceptible improvements combine to
produce a significantly faster experience.


Improved and expanded runtime hosting options



Hosting the CLR inside even the most performance-sensitive applications becomes
feasible with the extra fine-grained control offered by the new hosting
interfaces.  If its good enough for Yukon …


MSBuild



Being able to hook into things like the compile process at a very low level will
allow clean performance optimizations that
we haven't even dreamt up yet.


Eating your own dog food (eventually …)

I did a series of articles on SQL Server Reporting Services recently for Australian Developer, and was thrilled when I realized that the whole thing was written in .NET. It feels like Microsoft has taken a long time to start eating there dog food on this one, particularly for groups that don't deal with external developers to the same extent as the tools team.

Longhorn certainly delivers on the promise of managed code ubiquity. Now for Office ...