|
-
Oct 17th, 2010, 02:50 AM
#1
Thread Starter
Junior Member
Too fast for VB to detect? Stopwatch.
Hi,
I put
Label1.Text = Watch.Elapsed.Milliseconds
And notice that it goes from 0 to 1000 milliseconds and then back to 0 starting over every time.
Ok, no problems
Then I do some tests and put,
If e key pressed = True Then
Count = Watch.Elapsed.Milliseconds
label2.text=count
End If
Whenever I press e, it logs the value in count and displays it.
No problems.
Now if i do this,
If Watch.Elapsed.Milliseconds = 5 (or any number from 0 - 1000) Then
End
End If
This should end program once it hits 5 milliseconds.
But the problem is it doesn't.
On one of my test runs i notice it does end, but only after a little while. Does this mean VB has a hard time detecting the stopwatch or something?
How can i fix this?
(I am beginner so please, not too technical or vague.)
BTW: Windows XP Pro 64bit,
VB.NET 2010 Express
-
Oct 17th, 2010, 09:44 AM
#2
Re: Too fast for VB to detect? Stopwatch.
The following code does two things. It automatically closes the program after some period of time, and times the interval between Button1 clicks. You will need a form with a label and button to see the code work.
Code:
Public Class Form1
Dim stpw As New Stopwatch
Dim tmr As New Windows.Forms.Timer
Private Sub Form1_Shown(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Shown
AddHandler tmr.Tick, AddressOf tmr_Tick 'add handler for timer
tmr.Interval = 100 'set how often (in ms.) to check
tmr.Start() 'start the timer
stpw.Reset() 'start the stopwatch
stpw.Start()
End Sub
Dim stopIn As New TimeSpan(0, 0, 30) '30 seconds (hours,minutes,seconds)
Private Sub tmr_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
'close program in stopIN seconds
If stpw.Elapsed > stopIn Then Me.Close()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Static lastTS As New TimeSpan
If lastTS.TotalMilliseconds = 0 Then 'first time
lastTS = stpw.Elapsed
Exit Sub
End If
'display time between button clicks
Dim curElapsed As TimeSpan = stpw.Elapsed
Label1.Text = (curElapsed - lastTS).ToString
lastTS = curElapsed
End Sub
End Class
-
Oct 17th, 2010, 09:45 AM
#3
New Member
Re: Too fast for VB to detect? Stopwatch.
I'm afraid the StopWatch control simply isn't accurate enough for whatever it is you're trying to achieve. If you simply want to see when a certain amount of time has passed, you could do it using a thread.
vb Code:
Dim i As UInt32 = 0 While (i < 5) Threading.Thread.Sleep(1) End While '5 ms passed
Or alternatively replacing
vb Code:
If Watch.Elapsed.Milliseconds = 5
in your code with
vb Code:
If Watch.Elapsed.Milliseconds >= 5
in which case it would fire if the elapsed milliseconds are either 5, or bigger than 5.
-
Oct 17th, 2010, 11:16 AM
#4
Re: Too fast for VB to detect? Stopwatch.
Ya. The problem is that you are checking for exactly 5 milliseconds. That means that it will only be true if the the count is 5 at the exact instant that the condition is tested. Not a very likely scenario.
However, it does bring up the question as to what you are trying to achieve. Are you just playing around with the stopwatch, or is there some ultimate objective to those tests?
My usual boring signature: Nothing
 
-
Oct 17th, 2010, 11:50 AM
#5
Re: Too fast for VB to detect? Stopwatch.
 Originally Posted by GinGin
I'm afraid the StopWatch control simply isn't accurate enough for whatever it is you're trying to achieve. If you simply want to see when a certain amount of time has passed, you could do it using a thread.
vb Code:
Dim i As UInt32 = 0
While (i < 5)
Threading.Thread.Sleep(1)
End While
'5 ms passed
Or alternatively replacing
vb Code:
If Watch.Elapsed.Milliseconds = 5
in your code with
vb Code:
If Watch.Elapsed.Milliseconds >= 5
in which case it would fire if the elapsed milliseconds are either 5, or bigger than 5.
This
Code:
Dim i As UInt32 = 0
While (i < 5)
Threading.Thread.Sleep(1)
End While
'5 ms passed
assumes, incorrectly, that the line after Threading.Thread.Sleep(1) will execute exactly 1 ms. later, and that the code takes 0 time to execute.
I agree with Shaggy, what is the OP trying to accomplish?
-
Oct 17th, 2010, 12:09 PM
#6
Re: Too fast for VB to detect? Stopwatch.
 Originally Posted by GinGin
I'm afraid the StopWatch control simply isn't accurate enough for whatever it is you're trying to achieve. If you simply want to see when a certain amount of time has passed, you could do it using a thread.
Your information about StopWatches is out of date. Any PC which passes the "Vista Ready" test (i.e. practically every PC made in the last 8 years) has a high resolution stopwatch which counts Ticks of about 250 nanoseconds. You use it by checking the stopwatch's ElapsedTicks reading and dividing by StopWatch.Frequency (shared) to get the number of seconds. But starting and reading the StopWatch has an overhead of 2-3 microseconds, which effectively limits the accuracy to that level. But it's fine for measuring fractions of milliseconds. Using threads won't work with any accuracy because they communicate through event queues. BB
-
Oct 17th, 2010, 12:19 PM
#7
New Member
Re: Too fast for VB to detect? Stopwatch.
 Originally Posted by boops boops
Your information about StopWatches is out of date. Any PC which passes the "Vista Ready" test (i.e. practically every PC made in the last 8 years) has a high resolution stopwatch which counts Ticks of about 250 nanoseconds. You use it by checking the stopwatch's ElapsedTicks reading and dividing by StopWatch.Frequency (shared) to get the number of seconds. But starting and reading the StopWatch has an overhead of 2-3 microseconds, which effectively limits the accuracy to that level. But it's fine for measuring fractions of milliseconds. Using threads won't work with any accuracy because they communicate through event queues. BB
By inaccurate I didn't mean the StopWatch wouldn't hit a point where it's ElapsedMilliseconds property is 5, but the lousy odds of managing to test a condition at that exact time.
-
Oct 17th, 2010, 12:24 PM
#8
Re: Too fast for VB to detect? Stopwatch.
To test this theory I wrote this code:
Code:
Dim stwTimer As Stopwatch = Stopwatch.StartNew()
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
stwTimer.Start()
While stwTimer.ElapsedMilliseconds < 2000
TextBox1.AppendText(stwTimer.ElapsedMilliseconds.ToString & vbCrLf)
End While
stwTimer.Stop()
End Sub
What it does it starts the stopwatch and appends the elapsedmilliseconds to a multiline textbox until 2 seconds have passed. Even though it is a really small loop I noticed 2 very important things. The first data written is 1913, which means the 2 seconds are almost up before the "while" completes the first loop! the second thing is that some numbers repeat, sometimes more than twice (like the 1914) but then some are skipped (1927) which tell me that performance of the code decreases while the textbox is being filled and in that case is not reliable to try to catch a specific milisecond.
Here's a partial output of the code:
1913
1914
1914
1914
1915
1915
1916
1916
1917
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1928
1929
1930
Last edited by kaliman79912; Oct 17th, 2010 at 12:29 PM.
-
Oct 17th, 2010, 12:27 PM
#9
New Member
Re: Too fast for VB to detect? Stopwatch.
I tried that earlier today with a console app and only 50 numbers, some of which were still repeated and some skipped.
-
Oct 17th, 2010, 12:43 PM
#10
Re: Too fast for VB to detect? Stopwatch.
I would expect that the textbox would slow over time, since that append text is going to throw out the existing string, create a new string with both the old information and the new information, then paint the whole thing into the textbox. That last step seems like it will get slower over time, as will the earlier steps, though probably those earlier ones won't change enough for anybody to really notice.
My usual boring signature: Nothing
 
-
Oct 17th, 2010, 01:01 PM
#11
Re: Too fast for VB to detect? Stopwatch.
The individual times recorded can't mean much. Besides the Append and the ToString methods, they could be affected by things going on in the framework (garbage collecting) and in the system (other processes). To measure how long it takes to append stuff to a textbox (assuming that's what you want to do) I would take an average like this:
Code:
Dim sw as StopWatch = StopWatch.Startnew
For i as integer = 0 to 1000
TextBox1.AppendText("SomeText" & vbCrLf)
Next
Console.WriteLine((sw.ElapsedMilliseconds / 1000).ToString("0.00"))
BB
-
Oct 17th, 2010, 01:03 PM
#12
Re: Too fast for VB to detect? Stopwatch.
Try it this way to get a better idea of the speed and accuracy:
Code:
Dim stwTimer As New Stopwatch
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
RichTextBox1.Clear()
stwTimer.Reset()
stwTimer.Start()
Dim sb As New System.Text.StringBuilder
While stwTimer.ElapsedMilliseconds < 5 'limit the damage
sb.AppendLine(stwTimer.ElapsedTicks.ToString) 'note ticks
End While
stwTimer.Stop()
RichTextBox1.AppendText(sb.ToString)
End Sub
I am not sure what we are discussing anymore.
-
Oct 17th, 2010, 01:31 PM
#13
Re: Too fast for VB to detect? Stopwatch.
The point is, to answer the original question posted by Silhorn, the code is not reliable enaugh to catch a specific number in the ElapsedMiliseconds method in any case. You should do a range check or a grater than or some other variable to stop your code because most times you won't catch the 5.
-
Oct 17th, 2010, 02:10 PM
#14
Re: Too fast for VB to detect? Stopwatch.
Really?
Code:
Dim stwTimer As New Stopwatch
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
stwTimer.Reset()
stwTimer.Start()
Do While stwTimer.ElapsedMilliseconds < 5 'limit the damage
Loop
If stwTimer.ElapsedMilliseconds = 5 Then Stop
stwTimer.Stop()
End Sub
Not that I am recommending this. As has been mentioned, the OP needs to provide a larger context.
-
Oct 18th, 2010, 01:29 AM
#15
Thread Starter
Junior Member
Re: Too fast for VB to detect? Stopwatch.
Thanks for your replies 
But seems like I have to provide more information.
I am trying to design something that gives my program a heads up when every 10 milliseconds have passed. So maybe something like a Switch variable that changes to one when that 10th millisecond has been reached and back to 0 when it's over and then back to 1 when the next 10 milliseconds...
This is so that i can get my program to execute something every 10 milliseconds.
I knew this was going to be a little problem when i found out the system.timer and form timers could not output as low as 1 millisecond intervals.
I did some searching and found out there was 2 ways that might work. QueryPerformanceCounter was said to have a resolution of less than 1millisecond. Then i found somewhere that someone said StopWatch was a command that was the same functionality as QueryPerformanceCounter.
I did just found out though, and as stated here that the reason why it didn't pick up my 5ms was because the all the other coding I have in my program also takes time to run so that's probably why it may have missed the 5ms or any millisecond i put in. I confirmed this by making a new program with nothing but the code I used for the timing and it seemed to catch the 5ms pretty much most of the time.
Is there a way I can make this workout without making it complicated?
It's not very important but If i can get it to work it would be nice.
-
Oct 18th, 2010, 03:09 AM
#16
Thread Starter
Junior Member
Re: Too fast for VB to detect? Stopwatch.
I think i've found a solution.
Discovered that threads are things which you can run 2 sections of code at the same time, I have done some basic testing so far and it looks like it works.
I will report back if it is all good.
-
Oct 18th, 2010, 03:45 AM
#17
Re: Too fast for VB to detect? Stopwatch.
You may want to try using the System.Timers.Timer instead of the normal Forms timer. The advantage is that it automatically uses a separate thread so it isn't held up by whatever else is going on in your program. By default it's a one-shot timer, but if you set its AutoReset property to true it fires at regular intervals. The event is called Elapsed instead of Tick but you program it in much the same way as a normal Timer.Tick.
There are a few restrictions, though, because it uses a separate thread. For example, you can't update the UI by using Refresh or Update because that would cause a cross-threading error. But Invalidate works, because that goes via a queue.
Like any events, a Forms.Timer.Tick or System.Timers.Timer.Elapsed event is only approximate. It's possible to measure time accurately down to zillionths of a second using a StopWatch or DateTime, but to trigger anything with that information in code requires raising an event and that doesn't happen in real time. This applies to VB.Net, CSharp and all the other managed languages. Normal Timer events can only be relied on to be accurate at an interval about 55 milliseconds (according to MSDN). An interval of 10 milliseconds is still useful for various things, but it's likely to be off by a few milliseconds now and then.
There is also a timer called a Multimedia Timer which is used in WPF. It's a bit more accurate, I believe something like 30 milliseconds guaranteed. I've seen an article about using it in Windows Forms somewhere on the Code Project, but I haven't tried it.
BB
-
Oct 18th, 2010, 06:26 AM
#18
Re: Too fast for VB to detect? Stopwatch.
What does, "I am trying to design something that gives my program a heads up when every 10 milliseconds have passed." In particular, "heads up."
Code:
Public Class Form1
Private Sub Form1_FormClosing(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If Threading.Interlocked.Read(isRun) = 1L Then
Button1.PerformClick()
e.Cancel = True
Exit Sub
End If
End Sub
Private Sub Form1_Shown(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Shown
myDelegate = New CaptureIntrvl(AddressOf foobar)
Dim l As Long = Threading.Interlocked.Exchange(isRun, 1L)
Dim t As New Threading.Thread(AddressOf foo)
t.Start()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim l As Long = Threading.Interlocked.Exchange(isRun, 0L)
End Sub
Public Sub foobar(ByVal d As DateTime)
TextBox1.Text = d.ToString("HH:mm:ss.ffffff")
End Sub
Dim isRun As Long = 0L
Delegate Sub CaptureIntrvl(ByVal d As DateTime)
Public myDelegate As CaptureIntrvl
Public Sub foo()
Dim notify As New TimeSpan(0, 0, 0, 0, 10)
Dim d As DateTime = DateTime.Now
Do
If (DateTime.Now - d).TotalMilliseconds >= notify.TotalMilliseconds Then
d = DateTime.Now
Invoke(myDelegate, New Object() {d})
End If
Threading.Thread.Sleep(0)
Loop While Threading.Interlocked.Read(isRun) = 1L
End Sub
End Class
-
Oct 18th, 2010, 06:49 AM
#19
Re: Too fast for VB to detect? Stopwatch.
There is a difference, also, between 'after 10ms' and 'every 10ms'. In addition, with such a tiny span, it's unlikely you will get a reliable operation on a non-deterministic operating system. Further, what you do when the event is raised can (and most likely will) have a significant impact on your timing.
I believe the stopwatch object uses the performance timer objects 'under the hood', but I'd have to re-check that.
All these timers mentioned have essentially perfect resolution - that is, they can measure down to the tick level. However, the accuracy is highly dependent on the OS, the surrounding code and the hardware.
There will be a non-deterministic overhead that becomes much more significant as the interval you need to measure becomes smaller and smaller. While todays hardware and OS are of a much greater performance than [yesterday], measuring and doing something on a 10ms interval implies that it must be reliable and consistent - something you aren't going to get on a PC with a non-RTOS without specialized hardware.
"Ok, my response to that is pending a Google search" - Bucky Katt.
"There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
"Before you can 'think outside the box' you need to understand where the box is."
-
Oct 18th, 2010, 07:13 AM
#20
Re: Too fast for VB to detect? Stopwatch.
 Originally Posted by SJWhiteley
There is a difference, also, between 'after 10ms' and 'every 10ms'. In addition, with such a tiny span, it's unlikely you will get a reliable operation on a non-deterministic operating system. Further, what you do when the event is raised can (and most likely will) have a significant impact on your timing.
I believe the stopwatch object uses the performance timer objects 'under the hood', but I'd have to re-check that.
All these timers mentioned have essentially perfect resolution - that is, they can measure down to the tick level. However, the accuracy is highly dependent on the OS, the surrounding code and the hardware.
There will be a non-deterministic overhead that becomes much more significant as the interval you need to measure becomes smaller and smaller. While todays hardware and OS are of a much greater performance than [yesterday], measuring and doing something on a 10ms interval implies that it must be reliable and consistent - something you aren't going to get on a PC with a non-RTOS without specialized hardware.
I agree with you Stephen.
On my dual core system, just running this sample application, it appears to work. However I wouldn't bet my life on it always working for the reasons given by Stephen.
Code:
Public Class Form1
Private Sub Form1_FormClosing(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If Threading.Interlocked.Read(isRun) = 1L Then
Button1.PerformClick()
e.Cancel = True
Exit Sub
End If
End Sub
Private Sub Form1_Shown(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Shown
myDelegate = New CaptureIntrvl(AddressOf foobar)
Dim l As Long = Threading.Interlocked.Exchange(isRun, 1L)
Dim t As New Threading.Thread(AddressOf foo)
t.Start()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim l As Long = Threading.Interlocked.Exchange(isRun, 0L)
End Sub
Public Sub foobar(ByVal ts As TimeSpan)
TextBox1.Text = ts.TotalMilliseconds.ToString("N0")
End Sub
Dim isRun As Long = 0L
Delegate Sub CaptureIntrvl(ByVal ts As TimeSpan)
Public myDelegate As CaptureIntrvl
Public Sub foo()
Dim notify As New TimeSpan(0, 0, 0, 0, 10)
Dim d As DateTime = DateTime.Now
Do
Dim ts As TimeSpan = DateTime.Now - d
If ts.TotalMilliseconds >= notify.TotalMilliseconds Then
d = DateTime.Now
Invoke(myDelegate, New Object() {ts})
End If
Threading.Thread.Sleep(0)
Loop While Threading.Interlocked.Read(isRun) = 1L
End Sub
End Class
Last edited by dbasnett; Oct 18th, 2010 at 07:22 AM.
-
Oct 18th, 2010, 08:34 AM
#21
Re: Too fast for VB to detect? Stopwatch.
For this to work with any kind of reliability you would want multiple cores and not a battery. After all, you are effectively busy waiting on one core, which is going to suck the power out of a battery pretty fast.
My usual boring signature: Nothing
 
-
Oct 18th, 2010, 04:25 PM
#22
Re: Too fast for VB to detect? Stopwatch.
 Originally Posted by Shaggy Hiker
For this to work with any kind of reliability you would want multiple cores and not a battery. After all, you are effectively busy waiting on one core, which is going to suck the power out of a battery pretty fast.
Agreed. I did mention the code environment, and you point about the battery is excellent.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|