Showing posts with label coding. Show all posts
Showing posts with label coding. Show all posts

Monday, May 26, 2008

Leveraging MSVC's output window

If you use scripts to identify parts of your code that may not meet standards, you can simplify the job of the developer by making use of Visual Studio's Output Window. Any output from a script that appears on a seperate line in the output window with the following format is clickable.

$filepath($line) : $message

When you click on it, the user is taken to the specified file and line and the message will be displayed in the status bar. This is how it works when you let Visual Studio perform builds for you.

So now that you know how to format user messages in the output window, you need to be able to run your script to that output is sent to the output window.

This is pretty easy to do... in Visual Studio, go to: Tools > External Tools and setup you're tool a bit like mine. My example is a perl script that looks for //TODO comments in code and writes the information to the standard output.


The "Use Output Window" is the kicker here. Otherwise it'll run in a separate console window and be less useful to you. When you write your scripts, you should dump the output to the standard output. That is what gets piped into the output window.

With this in mind you can start writing scripts to useful feedback to developer like:
  • not consting parameters
  • identifying classes / methods without unit tests
  • poor coding standards / formatting
  • implementing FxCop like functionality (for non C# languages)
Basically anything you can identify in a script. I use it for enforcing coding standards, allowing other developers to mark areas for me that could be performance tuned.

It is also useful for doing ASCII to Unicode conversions. Conversions like so are non-trivial and carte-blanche find and replace methods generally don't work. You can write a script to identify potential areas for change and then tackle them one at a time.

Happy Scripting!


note: I don't know how to get it to show up in the Error List window (not that I've looked recently) but if anyone knows, send me a link. That would be super.

Friday, May 16, 2008

Late Copy Instantiation - Addendum

Regarding my post the other day about delaying an object copy until required a friend asked for me to show my working out. So here is the "proof". The scenarios are somewhat contrived as I didn't spend much effort initially as I felt the tip was self explanatory.

Overview
The basic setup for the test is a simple function that either takes a by-value object to force the copy or a const-reference as the most efficient non-pointer implementation. The object has a method called isValid which returns true if one of its attributes is greater than zero. This attribute is defined in the constructor and therefore remains constant over the life of the object.

To give the object something to do whilst in the function, there is a second method called update. This increments a different attribute by one. It also enforces the requirement that a non-const object exist at some point.

Objects
There are three types of objects. A simple object, a string object and a complex object. Each one has different members to make the copy constructor increasingly complex.

The Single Object has 8 32 bit unsigned int attributes and that is all. The String Object has the same eight attributes as the Single Object and on top of this are five emptystl string objects. Finally the Complex object has the same attributes as the String Object as well as three dynamic arrays that are allocated to 100 bytes in length on construction and threestl vectors of differing types. The Complex Object has a custom copy constructor to copy the dynamic byte array.

Simple (click to enlarge)

String (click to enlarge)

Complex (click to enlarge)


Tests
There were two basic tests. Always exit early and never exit early. There was also two builds. Debug mode and a Release build with "full optimisation" that didn't favour speed or size. Both were compiled using the Microsoft Visual Studio 2005 compiler.

These are the release-full compiler switches:
/Ox /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FD /EHsc /MD /Fo"Release-Full\\" /Fd"Release-Full\vc80.pdb" /W3 /nologo /c /Wp64 /Zi /TP /errorReport:prompt

Each test was placed inside a loop and executed 50,000,000 times so that the timing code would return cycles greater than zero. I used timing code that had a resolution of one second. Any finer granularity wouldn't have really made a difference.

test code (click to enlarge)


Hardware/Software Configuration
The computer details are:
  • Microsoft Windows XP Professional, Version 2002, SP2
  • AMD Athlon 64bit X2 Dual Core 4200+ (2.21GHz)
  • 2GB 800Mhz DDR3 RAM

The machine had a fair few other applications open at the same time but none had focus aside from the executing test. Naturally the other apps are still waking and sleeping from time to time and while they may impact the overall run time they won't impact the outcome of the test.

Results
Here are the results. Numbers indicate clocks per second. The finest granularity I used was a second. The zero numbers are, more than likely, caused by the optimiser realising that the isValid method will always return true or false and as such it removed that code out of the equation. In the exit-early scenarios this collapses the function to nothing.

The simple object with always copy ends up being "zero time" I believe because the compiler knew in advance the number of iterations and the functionality in the update was trivial (integer increment). This means it could calculate an end result without running the loop at all.

Irrespective of the poor test setup it is blindingly obvious that the const-ref scenario wins as soon as the object being copied becomes non-trivial.

results (click to view same image in own window...)


Conclusion

There you have it, const reference parameters with late copying are faster than pass by value copied parameters for anything but simple data objects. They are marginally slower when the late copy needs to occur but this delay is the time it takes to make a four byte copy. Which could be offset by using the const-reference object for as long as possible, therefore enabling the compiler to make better optimisations. Const objects are easier to optimise than non-const.

If my memory of Java is true, then this applies to Java. I don't know if it applies to C#. I suspect that C# does some of this in the background.

Wednesday, May 14, 2008

Coding Tip #3 - Late Call by Value Instantiation (C++)

When you have a function that takes anything but a simple data type as a parameter and that parameter is being passed in by value, a copy of the object is created. This may be exactly what you wanted. It is standard behaviour. For example, you probably want a copy of your object when putting the object into a collection.

Figure 1. pass by value

If your method has gaurd clauses to ensure only valid objects are added to the collection then there is a chance your code is being wasteful. The early exit event that occurs when the gaurd clauses are true will mean that the original object copy was not required.

You can improve this by doing a const pass-by-reference. You then use the const reference to evaluate your gaurd clauses. If you exit early, all you have spent is 4 bytes on the stack (32bit of course) and you save on the time it takes to copy.

Figure 2. pass by const-reference with late copy

If your code then needs its own copy of the data, create it as a local variable using the const reference as parameter for the copy constructor.

The benefits are directly related to the following:
  • how many chances for early exit exist
  • the size of the object begin copied
  • whether a deep or shallow copy is occuring
  • how long it takes to copy
  • the frequency of early exit calls in relation to copy calls

Tuesday, May 13, 2008

Coding Tip #2 - First Run Tracing

I have a specific method for testing new code that can't be tested by traditional means. By traditional I mean unit tests with mock objects. By code that can't be easily tested I am usually referring to graphics code where a successful implementation is a subjective one. Or, where you are directly allocating memory on a GPU and don't have privy to all the gooey details.

Now, I use the following method for all code I write. Even when I do write unit tests. The first thing I do is step through the code, line by line, mentally desk checking memory references and values. Making sure it all works as I expected it to. I don't have the statistics to back it up but my feelings on it are it gives you a good indication if the logic you have implemented makes sense while it is running. Not just while you are coding it (it just about always makes sense while you are coding it). It allows you to identify failures as they occur rather than waiting for the unit tests to complete. You also get the benefit of analysing live data rather than static lines of code.

When I get an error, I drop a break point in, stop debugging and fix it. After the rebuild I can let it run to the break point because I have confidence up to that line. I continue to go through my code until it works. Depending on the complexity of the code I may trace through some alternate paths. In any case I then go an write any additional unit tests I may have realised I needed whilst tracing through and then let my code execute over all the unit tests.

This may seems a little bit OTT but the next time you implement polymorphism with virtual inheritance you may thank me. On more than one occasion I have uttered the words: "wait a minute, how did my code get over here?".

Monday, May 12, 2008

Coding Tip #1 - Object Identifiers

When designing an interface that allows callers to request an object from some data storage, ensure that your interface accepts unsigned integers rather than signed ones. If you use a signed integer then you need to have a guard clause to reject a negative parameter. However, if you ensure your identifier type accurately models the data it represents. Then your guard clause is implicitly implemented by your parameter. This means you can drop the explicit guard clause from your code. Cleaner, faster, better code. Everyone is a winner.


Apologies for the image of code. Google Blogger doesn't really allow anything except poorly formatted text.


Note:
Obviously this does not hold true if your information model allows negative identifiers.