views:

140

answers:

3

I've got some timers that measure the time to execute code.

 DateTime startTimeFunctionTotal = DateTime.Now;
     for (int i = 0; i < array.Count; i++) {
         DateTime startTimeFunction = DateTime.Now;
         //some code here

          DateTime stopTimeFunction = DateTime.Now;
          TimeSpan durationTimeFunction = stopTimeFunction - startTimeFunction ;

 }
 DateTime stopTimeFunctionTotal = DateTime.Now;
 TimeSpan durationTimeFunctionTotal = stopTimeFunctionTotal - startTimeFunctionTotal ;

It's allowed (even better) if the predicted time changes according to more data (every loop there is more data so prediction should be more accurate).

I would like to give user a predicted time of finish (both time like 15 minutes, and 10:56).

+1  A: 

To get a better representation of timing for code performance (in a nice TimeSpan) have a look at the System.Diagnostics.StopWatch.

It works like you would expect: Start() to begin timing, Stop() to stop. Read Elapsed to get a TimeSpan of the time taken, or ElapsedTicks for the most accurate measurement (a TimeSpan.Ticks = 1.0 x 10-9 sec, or 100 nano-sec; ElapsedTicks is variable and is relative to the StopWatch.Frequency of 1-sec/value).

Codesleuth
+3  A: 

Assuming each action in your for statement takes roughly the same amount of time:

List<TimeSpan> timeSpans = new List<TimeSpan>();
for(int i = 0; i < array.Count; i++)
{
    Stopwatch watch = Stopwatch.StartNew();
    //do stuff
    timeSpans.Add(watch.Elapsed);
    long ticksLeft = timeSpans.Sum(ts => ts.Ticks) * (array.Count - i) / timeSpans.Count;
    Console.WriteLine("Left: " + new TimeSpan(ticksLeft));
    Console.WriteLine("Finished in: " + 
        DateTime.Now.AddTicks(ticksLeft));
}

To go with the median use:

long ticksLeft = timeSpans.OrderBy(ts => ts.Ticks)
    .ElementAt(timeSpans.Count / 2).Ticks * (array.Count - i);
Yuriy Faktorovich
Testing it out. So far so good :)
MadBoy
It seems very good. What would you propose if there's a bit more differences in time (like 1 sec here, 5 secs there, 3 secs here). It has a bit of problem to make it time accurately. I know estimation is estimation but maybe it could be tweaked a bit.
MadBoy
@MadBoy: You could go with the median. as suggested by nobugz, I will update my answer with it. If this doesn't work, you need to say how many transactions and how long it should take, and I'll see if I can do something about throwing out values. But these things will likely vary widely by machine.
Yuriy Faktorovich
THanks. But are you sure median one is correct? Errors out on me. Operator '*' cannot be applied to operands of type 'System.TimeSpan' and 'int'
MadBoy
@MadBoy: Not my day today with bugs, I've fixed it.
Yuriy Faktorovich
THanks. Your code works very good. Thanks to nobugz as well!
MadBoy
+2  A: 

You can make an auto-correcting guess, as long as there are sufficient operations that each can be timed individually and each take roughly the same amount of time. Start out with a guess and multiply by the number of operations to perform. Measure the time of the next operation and add that to a list. Make a new guess by taking the average of the times in this list and multiply that by the number of operations left.

Your guess will get more accurate as you get more timing samples. And your progress bar will always reach 100% (+/- a wee bit). Taking the median instead of the average is better, it eliminates outliers due to sudden activity on your machine by other processes. And you'll want to throw out old measurements in the list, keeping only 10 to 20 is enough. Keep more samples if the operation time is more variable.

Hans Passant
Care to show an example how to aproach this? The biggest problem i have with Math on this, how to divide, multiply etc on TimeSpans and Dates.
MadBoy
Just make your guess an int or long, the number of milliseconds or microseconds per operation. Convert to TimeSpan only in the UI code.
Hans Passant
Would you consider Yuriy example as good one? It seems to be a bit too much off (even with 1000 samples).
MadBoy
@madboy - he doesn't handle Stopwatch.ElapsedTicks properly, its unit (1/Frequency) is not the same as that of TimeSpan.Ticks (100 nsec).
Hans Passant
@nobugz: Thanks, corrected. Looks like I still need Intellisense.
Yuriy Faktorovich
Things may vary for me because i use Database and each call gets sometimes 5 transactions and sometimes 30 then do the counting on that. Having around 1200 calls to database makes it vary a lot :-) Especially on the beginning when transactions are small and take less then a second and later on there are big guns which take up to 10 sec each. But i guess my users will just have to get used to term estimation isn't the right time it will finish :)
MadBoy
Time isn't good for feedback then. Why don't you just report the number of operations left to be performed...
Hans Passant
I do that. I give user about 10 diffrent measures saying how long last count took, which client it was, which day, which type was counted etc. How many loops are total, how many loops already passed, but rough estimation (come back in 15 minutes) should give them better overview.
MadBoy
Thanks for help.
MadBoy