Link to home
Start Free TrialLog in
Avatar of SuperMario
SuperMario

asked on

High-performance computing in ASP.NET

I have an algorithm that multiplies a chain of matrices in an optimized order and one that multiplies them from the beginning to the end. I want to show the difference in running time.

What I have now is like this:

I dropped a Timer component onto my web form and gave it a name, set its interval to 1 ms.
Then:

private int ms = 0; // milliseconds

// btnTime_Click function
timer1.Start();
for(...)
{
   algorithm...
}
timer1.Stop();

// OnTimer function
ms ++;

So I figured the OnTimer function would increment the number of milliseconds every time a millisecond passed and then stop doing that when the algorithm finished. However, the result seems to remain at 0, which to me either means I'm doing it wrong or my algorithm is faster than 1 ms (which could be reasonable).

*** UPDATE ***
Now there are a few more things going on. If I create a small number of matrices (like, 4) with high dimensions (randomized between 64 and 256) ASPNET is denied access and the server application cannot be found (I guess it locks up?) The same thing happens if I create a large number of matrices (like 200) with small dimensions (between 1 and 128).

However, if I bring the numbers down to just below the threshold, the running time shown by my imprecise timer is always 0 milliseconds.

Anybody have any ideas? Are there any timers that have higher precision than milliseconds?

Thanks,
-Dan
Avatar of Arthur_Wood
Arthur_Wood
Flag of United States of America image

a timer is NOT used in this manner.  Rather, a Timer control is closer to a metronome - in that it 'ticks' every so often.  What you want to do is to read the SYSTEM time to the nearest millisecond - which may be rther difficult) at the start of the process, let the process execute and the  read the system time at the end of the proces, and compare these tow times to get the elapsed time.


AW
Avatar of Pickle
Pickle

Use this timer object, I use this with my Direct3D programming, it will use the highest resolution timer available on your system.

All the methods are static just use it like this:

using SixBit.Taco;

//Get time since application started
float AppTime = Timer.ApplicationTime;


//Get the absolute time in the system
float AbsTime = Timer.AbsoluteTime;

//Get the time since the last call to Timer.ElapsedTime
//The first time this is called it will be the time elapsed since the app started
//So call it once before you do a timed event, and then read the value after your timed event to see how many seconds it took eg:
Timer.ElapsedTime;
SomeMethodToMeasure();
float ElapsedTime = Timer.ElapsedTime;
//The variable ElapsedTime now holds the number of seconds that SomeMethodToMeasure() took to execute



THE CODE:
-------------------------------------------------

using System;
using System.Runtime.InteropServices;

namespace SixBit.Taco
{
      /// <summary>
      /// Enumeration for various cmds our timer can execute
      /// </summary>
      enum TimerCommand
      {
            Reset,
            Start,
            Stop,
            Advance,
            GetAbsoluteTime,
            GetApplicationTime,
            GetElapsedTime
      };

      /// <summary>
      /// Wrapper for system level timer functions
      /// </summary>
      public class Timer
      {

            [System.Security.SuppressUnmanagedCodeSecurity] // Stop stack walk security check to improve performance
            [DllImport("kernel32")]
            private static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);

            [System.Security.SuppressUnmanagedCodeSecurity] // Stop stack walk security check to improve performance
            [DllImport("kernel32")]
            private static extern bool QueryPerformanceCounter(ref long PerformanceCount);

            [System.Security.SuppressUnmanagedCodeSecurity] // Stop stack walk security check to improve performance
            [DllImport("winmm.dll")]
            public static extern int timeGetTime();

            private static bool initialized = false;
            private static bool useQPF = false;
            private static bool stopped = true;
            private static long ticksPerSecond = 0;
            private static long timeStopped = 0;
            private static long timeElapsed = 0;
            private static long timeBase = 0;
            private static double doubleTimeElapsed = 0.0;
            private static double doubleTimeBase = 0.0;
            private static double doubleTimeStop = 0.0;

            private Timer(){}

            public static void Start()
            {
                  ExecTimerCommand(TimerCommand.Start);
            }

            public static void Stop()
            {
                  ExecTimerCommand(TimerCommand.Stop);
            }

            public static void Reset()
            {
                  ExecTimerCommand(TimerCommand.Reset);
            }

            public static void Advance()
            {
                  ExecTimerCommand(TimerCommand.Advance);
            }

            /// <summary>
            /// Application time.
            /// </summary>
            public static float ApplicationTime
            {
                  get{return ExecTimerCommand(TimerCommand.GetApplicationTime);}
            }
            
            public static float AbsoluteTime
            {
                  get{return ExecTimerCommand(TimerCommand.GetAbsoluteTime);}
            }

            public static float ElapsedTime
            {
                  get{return ExecTimerCommand(TimerCommand.GetElapsedTime);}
            }

            private static float ExecTimerCommand(TimerCommand cmd)
            {
                  if (!initialized)
                  {
                        initialized = true;

                        // Use QueryPerformanceFrequency() to get frequency of timer.  If QPF is
                        // not supported, we will timeGetTime() which returns milliseconds.
                        long qwTicksPerSec = 0;
                        useQPF = QueryPerformanceFrequency(ref qwTicksPerSec);
                        if (useQPF)
                              ticksPerSecond = qwTicksPerSec;
                  }
                  if (useQPF)
                  {
                        double time;
                        double fElapsedTime;
                        long qwTime = 0;
               
                        // Get either the current time or the stop time, depending
                        // on whether we're stopped and what cmd was sent
                        if (timeStopped != 0 && cmd != TimerCommand.Start && cmd != TimerCommand.GetAbsoluteTime)
                              qwTime = timeStopped;
                        else
                              QueryPerformanceCounter(ref qwTime);

                        // Return the elapsed time
                        if (cmd == TimerCommand.GetElapsedTime)
                        {
                              fElapsedTime = (double) (qwTime - timeElapsed) / (double) ticksPerSecond;
                              timeElapsed = qwTime;
                              return (float)fElapsedTime;
                        }
            
                        // Return the current time
                        if (cmd == TimerCommand.GetApplicationTime)
                        {
                              double fAppTime = (double) (qwTime - timeBase) / (double) ticksPerSecond;
                              return (float)fAppTime;
                        }
            
                        // Reset the timer
                        if (cmd == TimerCommand.Reset)
                        {
                              timeBase        = qwTime;
                              timeElapsed = qwTime;
                              timeStopped        = 0;
                              stopped     = false;
                              return 0.0f;
                        }
            
                        // Start the timer
                        if (cmd == TimerCommand.Start)
                        {
                              if (stopped)
                                    timeBase += qwTime - timeStopped;
                              timeStopped = 0;
                              timeElapsed = qwTime;
                              stopped = false;
                              return 0.0f;
                        }
            
                        // Stop the timer
                        if (cmd == TimerCommand.Stop)
                        {
                              if (!stopped)
                              {
                                    timeStopped = qwTime;
                                    timeElapsed = qwTime;
                                    stopped = true;
                              }
                              return 0.0f;
                        }
            
                        // Advance the timer by 1/10th second
                        if (cmd == TimerCommand.Advance)
                        {
                              timeStopped += ticksPerSecond/10;
                              return 0.0f;
                        }

                        if (cmd == TimerCommand.GetAbsoluteTime)
                        {
                              time = qwTime / (double) ticksPerSecond;
                              return (float)time;
                        }

                        return -1.0f; // Invalid cmd specified
                  }
                  else
                  {
                        // Get the time using timeGetTime()
                        double time;
                        double fElapsedTime;
               
                        // Get either the current time or the stop time, depending
                        // on whether we're stopped and what cmd was sent
                        if (doubleTimeStop != 0.0 && cmd != TimerCommand.Start && cmd != TimerCommand.GetAbsoluteTime)
                              time = doubleTimeStop;
                        else
                              time = timeGetTime() * 0.001;
            
                        // Return the elapsed time
                        if (cmd == TimerCommand.GetElapsedTime)
                        {  
                              fElapsedTime = (double) (time - doubleTimeElapsed);
                              doubleTimeElapsed = time;
                              return (float) fElapsedTime;
                        }
            
                        // Return the current time
                        if (cmd == TimerCommand.GetApplicationTime)
                        {
                              return (float) (time - doubleTimeBase);
                        }
            
                        // Reset the timer
                        if (cmd == TimerCommand.Reset)
                        {
                              doubleTimeBase         = time;
                              doubleTimeElapsed  = time;
                              doubleTimeStop         = 0;
                              stopped     = false;
                              return 0.0f;
                        }
            
                        // Start the timer
                        if (cmd == TimerCommand.Start)
                        {
                              if (stopped)
                                    doubleTimeBase += time - doubleTimeStop;
                              doubleTimeStop = 0.0f;
                              doubleTimeElapsed  = time;
                              stopped = false;
                              return 0.0f;
                        }
            
                        // Stop the timer
                        if (cmd == TimerCommand.Stop)
                        {
                              if (!stopped)
                              {
                                    doubleTimeStop = time;
                                    doubleTimeElapsed  = time;
                                    stopped = true;
                              }
                              return 0.0f;
                        }
            
                        // Advance the timer by 1/10th second
                        if (cmd == TimerCommand.Advance)
                        {
                              doubleTimeStop += 0.1f;
                              return 0.0f;
                        }

                        if (cmd == TimerCommand.GetAbsoluteTime)
                        {
                              return (float) time;
                        }

                        return -1.0f; // Invalid cmd specified
                  }
            }
      }
}
The code provided by Pickle looks like a good option to use for the super-accurate timer.  

For a slightly less complex method, you could compare DateTime.Now's with the format string "HH:mm:ss.fffffff".  This string will give you [Hours]:[Minutes]:[Seconds].[Seven bit precision second fractions].  For the fractional seconds, anything over the number of 'f's included is truncated, and the hours, minutes, and seconds have leading zeros.

With regards to ASP.Net worker process "locking", when it is carrying out a particularly intensive task (such as matrix multiplication, or deep recursion), the process will quickly run to 100% (or another value, if you're using WebGardens - divide by # of processors).  When the worker process reaches this limit, it refuses further incoming requests.  I would suggest looking at multi-threading your application to solve this (put the matrix multiplication on a new thread, so that ASP.Net Worker Process can serve other requests).
Avatar of SuperMario

ASKER

stevie_bm,
Thanks very much for the info on the worker process. That's exactly what I was looking for regarding the high-performance computing.

And Arthur_Wood, your initial suggestion solved my other problem.

Though it turns out that a timer is actually kind of useless here. The most important task of this application is to determine the actual _number_ of multiplications that take place and determine the optimum order in which to multiply the matrices (a classic dynamic programming problem).

So, I doubled the points and I'll ask customer service to divide them between Arthur_Wood and stevie_bm.

Thanks a lot guys, I truly appreciate your help!
Oh, by the way, stevie_bm:

Does your comment apply also to C# Windows apps? My roommate has this unnatural, and in my opinion, very weird, interest in pi (he has memorized something like 57 digits). He has been trying to use C# to calculate each number of pi in binary (up to 100 million digits) in hopes that it will lead him to the meaning of life. 10 million digits works just fine with his program, but 100 million will lock up the process. Is this due to the same thing you told me, and should he use multithreading to solve it?
ASKER CERTIFIED SOLUTION
Avatar of stevie_bm
stevie_bm

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
xxx

You asked to split points between Arthur_Wood and stevie_bm.

I have reduced the points on this question from 200 to 100 as indicated by your request at Community Support. Please copy the URL and create a new question in this topic area for the other Experts to whom you wish to award points. The title of the question should read "Points for", followed by the Expert's name. In the question itself, you should paste the link to the original question and perhaps a comment stating that the points are for their help with that question. Once you have created the new questions, you can go back to the original, and accept the comment from the Expert for whom you did not create a new question. The Experts will  comment in your new "Points for" question(s), which you then accept and grade to close.
If you have any questions, please don't hesitate to ask.
Thank you.

** Mindphaser - Community Support Moderator **