Wednesday, September 30, 2009

Measuring Execution Time in C#

Motivation

Sometimes, while writing program

, we can get into situations when we need to measure execution times of various tasks.

Each programming language provides some mechanism to retrieve the current time from the system. If we read and store the system time at various moments, we can compute time intervals by substracting the values of system time taken at diffent moments.

We will see how to read the system time and how to measure time intervals in C#.

Reading the system time in C#

In C#, the DateTime class is used for storing the value of the system time at a specified moment. A DateTime instance stores

both date and time information. The DateTime class can be found in the System namespace.

In order to retrieve the current system time, we can use the static property Now of the DateTime class. For example the following two lines of code


DateTime currentSystemTime = DateTime.Now;
Console.WriteLine(currentSystemTime);
print out something like this:

4/17/2005 4:05:35 PM

We can print the date and time information stored in a DateTime instance in various formats, but we do not focus on them here, since our purpose is only to see how to measure time intervals.

Measuring time intervals in C#

In C#, there exists a dedicated class that stores information about a time interval. The name of the class is TimeSpan and it can be found in the System namespace.

The TimeSpan class is very easy to use. If we have an instance of TimeSpan class, we can assign to it directly a difference of two DateTime instance. See the code below to see how to do this.


/* Read the initial time. */
DateTime startTime = DateTime.Now;
Console.WriteLine(startTime);

/* Do something that takes up some time. For example sleep for 1.7 seconds. */
Thread.Sleep(1700);

/* Read the end time. */
DateTime stopTime = DateTime.Now;
Console.WriteLine(stopTime);

/* Compute the duration between the initial and the end time. */
TimeSpan duration = stopTime - startTime;
Console.WriteLine(duration);

The output of this code looks something like this:


4/17/2005 4:12:30 PM
4/17/2005 4:12:31 PM
00:00:01.7224768

As we see, by default the time interval is printed in the format hh:mm:ss.msec. If we want to retrieve separately the number of hours, minutes, seconds or milliseconds, we can do it through the properties of the TimeSpan class. Look at the code below to see how to do this.


/* Read the initial time. */
DateTime startTime = DateTime.Now;
Console.WriteLine(startTime);

/* Do something that takes up some time. For example sleep for 1.7 seconds. */
Thread.Sleep(1700);

/* Read the end time. */
DateTime stopTime = DateTime.Now;
Console.WriteLine(stopTime);

/* Compute the duration between the initial and the end time.
* Print out the number of elapsed hours, minutes, seconds and milliseconds. */
TimeSpan duration = stopTime - startTime;
Console.WriteLine("hours:" + duration.Hours);
Console.WriteLine("minutes:" + duration.Minutes);
Console.WriteLine("seconds:" + duration.Seconds);
Console.WriteLine("milliseconds:" + duration.Milliseconds);

The result of running this code is something like this:


4/17/2005 4:17:28 PM
4/17/2005 4:17:30 PM
hours:0
minutes:0
seconds:1
milliseconds:712

If we look more attentively, we will realize that this mode of retrieving the hours, minutes, seconds and milliseconds is not very useful. Because each field is returned separately and if we want to find out the total number of hours, minutes or seconds or milliseconds we have to manually sum up the individual fields.

Luckily, the TimeSpan class also provides some properties for directly retrieving the total elapsed hours, minutes, seconds and milliseconds. Look at the following code to see how these properties can be read.


/* Read the initial time. */
DateTime startTime = DateTime.Now;
Console.WriteLine(startTime);

/* Do something that takes up some time. For example sleep for 1.7 seconds. */
Thread.Sleep(1700);

/* Read the end time. */
DateTime stopTime = DateTime.Now;
Console.WriteLine(stopTime);

/* Compute the duration between the initial and the end time.
* Print out the number of elapsed hours, minutes, seconds and milliseconds. */
TimeSpan duration = stopTime - startTime;
Console.WriteLine("hours:" + duration.TotalHours);
Console.WriteLine("minutes:" + duration.TotalMinutes);
Console.WriteLine("seconds:" + duration.TotalSeconds);
Console.WriteLine("milliseconds:" + duration.TotalMilliseconds);

The result of this code is something like:


4/17/2005 4:23:27 PM
4/17/2005 4:23:29 PM
hours:0.000475684
minutes:0.02854104
seconds:1.7124624
milliseconds:1712.4624
Which is indeed much more useful, isn't it?

More advanced operations on time intervals

C# allows more advanced operations on time intervals. For example we can compute the sum of two TimeSpan instances, and the result is also of TimeSpan type.

Look at the following code to see how we can measure two separate time intervals and then easily compute the total execution time.


/* Read the initial time. */
DateTime startTime1 = DateTime.Now;

/* Do something that takes up some time. For example sleep for 1.7 seconds. */
Thread.Sleep(1700);

/* Read the end time. */
DateTime stopTime1 = DateTime.Now;

/* Compute and print the duration of this first task. */
TimeSpan duration1 = stopTime1 - startTime1;
Console.WriteLine("First task duration: {0} milliseconds.", duration1.TotalMilliseconds);

/* Do something that does not have to be measured.
* For example sleep for a while. */
Thread.Sleep(900);

/* Now we want to measure another task. We store the start time. */
DateTime startTime2 = DateTime.Now;

/* We perform the second task which again takes up some time.
* For example we can sleep for 2.1 seconds. */
Thread.Sleep(2100);

/* We store the end time of the second task. */
DateTime stopTime2 = DateTime.Now;

/* Compute and print the duration of this second task. */
TimeSpan duration2 = stopTime2 - startTime2;
Console.WriteLine("Second task duration: {0} milliseconds.", duration2.TotalMilliseconds);

/* Compute the total execution time. */
TimeSpan totalDuration = duration1 + duration2;
Console.WriteLine("Total duration: {0} milliseconds.", totalDuration.TotalMilliseconds);

The ouput obtained by running this code is:


First task duration: 1702.448 milliseconds.
Second task duration: 2103.024 milliseconds.
Total duration: 3805.472 milliseconds.

In the same manner we can compute the difference between two TimeSpan instances. Again the result will be of TimeSpan type.

Conclusions

As we could see, the combination of DateTime and TimeSpan classes is very powerfull. It allows us to very easily record the system time and then measure execution times. These two classes can save us a lot of headaches if we know about their existence.

Wednesday, September 23, 2009

C# Snippets: Directory Listing in C#

This will process a directory and get a list of all the files in the directory, returning them as a StringBuilder object.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
StringBuilder dirList = directoryListing("C:\\Inetpub", "");
Console.WriteLine(dirList.ToString());
}

static StringBuilder directoryListing(string path, string indent)
{
StringBuilder result = new StringBuilder();
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] rgDirs = di.GetDirectories();

foreach (DirectoryInfo dir in rgDirs)
{
result.AppendLine(indent + dir.Name);
result.Append(directoryListing(path, indent + "..").ToString());
}
return result;
}
}
}

C# Snippets: Saving User Preferences and Settings

Almost every application will at some stage need to store information, settings or user preferences to a file so that they can be retrieved at a later date. This has formerly be done using INI configuration files and more recently using the system Registry. This snippet will show you how to save settings in the Registry, to a SQL Database or to an XML file.

The first thing you need is a class that holds all the data you need to save, in this example we are creating a simple class called UserPreferences which contains two strings and an integer.

public class UserPreferences
{
private string _DisplayName;
public string DisplayName
{
get { return _DisplayName; }
set { _DisplayName = value; }
}

private string _Company;
public string Company
{
get { return _Company; }
set { _Company = value; }
}

private int _SomeValue;
public int SomeValue
{
get { return _SomeValue; }
set { _SomeValue = value; }
}
}

This class will form a basis for each of the derived classes that we will use for storing the information in XML, Registry and Database.

XML Serialization :

Attribute before the declaration or create a class that implements the ISerializable interface.


To save the user preferences class to an XML file simply create an XML Writer and invoke the Serialise method.


UserPreferences up = new UserPreferences();

XmlSerializer mySerializer = new XmlSerializer(typeof(UserPreferences));
StreamWriter myWriter = new StreamWriter("c:/prefs.xml");
mySerializer.Serialise(myWriter, up);
myWriter.Close();

To read the data back in, you simply call the Deserialise method.


UserPreferences up;

XmlSerializer mySerializer = new XmlSerializer(typeof(UserPreferences));
FileStream myFileStream = new FileStream("c:/prefs.xml",FileMode.Open);

up = (myTestClass)mySerializer.Deserialize(myFileStream);

You could also implement the IFormatter interface which will allow you to format the data and save it within a SOAP XML package using SoapFormatter or using a BinaryFormatter to store the data in a binary format.


Saving Settings within a SQL Database :

If you are developing an application that relies on data stored within a database (i.e. the program will not function without the database) then it makes sense to store configuration settings for the application within the database as well. This allows for a distributed model where the application can be downloaded to any client machine and settings retrieved from a central source.

We need to create an implementation of the class that will handle saving to the database. I am going to create a derived class which inherits the properties of UserPreferences as well as two new methods; one for saving to the database and one for loading the data back. Since we need to load the data each time the program is run (when we instantiate the UserPrefererences class) we can put the loading code into the constructor for the class.



public class SQLUserPreferences : UserPreferences
{
public SQLUserPreferences()
{
string connectionString = "Data Source=.\\SQLEXPRESS;AttachDbFilename=\"C:\\DOCUMENTS AND SETTINGS\\TROTTT\\MY DOCUMENTS\\VISUAL STUDIO 2005\\PROJECTS\\WINDOWSAPPLICATION5\\WINDOWSAPPLICATION5\\DATABASE1.MDF\";Integrated Security=True;Connect Timeout=30;User Instance=True";
SqlConnection sqlCon = new SqlConnection(connectionString);

sqlCon.Open();
string commandString = "SELECT * FROM appSettings WHERE UserLogon = '" +
System.Environment.UserDomainName + "\\" +
System.Environment.UserName.ToString() + "'";

SqlCommand sqlCmd = new SqlCommand(commandString, sqlCon);
SqlDataReader dr = sqlCmd.ExecuteReader();

while (dr.Read())
{
// Index 0 contains the domain/username used
// as a primary key for the database.
_DisplayName = dr.GetString(1);
_Company = dr.GetString(2);
_SomeValue = dr.GetInt32(3);
}

dr.Close();
sqlCon.Close();
}

public void Save()
{
string connectionString = "Data Source=localhost; Integrated Security=SSPI; Initial Catalog=appSettings";
SqlConnection sqlCon = new SqlConnection(connectionString);

sqlCon.Open();
string commandString = "UPDATE appSettings SET " +
"DisplayName = '" + _DisplayName + "', " +
"Company = '" + _Company + "', " +
"SomeValue = " + _SomeValue +
" WHERE UserLogon = '" +
System.Environment.UserDomainName + "//" +
System.Environment.UserName + "'";

SqlCommand sqlCmd = new SqlCommand(commandString, sqlCon);
sqlCmd.ExecuteNonQuery();
sqlCon.Close();
}
}


Saving Settings to the Registry :

The Windows registry is a general purpose mechanism for storing information that is to be maintained when a Windows application terminates. The .Net framework provides a class that provides easy access to registry methods. The registry contains many locations, called keys, such as HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER. These are a few of the read only base keys that contain information about users, the operating system, the software installed and the settings for the current logged on user.

We are going to create a similar derived class to the one we created for SQL Databases; in fact the technique is exactly the same. You will need to add a reference to the namespace Microsoft.Win32.


public class RegUserPreferences : UserPreferences
{
public RegUserPreferences()
{
RegistryKey UserPrefs = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Your-Company-Name\\App-Name", true);

if (UserPrefs != null)
{
_DisplayName = UserPrefs.GetValue("DisplayName");
_Company = UserPrefs.GetValue("Company");
_SomeValue = UserPrefs.GetValue("SomeValue");
}
else
{
// Key did not exist so use defaults
_DisplayName = System.Environment.UserName;
_CompanyName = System.Environment.UserDomainName;
_SomeValue = 0;
}
}

public void Save()
{
RegistryKey UserPrefs = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Your-Company-Name\\App-Name", true);

if (UserPrefs == null)
{
// Value does not already exist so create it
RegistryKey newKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Your-Company-Name", true);
UserPerfs = newKey.CreateSubKey("App-Name");
}

UserPerfs.SetValue("DisplayName", _DisplayName);
UserPerfs.SetValue("Company", _Company);
UserPerfs.SetValue("SomeValue", _SomeValue);
}
}


...

C# Snippets: To Obtain Current Application Directory

From time to time you may need to access a file within the current application folder. .Net provides a property that is set to the absolute path to the application executable, and a method can be used to extract the folder name.

using System.IO;
using System.Windows.Forms;

string appPath = Path.GetDirectoryName(Application.ExecutablePath);


Console Application project types will have to manually add a reference to the System.Windows.Forms assembly for the Application object to be exposed.

C# Snippets: Beeping the PC Speaker in C#

[DllImport("Kernel32.dll")]
public static extern bool Beep(UInt32 frequency, UInt32 duration);
public static void BeepMe()
{
int Frequency = 500;
int DurationInMS = 100;
Beep(Frequency, DurationInMS);
}

..

C# Snippets: Lorem Ipsum Generator

.

C# Snippets: Foreach Loop Over Hashtable

foreach (string key in hash.Keys)
{
Console.WriteLine(key + '=' + hash[key]);
}

...

Followers