dotNoted

Icon

Observations of .Net development in the wild

MSDN Library Remarks Section Goodness

I am implementing an instance of IBindingListView for a UI binding scenario. This is a fairly complex undertaking, given also that the list is relying on some dynamically generated runtime code to avoid reflection yet give the list the flexibility in dealing with multiple types. Ultimately, I need knowledge of the properties of the type being displayed in the list, so I can parse the IBindingListView.Filter property string and behave correctly under a call to IBindingListView.ApplySort. Enter System.ComponentModel.PropertyDescriptor and the related type description API.

Since I will be dealing with potentially incorrectly cased values in the filter, I need to know how to get a property out of the PropertyDescriptorCollection regardless of case. There is an .Item property, mmm, ok… but what about case? The ‘Remarks’ section comes to the rescue (as jfo also observes at her new digs):

The Item property is case-sensitive when searching for names. That is, the names “Pname” and “pname” are considered to be two different properties.

This is not the first time that the Remarks section has helped me out. Indeed, it is often the only valuable information in my effort to understand the behavior of the type or operation. This is good to consider when decorating my own types with the <remarks></remarks> xml doc tag – what does the user of this API need to know to eliminate having to make explorations with mockup code?

Now, if only the same existed for expected behavior for an IBindingListView’s ‘Contains’, ‘Find’ and ‘IndexOf’ methods in the presence of a non-null ‘Filter’. I suppose this is where MSDN Community Comments come in.

Filed under: Code Kaizen

Just enough ASM to get by… (now for you Mac programmers, too!)

In college, I worked through an Assembly programming course. I liked it a lot, I remember, but I got bored realizing the tedium. Plus, it was on 16-bit real mode, and 32-bit was just getting firmly established in the OS (WinNT, Win95*, FreeBSD, Linux) (…after 10 years since the intro of the Intel 386! I still remember going to the library in 5th grade and the sense of awe that came over me as I saw the cover of ‘Byte’ magazine declaring the 25MHz of the newest rev of that awesome chip). Of course, I wanted to use the protected mode instructions, but the department chair frowned on such excursions. God forbid learning take place. College is an institution of administration, after all, and it’s hard to administer the spark of interest, curiosity and independent investigation.

I’ve forgotton much of it. Too bad, now that I need it to trace code execution across native libraries which don’t have symbols (ugh). I just found this helpful guide, though. Still very relavant.

Under the Hood: Matt’s Just Enough Assembly Language to Get By.

* Sure, Windows 3.0 ran in 386 protected mode, but didn’t use pre-emptive multitasking nor a paged, flat 32-bit address model, so was it really making use of Protected mode? Not like we know it today…

Filed under: Code Kaizen

Live search – on the pulse

Apparently, I’m not the only one thinking Live search is getting better. Of course, I wouldn’t admit to influencing Scoble’s opinion, but a careful examination of posting dates might lead you to a certain conclusion… (no doubt the wrong one – yet I’d still relish it).

Filed under: Code Kaizen

Getting today’s date (without the time) in T-SQL (enhanced)

Ok, I thought about it some more.
 
I have been surprised by all the hits on dotNoted which are looking for ways to express the date without the time in SQL Server’s T-SQL.
 
And I realized how lame the string concatination example looks. So I went back to the drawing board to give you some more T-SQLly goodness. Here’s the result. It keeps the datetime binary throughout, so all the overhead converting to and manipulating strings is eliminated. Plus, it seems a bit more elegant:

DECLARE @datemask bigint

SET

@datemask = 0xffffffffff000000

SELECT

CAST(CAST((CAST(getdate() as binary) & @datemask) as binary(8)) as datetime)


Let’s try to compare the performance of this method to the string method…

DECLARE

@tdate datetime

DECLARE

@datemask bigint

SET

@datemask = 0xffffffffff000000

DECLARE @iterationcount int

SELECT

@iterationcount = 1000000

DECLARE

@start datetime

DECLARE @end datetime

DECLARE

@i int

SELECT

@i = 0

SELECT @start = getdate()

WHILE(@i < @iterationcount)

BEGIN

SELECT @tdate = CAST(CAST((CAST(getdate() as binary) & @datemask) as binary(8)) as datetime)

SELECT @i = @i+1

END

SELECT

@end = getdate()

SELECT

@end @start as "Binary Method Time"

SELECT

@i = 0

SELECT @start = getdate()

WHILE

(@i < @iterationcount)

BEGIN

SELECT @tdate = CAST(YEAR(getdate()) as varchar) + RIGHT(’00’+CAST(MONTH(getdate()) as varchar), 2) + RIGHT(’00’+CAST(DAY(getdate()) as varchar), 2)

SELECT @i = @i+1

END

SELECT

@end = getdate()

SELECT

@end @start as "String Method Time"

Here are the results after iterating 1,000,000 times –

Binary Method Time: 2.22 sec

String Method Time: 3.517 sec

Not very impressive gains, but it probably is worth using the binary method. Not worth converting existing code, however. The succinctness of the binary method is it’s strongest point – it can be inlined into the code more easily than the comparitively unwieldy string method, but if your looking for massive performance gains, they aren’t here. It is a relatively easy thing for the engine to compute, either way.

 

Filed under: Code Kaizen

Getting today’s date (without the time) in TSQL

 
 

 
 
It’s a technical term for spanglish.
 
It also makes a lot of sense when constructing software, and we get to jump back and forth between languages.
 
Going between different imperative languages isn’t too hard, although I’m beginning to use the -> operator in C# more often (and am now convinced it is better where ref objects are concerned in .Net – since the semantics are so different between heap and stack types.) Going between language styles, like imparative to declarative, or functional to imparative things get more tiring. But some things are just easier expressed in one language style vs. another ((HT|X)ML comes to mind as the most oustanding – coding it imparatively just is awful).
 
Case in point: try to get today’s date without the time from T-SQL. Go ahead….
 
Yea, it’s ugly. This is as good as I can get it. Your comments to improve it are appreciated…

DECLARE

@today varchar(30)

SET

@today = CAST(YEAR(getdate()) as varchar) + RIGHT(’00’+CAST(MONTH(getdate()) as varchar), 2) + RIGHT(’00’+CAST(DAY(getdate()) as varchar), 2)

Of course, this is implicitly convertable in TSQL…

DECLARE

@tdate datetime

SET

@tdate = @today

PRINT

@tdate

Filed under: Code Kaizen

.Net memory copy performance

I couldn’t find any articles on the performance of .Net memory copy techniques, so I crafted a very rough test to see for myself. Note: this is a very rough test, if I hadn’t mentioned it. As such there are lots of problems with it. I don’t really care, other than to acknowledge that dealing with them is a hallmark of a well done test. This isn’t a well-done test. It is a hack to convince me that Array.Copy isn’t an evil performance hog. This is what I have to work with and it’s an improvement.

 

I though of 4 different ways to copy memory which don’t use the Marshal class and wrote a quick routine to test the speed of each one. You’ll find the code below. Here are the results of a typical test:

 

Array.Copy took: 0.0200288 seconds

ArrayList took: 3.6051840 seconds

MemoryStream took: 0.6709648 seconds

P/Invoke copy took: 0.0600864 seconds

Array.Copy took: 0.0300432 seconds

ArrayList took: 4.3462496 seconds

MemoryStream took: 0.0300432 seconds

P/Invoke copy took: 0.0300432 seconds

Array.Copy took: 0.0400576 seconds

ArrayList took: 4.9971856 seconds

MemoryStream took: 0.0100144 seconds

P/Invoke copy took: 0.0400576 seconds

Each test is run ten times on a new set of data. Oh, yea, the data is a byte array of 10,000,000 randomly chosen values. It gets recreated on each run so that caching has less of an effect. So what are we seeing here? Well, the Array.Copy method is about as fast as both MemoryStream (which was suprising – I thought wrapping a stream around a data buffer and copying in the data would take a while) and PInvoke. All of them are pretty quick for normal application use. Copying the data into ArrayList took anywhere from 100 to 1000 times longer than any of these other methods. This is due, obviously, to the boxing and unboxing of the byte datatype – a big hit. If you run this and let the test run a couple of times, you’ll also perhaps see some big (~2x) variations on the ArrayList time, since there is possibly some GC activity due to memory pressure – it depends on your system, however (which is one of the problems with this test, I ran it on my regular workstation). Another interesting thing is that the MemoryStream method took an order of magnitude more time on the first run… I’d chalk this up to the great instruction cache on the Intel chip I’m running. I don’t really know, I’m speculating, but then I didn’t really want to answer this question, so I’m good with it for now. If you have an answer, post a comment and I’ll concede ignorance if your explaination is convincing. Finally, the times that MemoryStream and P/Invoke took are surprisingly (to me) short. I already mentioned MemoryStream, but I also thought that the extra baggage in the form of a switch into unmanaged code for P/Invoke would be more significant. As it is, there doesn’t seem to be any significant difference among these methods and Array.Copy (which is another problem – no measurement of variance and significance levels).

I’m now rather convinced that using any of these methods to push bytes around in memory is ok, and I’ll proceed to use which ever lends itself to the problem at hand, which will most likely overwhelmingly be Array.Copy.

As mentioned, here’s the whole test:

using System;

namespace

MemcopyTests

{

/// <summary>

/// Summary description for Class1.

/// </summary>

class Class1

{

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main(string[] args)

{

TimeSpan startTime, endTime;

for(int i=0; i<10; i++)

{

byte[] data = createTestData();

startTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

byte[] newData = new byte[data.Length+1];

Array.Copy(data, 0, newData, 0, data.Length);

newData[newData.Length-1] = (byte)1;

endTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

System.Diagnostics.Debug.WriteLine(String.Format(

"Array.Copy took: {0:N7} seconds", endTime.TotalSeconds – startTime.TotalSeconds));

startTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

System.Collections.ArrayList dataList =

new System.Collections.ArrayList(data);

dataList.Add((

byte)1);

endTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

System.Diagnostics.Debug.WriteLine(String.Format(

"ArrayList took: {0:N7} seconds", endTime.TotalSeconds – startTime.TotalSeconds));

startTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

System.IO.MemoryStream dataStream =

new System.IO.MemoryStream(data.Length);

dataStream.Read(data, 0, data.Length);

dataStream.Capacity += 1;

dataStream.Position = dataStream.Capacity-1;

dataStream.WriteByte((

byte)1);

endTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

System.Diagnostics.Debug.WriteLine(String.Format(

"MemoryStream took: {0:N7} seconds", endTime.TotalSeconds – startTime.TotalSeconds));

startTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

byte[] newData2 = new byte[data.Length+1];

unsafe

{

fixed(void* pData = data)

fixed(void* pNewData2 = newData2)

MoveMemory(new IntPtr(pNewData2), new IntPtr(pData), data.Length);

}

newData2[newData2.Length-1] = (

byte)1;

endTime = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;

System.Diagnostics.Debug.WriteLine(String.Format(

"P/Invoke copy took: {0:N7} seconds", endTime.TotalSeconds – startTime.TotalSeconds));

}

Console.ReadLine();

}

[System.Runtime.InteropServices.DllImport(

"Kernel32.dll", EntryPoint="RtlMoveMemory", SetLastError=false)]

static extern void MoveMemory(IntPtr dest, IntPtr src, int size);

private static byte[] createTestData()

{

byte[] data = new byte[10000000];

Random random = new Random();

random.NextBytes(data);

return data;

}

}

}

Filed under: Code Kaizen

Follow-up from newsgroups on Ping code

Willy Denoyette replied to a question in the microsoft.public.dotnet.languages.csharp group which improves my code to reach machines.

It’s a small addition, but it makes a big difference, since it uses the framework more elegantly – code kaizen for sure. The thing I wonder is if you wanted to expand this code to check multiple IPs for a machine, would WMI take care of this or would you need to lookup all IPs via System.Net.Dns methods?

 

I’ve updated the code. Thanks, Willy.

 

-r

 

Filed under: Code Kaizen

Cornerstone of good software – understand the domain.

My company, DigitalCommons, was invited by Microsoft to participate in a program aimed to encourage and provide access to resources to ramp quickly on the new Small Business Accounting for MS Office. I have to say that MS seems to be getting much better at 1.0 releases, producing a polished, user friendly product with great dev support. Although I haven’t used OneNote much, it looks cool, is easy to get to know, and is extensible. SBA even goes so far as to use the very same API that they expose to ISVs and other developers. 

I was at a hands-on lab in Building 20, the Platform Adoption Center, (I like to think of it alternatively as a brilliant showcase and some kind of opiate of developers), and in between grinding code for Intel, I was spinning some code to try out the API for SBA. I was stymied mostly by my shallow (mostly from evaporation, since I had a good course in accounting in college [ok only one, but how many do you need?]) of the basics of the science and practice of accounting. No one there could help me much except for a couple of devs from a company which does financial stuff. Fine. Let’s grep wikipedia:

List of accounting topics – Wikipedia, the free encyclopedia

Ah, there we are. I feel better about much of the API. A lot of my confusion about the design choices they made was due to my perspective. It is heavily biased by my varyingly deep understanding of numerous object models which define the APIs of most MS products (Office, .Net Framework, ADO, SQL Server components, MSI wrappers, ASDI… well, you get the idea). Object models have at least one root object, collections, and children objects. All entities are covered by objects (ideally). In the financial world, it is best to model items as classes (accounts), not objects, and just keep track of the quantity, since apparenly each item is identical and maintaining state (via properties) would be senseless. So the category is an object, not a collection. This was hard for me to overcome, but my desire to understand the domain helped me do it.

This leads me to reinforce my belief that the soul of good development is an understanding of the problem domain to at least the level of a lay-person, if not a journeyman. With this understanding comes some interesting inferences: niches for good software development will always exist, providing a good long term prospect for business, the offshoring movement will stablize or even reverse, open-source will only slowly migrate to areas which are now the staple of proprietary systems since there has to be incentive to develop a level of mastery over certain problem domains, whereas the incentive to build cool tools that have usefulness to the devs is inherent, and finally, developing software is a fast way to care about, and begin to master, a lot of various problem domains.

Because of the need (or compulsion, I suppose) to develop software for it, I have had to develop understandings of call-centers (help desks), exotic metal manufacturing and sales, product marketing through indirect channels, police dispatching and record keeping, tax assessment and property appraisal, 3D graphics and linear algebra, and vector calculus (for games, of course!). Now add accounting to the list. I hope to develop a campaign managment system for community development, and use SBA for the back-end. We’ll see if I can free up the time this summer, and inspire a few individuals to arise and assist me… I hope they like accounting. 😉

-rory

Filed under: Code Kaizen