Showing posts with label tips. Show all posts
Showing posts with label tips. 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.

Monday, May 19, 2008

Winamp and FLV

Even though Winamp comes with a plug-in to support FLV (Flash Video) it doesn't work. AVI playback didn't seem to work out of the box either.

There is a fairly simple solution that involves installing a couple of little apps and turning off Winamp's default plug-in.

The link is here (on a winamp forum)

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.

Thursday, May 15, 2008

The value of hyphens

It is the contract renewal time of the year for me. I have a little tip for you. If you intend to extend your contract, make sure you use words like extend or renew. While wording up an email regarding my conditions of an extension I found I was about to resign... or was it re-sign?


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

Life Tip #1 - Birthday Candles

When you a placing birthday candles on a cake, make sure that you put them the right way up. The base of a candle, once lit, burns faster and more brightly than the wick-end of the candle.

This achieves a number of things:

  • The candles burn much faster - you need to belt out "Happy Birthday" just a bit quicker
  • The cake looks a lot more exciting covered in flame - always good unless it's ice cream cake
  • The cake gets covered in wax - never good

I wish I had photos from the birthday cake I witnessed on the weekend. Classic.

Additional:
I looked up Happy Birthday on Wikipedia and did not expect the copyright issues around the song to be so ridiculous. Still the words come out of copyright at the end of this year. Woo!

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.

Testing Tip #1 - Boundary testing business objects

When testing business objects, for example an object that represents a Person or a Customer, you often have a minimum set of data requirements. I.e. a customer must have a last name. As well as having a set of optional data attributes (first name, date of birth, gender, etc).

To provide full test coverage you would mathematically need to provide N factorial minus M factorial combinations where N is the number of attributes and M is the number of mandatory attributes. I don't think I have ever had enough time to test that much, incredibly boring, testing and nor would I, had I.

In my experience the best pass through is to look at the two bounds. The minimum set where you specify the object with the bare minimum of attributes, the mandatory attributes, and each of these attributes has as little data as possible. In our customer example this would be a last name that is one single character in length.

The next test case would include every single attribute populated to it's maximum extent. So if you have a twenty character first name you specify all twenty characters. I document this as my all set.

These two test cases have been enough for every system I've tested. Using them you can prove every attribute being supplied and every attribute being absent, or supplied to their bare minimum allowed.


I don't include out-of-bounds testing here. That is, I don't check for 21 character first name objects, nor do I test for zero length last names. That specific boundary testing, I document as separate tests against the user interface. This achieves two things. Firstly, my test cases are granular and relate to a specific business requirement. This then means that defects raised are very specific and generally easier to track down. Secondly it cuts the amount of testing I have to do to what is more than likely going to cause defects.

Additional:
If you have more complex data types. For instance, if there is a business rule that states that attribute-x is only provided when attribute-z is set. Then that specific combination is already covered by your all set (attribute-z is set) and your minimum set (attribute-z is not set). I would additionally include test cases to ensure that any user interface validation of these attributes occurs.

Tuesday, April 8, 2008

QuickTest : Applying major changes to a repository

There are times when major changes need to be applied to a repository. Such an example is when a deployed application is moved from a local test server to a server in a pre-production environment. Nothing should change except for the URL, which unfortunately is hard-coded into every single object in your repository.
  1. Open Object Repository Manager [Resources > Object Repository Manager]
  2. Open your project repository [File > Open] Export to XML [File > Export to XML]
  3. Enter a filename [exported.xml]
  4. [ok]
  5. Open you’re favourite XML editor (i.e. Notepad++)
  6. Find and Replace on the current path to the new path
  7. Do any other maintenance work
  8. [Save xml-doc]
  9. ensure document is well-formed
  10. [Close xml-doc]
  11. Meanwhile… Back in Object Repository Manager
  12. Import from XML [File > Import from XML]
  13. Save your Imported repository [imported.tsr]
  14. In the file system, delete repository.tsr and exported.xml
  15. Rename: imported.tsr to repository.tsr
Note: You will need to open a different QuickTest project and then reopen your current project for the results of the merge to be visible in the Object Repository. It’s a pain, but that’s the way of things.