Stopwatch appears to jump 500µs between iterations of a tight loop - c#

I wrote some code which monitors the output of Stopwatch using a tight loop. This loop tracks the number of ticks which have elapsed since the last iteration. I'm observing jumps of 500 microseconds 20 times a second, while most other iterations take <1µs.
Can someone explain why I'm seeing these jumps?
I've tried:
Setting processor affinity (no effect)
Changing thread priority (Highest/AboveNormal makes things worse)
Running outside of the debugger
Release build with optimizations
My code is below:
Stopwatch sw = new Stopwatch();
int crossThresholdCount = 0;
long lastElapsedTicks = 0;
long lastPrintTicks = 0;
Console.WriteLine("IsHighResolution: " + Stopwatch.IsHighResolution);
Console.WriteLine("Frequency: " + Stopwatch.Frequency);
sw.Start();
long thresholdTicks = 5000; // 10000 ticks per ms
while (true)
{
long tempElapsed = sw.ElapsedTicks;
long sincePrev = tempElapsed - lastElapsedTicks;
lastElapsedTicks = tempElapsed;
if (sincePrev > thresholdTicks)
crossThresholdCount++;
// print output
if (crossThresholdCount > 0 && tempElapsed - lastPrintTicks > TimeSpan.TicksPerSecond)
{
lastPrintTicks = tempElapsed;
Console.WriteLine("crossed " + crossThresholdCount + " times");
crossThresholdCount = 0;
}
}

Most likely you are seeing preemptive task switching. This is when the operating system suspends your program, and goes off to execute other programs. This is how things have been since Windows 95 (Win 3.1 and earlier had cooperative multitasking, whereby you could hold the CPU for as long as you want).
By the way, there is a better way to time your execution accurately: QueryThreadCycleTime, which counts CPU cycles only when your code is executing, and so excludes such pauses.

Your test doesn't really make sense... Your process is not the only one to run on your machine. The system gives processor time to each thread in turn, so there are periods of time when your loop is not running at all, which explains the "jumps".

Related

problems diagnosing time spent in a for loop C#

I have a for loop that is taking way too long and i dont know why.
Stopwatch proctime = new Stopwatch();
Stopwatch innerlooptime = new Stopwatch();
Stopwatch outerlooptime = new Stopwatch();
proctime.Start();
int length = inbtable.Rows.Count;
outerlooptime.Start();
for (int i = 0; i < length; i++)
{
outerlooptime.Stop();
DataRow newrow = graphdata.NewRow();
innerlooptime.Start();
for (int j = 0; j < graphdata.Columns.Count; j++)
{
colname = graphdata.Columns[j].ColumnName;
newrow[j] = inbtable.Rows[i][colname];
}
innerlooptime.Stop();
outerlooptime.Start();
graphdata.Rows.Add(newrow);
}
proctime.Stop();
if you time it all out, the time spent on just the "inner loop" or the j-loop is like 1/10th of a second.
the time spent inside the i loop, but not the j-loop is like 1/10th of a second.
the time spent on the total loop is around 1-second. so Time-iloop + Time-jloop is like 1/5th of the total time. where is the rest of the time being spent? take a look at the image, comparing processing time (proctime in the code), outerloop time and innerloop time. why dont those add up to something much closer to each other?
You don't show the declarations of your timers, but the variable names imply that you are looking at the processor time, not the actual amount of time spend. Processor time is the amount of time spent by the processor core running your calculations - the processor is shared among all the processes running on your computer, so in 1 second, it is perfectly reasonable to receive 0.2 seconds of processor time.
Try using the Stopwatch class instead:
// using System.Diagnostics;
Stopwatch sw = new Stopwatch();
sw.Start();
DoThings(); // run your code
sw.Stop();
Debug.WriteLine("Actual time elapsed: " + sw.Elapsed.ToString());
I figured out the answer. it was really silly. i had the stopwatches switched around in my message box statement at the end of the function, so one stopwatch was being reported as another one. all the time is being spent somewhere else, outside the code i posted. Thanks for all of your help.

C# Timing Loop Rate Inaccuracies

I'm trying to create a method in C# whereby I can repeatedly perform an action (in my particular application it's sending a UDP packet) at a targeted rate. I know that timer inaccuracy in C# will prevent the output from being precisely at the target rate, but best effort is good enough. However, at higher rates, the timing seems to be completely off.
while (!token.IsCancellationRequested)
{
stopwatch.Restart();
Thread.Sleep(5); // Simulate process
int processTime = (int)stopwatch.ElapsedMilliseconds;
int waitTime = taskInterval - processTime;
Task.Delay(Math.Max(0, waitTime)).Wait();
}
See here for the full example console app.
When run, the FPS output of this test app shows around 44-46 Hz for a target of 60 Hz. However at lower rates (say 20 Hz), the output rate is much closer to the target. I can't understand why this would be the case. What is the problem with my code?
The problem is that Thread.Sleep (or Task.Delay) is not very accurate. Take a look at this: Accuracy of Task.Delay
One way to fix this is to a start the timer once, and then have a loop where you delay some ~15 ms in each iteration. Inside each iteration, you calculate how much times the operation should have been executed so far and you compare it with how many times you have run it so far. And you then run the operation enough times to catch up.
Here is some code sample:
private static void timerTask(CancellationToken token)
{
const int taskRateHz = 60;
var stopwatch = new Stopwatch();
stopwatch.Start();
int ran_so_far = 0;
while (!token.IsCancellationRequested)
{
Thread.Sleep(15);
int should_have_run =
stopwatch.ElapsedMilliseconds * taskRateHz / 1000;
int need_to_run_now = should_have_run - ran_so_far;
if(need_to_run_now > 0)
{
for(int i = 0; i < need_to_run_now; i++)
{
ExecuteTheOperationHere();
}
ran_so_far += need_to_run_now;
}
}
}
Please note that you want to use longs instead of ints if the process is to remain alive for a very long time.
If you replace this:
Task.Delay(Math.Max(0, waitTime)).Wait();
with this:
Thread.Sleep(Math.Max(0, waitTime));
You should get closer values on higher rates (why would you use Task.Delay(..).Wait() anyway?).

Is there anyway to know if thread has released CPU?

I have accidentally found a peculiar behaviour for which I am not getting any reason. In the program below there are 2 sections. First section is commented which creates 2 threads and does some work, in second section I added some code for getting primes which I tried for checking AsParallel Performance. AsParallel really decreased the time for program. But the thing which struck me most was when I commented the above section I got a improvement in time.
So my question is did the first section ,which I have commented, had kept the CPU busy enough. Or was there any other reason.
Please see time elapsed for
1) When first section is not commented : Elapsed: 4260619 (Ticks)
2) When first section is commented : Elapsed: 2700445 (Ticks)
class Program
{
[ThreadStatic]
static int thStaticInt = 0;
static void Main(string[] args)
{
//new Thread(() =>
//{
// for (int i = 0; i < 10; i++)
// {
// thStaticInt++;
// Console.WriteLine("from first {0}", thStaticInt);
// }
//}
//).Start();
//new Thread(() =>
//{
// for (int i = 0; i < 10; i++)
// {
// thStaticInt++;
// Console.WriteLine("from second {0}", thStaticInt);
// }
//}
//).Start();
//Console.WriteLine("Press any key");
//Console.ReadLine();
//Another section starts here
IEnumerable<int> numbers = Enumerable.Range(3, 1000000);
Stopwatch watch = new Stopwatch();
watch.Start();
var primes = from n in numbers.AsParallel()
where Enumerable.Range(2, (int)Math.Sqrt(n)).All(i => n % i != 0)
select n;
IEnumerable<int> primeNumbers = primes.ToArray();
watch.Stop();
TimeSpan ts = watch.Elapsed;
Console.WriteLine("Time Elapsed {0}", ts.Ticks);
Console.ReadLine();
}
}
You're not grabbing the complete picture. Your profiling leads you to misinterpretation.
When you start a thread you request the operating system to start a thread, that doesn't mean it starts immediately, it's just a request. The OS decides when it runs your thread and for how long. That being said, in your example, your threads in the commented section could be run before, during or even after your second section.
The work in your threads is also a bit dubious. A counter to ten is very minimalistic. Also keep in mind that what you do, writing to the console, from a thread is only possible because the Console class does the thread synchronization for you. So, how does this fit in the timing? I have no idea.
Then there might be other processes with other threads running that you don't know of.
And on top of all of that you probably have a multicore processor, which might or might not affect everything.
Profiling is not an easy task. You should at least repeat your tests multiple times, corelate the results and have a solid understanding of everything involved.

Why Thread.Start method is blocked when CPU load is high?

For test purposes I write CPU stress program: it just do N for-loops in M threads.
I run this program with large number of threads, say 200.
But in Task Manager I see that threads counter not exceed some little value, say 9 and a Thread.Start methods waits for finish previous running threads.
This behavior seems like a ThreadPool behavior, but I expect that regular System.Threading.Thread must start anyway without waiting for some reason.
Code below will reproduce this issue and have an option for workaround:
using System;
using System.Diagnostics;
using System.Threading;
namespace HeavyLoad
{
class Program
{
static long s_loopsPerThread;
static ManualResetEvent s_startFlag;
static void Main(string[] args)
{
long totalLoops = (long)5e10;
int threadsCount = 200;
s_loopsPerThread = totalLoops / threadsCount;
Thread[] threads = new Thread[threadsCount];
var watch = Stopwatch.StartNew();
for (int i = 0; i < threadsCount; i++)
{
Thread t = new Thread(IntensiveWork);
t.IsBackground = true;
threads[i] = t;
}
watch.Stop();
Console.WriteLine("Creating took {0} ms", watch.ElapsedMilliseconds);
// *** Comment out s_startFlag creation to change the behavior ***
// s_startFlag = new ManualResetEvent(false);
watch = Stopwatch.StartNew();
foreach (var thread in threads)
{
thread.Start();
}
watch.Stop();
Console.WriteLine("Starting took {0} ms", watch.ElapsedMilliseconds);
if (s_startFlag != null)
s_startFlag.Set();
watch = Stopwatch.StartNew();
foreach (var thread in threads)
{
thread.Join();
}
watch.Stop();
Console.WriteLine("Waiting took {0} ms", watch.ElapsedMilliseconds);
Console.ReadLine();
}
private static void IntensiveWork()
{
if (s_startFlag != null)
s_startFlag.WaitOne();
for (long i = 0; i < s_loopsPerThread; i++)
{
// hot point
}
}
}
}
Case 1: If s_startFlag creation is commented, then starting threads immediately begins a high intensive CPU work. In this case I have a small concurrency (around 9 threads) and all the time I hold on thread starting code:
Creating took 0 ms
Starting took 4891 ms
Waiting took 63 ms
Case 2: But if I create s_startFlag, all new threads will wait until it will be set. In this case I successfully start all 200 threads concurrently and get expected values: little time for a start and much time for a work and number of threads in Task Manager is 200+:
Creating took 0 ms
Starting took 27 ms
Waiting took 4733 ms
Why threads refuse start in first case? What kind of limitation I exceed?
System:
OS: Windows 7 Professional
Framework: NET 4.6
CPU: Intel Core2 Quad Q9550 # 2.83GHz
RAM: 8 Gb
I do some research and now I see that high CPU load really have strong affect to the thread starting timings.
First: I set totalLoops to 100 times bigger value for have more time of observation. I saw that threads not limited but very slowly created. 1 thread start in 1-2 seconds!
Second: I explicitly bind a main thread to CPU core #0 and working threads to cores #1, #2, #3 using of SetThreadAffinityMask function (https://sites.google.com/site/dotburger/threading/setthreadaffinitymask-1).
Stopwatch watch;
using (ProcessorAffinity.BeginAffinity(0))
{
watch = Stopwatch.StartNew();
for (int i = 0; i < threadsCount; i++)
{
Thread t = new Thread(IntensiveWork);
t.IsBackground = true;
threads[i] = t;
}
watch.Stop();
Console.WriteLine("Creating took {0} ms", watch.ElapsedMilliseconds);
}
and
using (ProcessorAffinity.BeginAffinity(1, 2, 3))
{
for (long i = 0; i < s_loopsPerThread; i++)
{
}
}
Now main thread has own dedicated CPU core (in the process boundaries) and worker threads starting after ~10 milliseconds (totalLoops = 5e10).
Creating took 0 ms
Starting took 2282 ms
Waiting took 3681 ms
Additionally, I found this sentence in MSDN:
When you call the Thread.Start method on a thread, that thread might
or might not start executing immediately, depending on the number of
processors and the number of threads currently waiting to execute.
https://msdn.microsoft.com/en-us/library/1c9txz50(v=vs.110).aspx
Conclusion: Thread.Start method a very sensitive to number of actively working threads. It could be a very strong performance impact - slowing in hundreds times.

Measure Execution time of Parallel.For

I am using a Parallel.For loop to increase execution speed of a computation.
I would like to measure the approximate time left for the computation. Normally one simply has to measure the time it takes for each step and estimate the total time by multiplying the step time by the total number of steps.
e.g., If there are 100 steps and some step takes 5 seconds then one could except that the total time would be about 500 seconds. (one could average over several steps and continuously report to the user which is what I want to do).
The only way I can think to do this is by using an outer for loop that essentially resorts back to the original way by splitting up the parallel.for interval and measuring each one.
for(i;n;i += step)
Time(Parallel.For(i, i + step - 1, ...))
This isn't a very good way in general because either a few number of very long steps or a large number of short steps cause problems with timing.
Anyone have any ideas?
(Please realize I need a real time estimation of the time it is taking the parallel.for to complete and NOT the total time. I want to let the user know how much time is left in execution).
This method seems to be pretty effective. We can "linearize" the parallel for loop by simply having each parallel loop increment a counter:
Parallel.For(0, n, (i) => { Thread.Sleep(1000); Interlocked.Increment(ref cnt); });
(Note, thanks to Niclas, that ++ is not atomic and one must use lock or Interlocked.Increment)
Each loop, running in parallel, will increment cnt. The effect is that cnt is monotonically increasing to n, and cnt/n is the percentage of how much the for is complete. Since there is no contention for cnt, there are no concurrency issues and it is very fast and very perfectly accurate.
We can measure the percentage of completion of the parallel For loop at any time during the execution by simply computing cnt/n
The total computation time can be easily estimated by dividing the elapsed time since the start of the loop with the percentage the loop is at. These two quantities should have approximately the same rates of change when each loop takes approximately the same amount of time is relatively well behaved (can average out small fluctuation too).
Obviously the more unpredictable each task is, the more inaccurate the remaining computation time will be. This is to be expected and in general, there is no solution (which is why it's called an approximation). We can still get the elapsed computation time or percentage with complete accuracy.
The underlying assumption of any estimation of "time left" algorithms is each sub task takes approximately the same computation time (assuming one wants a linear result). For example, if we have a parallel approach where 99 tasks are very quick and 1 task is very slow, our estimation will be grossly inaccurate. Our counter will zip up to 99 pretty quick then sit on the last percentage until the slow task completes. We could linearly interpolate and do further estimation to get a smoother countdown but ultimately there is a breaking point.
The following code demonstrates how to measure the parallel for efficiently. Note the time at 100% is the true total execution time and can be used as a reference.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
namespace ParallelForTiming
{
class Program
{
static void Main(string[] args)
{
var sw = new Stopwatch();
var pct = 0.000001;
var iter = 20;
var time = 20 * 1000 / iter;
var p = new ParallelOptions(); p.MaxDegreeOfParallelism = 4;
var Done = false;
Parallel.Invoke(() =>
{
sw.Start();
Parallel.For(0, iter, p, (i) => { Thread.Sleep(time); lock(p) { pct += 1 / (double)iter; }});
sw.Stop();
Done = true;
}, () =>
{
while (!Done)
{
Console.WriteLine(Math.Round(pct*100,2) + " : " + ((pct < 0.1) ? "oo" : (sw.ElapsedMilliseconds / pct /1000.0).ToString()));
Thread.Sleep(2000);
}
}
);
Console.WriteLine(Math.Round(pct * 100, 2) + " : " + sw.ElapsedMilliseconds / pct / 1000.0);
Console.ReadKey();
}
}
}
This is almost impossible to answer.
First of all, it's not clear what all the steps do. Some steps may be I/O-intensive, or computationally intensive.
Furthermore, Parallel.For is a request -- you are not sure that your code will actually run in parallel. It depends on circumstances (availability of threads and memory) whether the code will actually run in parallel. Then if you have parallel code that relies on I/O, one thread will block the others while waiting for the I/O to complete. And you don't know what other processes are doing either.
This is what makes predicting how long something will take extremely error-prone and, actually, an exercise in futility.
This problem is a tough one to answer. The problems with timing that you refer to using very long steps or a large number of very short steps are likley related to that your loop will be working at the edges of what the parallel partitioner can handle.
Since the default partitioner is very dynamic and we know nothing about your actual problem there is no good answer that allows you to solve the problem at hand while still reaping the benefits of parallel execution with dynamic load balancing.
If it is very important to achive a reliable estimation of projected runtime perhaps you could set up a custom partitioner and then leverage your knowledge about the partioning to extrapolate timings from a few chunks on one thread.
Here's a possible solution to measure the average of all previously finished tasks. After each task finishes, an Action<T> is called where you could summarize all times and divide it by the total tasks finished. This is however just the current state and has no way to predict any future tasks / averages. (As others mentioned, this is quite difficult)
However: You'll have to measure if it fits for your problem because there is a possibility for lock contention on both the method level declared variables.
static void ComputeParallelForWithTLS()
{
var collection = new List<int>() { 1000, 2000, 3000, 4000 }; // values used as sleep parameter
var sync = new object();
TimeSpan averageTime = new TimeSpan();
int amountOfItemsDone = 0; // referenced by the TPL, increment it with lock / interlocked.increment
Parallel.For(0, collection.Count,
() => new TimeSpan(),
(i, loopState, tlData) =>
{
var sw = Stopwatch.StartNew();
DoWork(collection, i);
sw.Stop();
return sw.Elapsed;
},
threadLocalData => // Called each time a task finishes
{
lock (sync)
{
averageTime += threadLocalData; // add time used for this task to the total.
}
Interlocked.Increment(ref amountOfItemsDone); // increment the tasks done
Console.WriteLine(averageTime.TotalMilliseconds / amountOfItemsDone + ms.");
/*print out the average for all done tasks so far. For an estimation,
multiply with the remaining items.*/
});
}
static void DoWork(List<int> items, int current)
{
System.Threading.Thread.Sleep(items[current]);
}
I would propose having the method being executed at each step report when it is done. This is slightly tricky with thread safety of course, so that is something to remember when implementing. This will let you keep track of number of finished tasks out of the total, and also makes it (sort of) easy to know the time spent on each individual step, which is useful to remove outliers etc.
EDIT: Some code to demonstrate the idea
Parallel.For(startIdx, endIdx, idx => {
var sw = Stopwatch.StartNew();
DoCalculation(idx);
sw.Stop();
var dur = sw.Elapsed;
ReportFinished(idx, dur);
});
The key here is that ReportFinished will give you continuous information about number of finished tasks, and the duration of each of them. This enables you to do some better guesses about how long time remains by doing statistics on this data.
Here i wrote class that mesures time and speed
public static class Counter
{
private static long _seriesProcessedItems = 0;
private static long _totalProcessedItems = 0;
private static TimeSpan _totalTime = TimeSpan.Zero;
private static DateTime _operationStartTime;
private static object _lock = new object();
private static int _numberOfCurrentOperations = 0;
public static void StartAsyncOperation()
{
lock (_lock)
{
if (_numberOfCurrentOperations == 0)
{
_operationStartTime = DateTime.Now;
}
_numberOfCurrentOperations++;
}
}
public static void EndAsyncOperation(int itemsProcessed)
{
lock (_lock)
{
_numberOfCurrentOperations--;
if (_numberOfCurrentOperations < 0)
throw new InvalidOperationException("EndAsyncOperation without StartAsyncOperation");
_seriesProcessedItems +=itemsProcessed;
if (_numberOfCurrentOperations == 0)
{
_totalProcessedItems += _seriesProcessedItems;
_totalTime += DateTime.Now - _operationStartTime;
_seriesProcessedItems = 0;
}
}
}
public static double GetAvgSpeed()
{
if (_totalProcessedItems == 0) throw new InvalidOperationException("_totalProcessedItems is zero");
if (_totalProcessedItems == 0) throw new InvalidOperationException("_totalTime is zero");
return _totalProcessedItems / (double)_totalTime.TotalMilliseconds;
}
public static void Reset()
{
_totalProcessedItems = 0;
_totalTime = TimeSpan.Zero;
}
}
Example of usage and test:
static void Main(string[] args)
{
var st = Stopwatch.StartNew();
Parallel.For(0, 100, _ =>
{
Counter.StartAsyncOperation();
Thread.Sleep(100);
Counter.EndAsyncOperation(1);
});
st.Stop();
Console.WriteLine("Speed correct {0}", 100 / (double)st.ElapsedMilliseconds);
Console.WriteLine("Speed to test {0}", Counter.GetAvgSpeed());
}

Categories

Resources