How is the running time of the virtual machine calculated vs. how system time is calculated? I know I can get the current running time of the AVM by calling:
getTimer();
And I can get the current unix system time by doing:
new Date().getTime();
I know that the Timer class and Event.ENTER_FRAME event each come with their ups and downs, but I figured the 2 values I was comparing should stay consistently relative to each other. Here's how I'm testing it:
private var _appRunTime:int;
private var _appStartTime:int;
private var _systemTime:int;
private var _systemCurrentTime:int;
//called at application launch
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
_systemTime = new Date().getTime();
_appStartTime = getTimer();
}
//called on button click to see values
protected function button1_clickHandler(event:MouseEvent):void
{
_systemCurrentTime = new Date().getTime();
_appRunTime = getTimer();
trace(_systemCurrentTime - _systemTime, _appRunTime - _appStartTime);
}
I don't understand why those numbers would slowly get out of sync. Using that code, I've found, at least on my computer, that the values grow apart from each other by about 3 milliseconds per minute, with the value coming from system time being the higher value and the value coming from AVM time being the lower.
Can anyone offer me an explanation what those are calculated on and why there would be that small, yet growing gap in their values as time passes?
On my system the same code gives no difference between getTimer() and getTime()
after ~10 mins the difference is always between 0 and 1 ms.
Maybe it's an issue of you system or the specific to the player you're running?
I'm running flash player 11 on Win 7 x64.
On my computer (Win 7 64-Bit), sometimes getTimer runs slower than Date.getTime() (system time), but sometimes getTimer() runs faster. The difference can range from -0.57ms/sec to 0.1ms/sec.
The result is independent of running in browser or Flash standalone player.
It will help you...
public static function getDaysBetweenDates(date1:Date,date2:Date):int
{
var one_day:Number = 1000 * 60 * 60 * 24
var date1_ms:Number = date1.getTime();
var date2_ms:Number = date2.getTime();
var difference_ms:Number = Math.abs(date1_ms - date2_ms)
return Math.round(difference_ms/one_day);
}
Related
I'm developing Windows 10 Universal App in C#/Xaml, I'm using await Task.Delay(delayInMilliseconds) to suspend a method for given time. My scenario is somewhat realtime, so it's very sensitive to time changes, and I need to make sure that when i suspend a method for let's say 8 millisecods it is suspended for 8 millisecods. I have noticed that the actual time span for which ** Task.Delay ** suspends the method differes from what is passed as delay parameter, for 1 up to 30 ms, the length of "deviation" being different in each call. So, when I want to sleep for 8 milliseconds, my system sleeps for 9 to 39 milliseconds, and this completly ruins my scenario.
So, my question what is the best way to substitute ** Task.Delay ** and to achieve good precision? For the time being I use this method:
public static void Delay1(int delay)
{
long mt = delay * TimeSpan.TicksPerMillisecond;
Stopwatch s = Stopwatch.StarNew();
while (true)
{
if (s.Elapsed.TotalMilliseconds > delay)
{
return;
}
}
}
but it guees it consumes a lot of resources, that is 100% of a processor's core. If an user has small number of processor's cores, this would be very insufficient.
According to msdn it's not possible to achieve more accuracy due to system clock resolution:
This method depends on the system clock. This means that the time
delay will approximately equal the resolution of the system clock if
the millisecondsDelay argument is less than the resolution of the
system clock, which is approximately 15 milliseconds on Windows
systems.
Seems like I've found a sattisfactory solution: using ManualResetEvent(false).WaitOne(delay) instead of await Task.Delay(delayInMilliseconds).
I've used following code to test both methods:
async void Probe()
{
for (int i = 0; i < 1000; i++)
{
// METHOD 1
await Task.Delay(3);
// METHOD 2
new System.Threading.ManualResetEvent(false).WaitOne(3);
}
}
The code above should take exactly 3 seconds to execute. With METHOD 2 it took around 3300 ms, so the error is 0.3 ms per call. Acceptable for me. But the METHOD 1 took around 15 seconds (as mentioned by others and explained above) to execute which gives totally unacceptable error for my scenario.
EDIT: WaitOne() is a blocking call, so you'll probably want to run it as a task to get it off the UI thread (or any other thread with a message pump). #Abel has pointed out another high-res timer approach that is already baked into a task and will run in an alternate thread as shown here: (https://stackoverflow.com/a/62588903/111575). That approach makes cpu-intensive calls to Thread.Spinwait() and Thread.Sleep(0) for small intervals.
You should use multi-media timers. Those are much accurate.
Take a look here:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/2024e360-d45f-42a1-b818-da40f7d4264c/accurate-timer
After working hard I found a solution to sleep the thread for specific time and the error is just 3 to 4 microseconds on my Core 2 Duo CPU 3.00 GHz.
Here it is:
Here is code.(C# code is also given at the end.) Use "ThreadSleepHandler":
Public Class ThreadSleepHandler
Private Stopwatch As New Stopwatch
Private SpinStopwatch As New Stopwatch
Private Average As New TimeSpan
Private Spinner As Threading.SpinWait
Public Sub Sleep(Time As TimeSpan)
Stopwatch.Restart()
If Average.Ticks = 0 Then Average = GetSpinTime()
While Stopwatch.Elapsed < Time
If Stopwatch.Elapsed + Average < Time Then
Average = TimeSpan.FromTicks((Average + GetSpinTime()).Ticks / 2)
End If
End While
End Sub
Public Function GetSpinTime() As TimeSpan
SpinStopwatch.Restart()
Spinner.SpinOnce()
SpinStopwatch.Stop()
Return SpinStopwatch.Elapsed
End Function
End Class
Here is example code:
Sub Main()
Dim handler As New ThreadSleepHandler
Dim stopwatch As New Stopwatch
Do
stopwatch.Restart()
handler.Sleep(TimeSpan.FromSeconds(1))
stopwatch.Stop()
Console.WriteLine(stopwatch.Elapsed)
Loop
End Sub
For c# programmers here is code (I have converted this code but I am not sure):
static class Main
{
public static void Main()
{
ThreadSleepHandler handler = new ThreadSleepHandler();
Stopwatch stopwatch = new Stopwatch();
do {
stopwatch.Restart();
handler.Sleep(TimeSpan.FromSeconds(1));
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
} while (true);
}
}
public class ThreadSleepHandler
{
private Stopwatch Stopwatch = new Stopwatch();
private Stopwatch SpinStopwatch = new Stopwatch();
private TimeSpan Average = new TimeSpan();
private Threading.SpinWait Spinner;
public void Sleep(TimeSpan Time)
{
Stopwatch.Restart();
if (Average.Ticks == 0)
Average = GetSpinTime();
while (Stopwatch.Elapsed < Time) {
if (Stopwatch.Elapsed + Average < Time) {
Average = TimeSpan.FromTicks((Average + GetSpinTime()).Ticks / 2);
}
}
}
public TimeSpan GetSpinTime()
{
SpinStopwatch.Restart();
Spinner.SpinOnce();
SpinStopwatch.Stop();
return SpinStopwatch.Elapsed;
}
}
Note:
"ThreadSleepHandler" is thread unsafe. You cannot use a single "ThreadSleepHandler" for multiple threads.
The first sleep time will not be enough accurate.
In my tests, I found that DispatcherTimer at 20ms intervals will deliver sufficiently smooth animation if you must do it in code. Doing it in XAML is another alternative as already mentioned.
I've created the standard player for dynamic sounds in a web app like so:
var _dynamicAudio:Vector.<Number> = new Vector.<Number>();
var _sampleIndex:uint = 0;
// ..Code to generate '_dynamicAudio' samples omitted
var _sound:Sound = new Sound();
_sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataEvent);
_sound.play();
function onSampleDataEvent(event:SampleDataEvent):void {
var samplesRead:int = 0;
while (samplesRead <= 8192 && _sampleIndex < _dynamicAudio.length) {
var sample:Number = _dynamicAudio[_sampleIndex];
event.data.writeFloat(sample);
event.data.writeFloat(sample);
_sampleIndex++;
_samplesRead++;
}
}
However, on slower computers (or if I stress my own by opening other applications) the audio tends to 'garble' occasionally. It sounds like it gets stuck looping over a block of the most recent samples. When this happens, I've noticed that event.position jumps by some multiple of 8192, which would also seem to imply that onSampleDataEvent isn't being called for a few consecutive chunks of samples. If that's true, it would seem this issue is unavoidable. What I'd like to know is if there's any way to detect the garbling before it happens so I can pause the audio in place of the awful noise? Thanks!
It might be that the while() loop is heavy and you don't always have the memory/CPU power to process it. So it freezes and gives you the effect you described.
It might be possible to break up the loop into smaller loops, thus evening out the CPU load. At the same time processing the event far ahead enough to seamlessly playback the audio.
The following code is not tested and is only an example of how breaking up a loop could look like:
var _dynamicAudio:Vector.<Number> = new Vector.<Number>();
var _sampleIndex:uint = 0;
// ..Code to generate '_dynamicAudio' samples omitted
var _sound:Sound = new Sound();
_sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataEvent);
_sound.play();
function onSampleDataEvent(event:SampleDataEvent):void {
var samplesRead:int = 0;
writeSamples(0, event);
}
function writeSamples(counter:int, eventReference:SampleDataEvent):void
{
var startTime:int = getTimer();
while (samplesRead <= (8192 - counter) && _sampleIndex < _dynamicAudio.length)
{
// check if the processing takes too long
if (getTimer() - startTime > 5)
{
writeSamples(counter, eventReference);
break;
}
counter++;
var sample:Number = _dynamicAudio[_sampleIndex];
event.data.writeFloat(sample);
event.data.writeFloat(sample);
_sampleIndex++;
_samplesRead++;
}
}
The main idea of the previewed code is to:
1) Check if the while loop is executed for too long. In my example 5ms is the limit
2) Break the loop if the execution is too long and start the loop again from the place it was stopped at.
If the whole process takes less than the limit, the loop will finish in one go.
You may want to refactor the code as it is not optimized and creates a lot of garbage instead of reusing objects.
I have to make a 5 minute countdown clock as an assignment. I was given the basis of a as3 and told to add 'Start' - 'Reset' - 'Stop' buttons. So far I have a respectable countdown going, but no way to control it. I'm new to as2 and flash so I hope this isn't one of those "If you know that, you should know your answer" situations. Anything i try to find on the web as far as tuts don't really help me so if anyone could just tell me if I'm on the right path or eve if it's possible to ass buttons to this code to do whats stated above. Thanks in adv :)
var secs = "0" + 0;
var mins = 5;
timerDisplay.text = mins + ":" + secs;
var timerInterval = setInterval(countDown,1000);
//DISPLAYS DYNAMIC TEXT
function countDown()
{
secs--;
if (secs < 0)
{
secs = 59;
mins--;
}
if (secs < 10)
{
var secs2 = "0" + secs;
}
else
{
var secs2 = secs;
}
if (mins == 0 && secs == 0)
{
clearInterval(timerInterval);//STOPS TIME # ZERO
}
timerDisplay.text = mins + ":" + secs2;
}
As this is an assignment, I won't give you any code, just some ideas to get you on your way to writing your own.
You may want to add two (possibly three) buttons to the stage. One button could be the reset button and another could be a button that trades off between being start and stop (depending on whether the timer is currently running).
The only code necessary for a reset button, is something that sets your min variable and your secs variable back to their original values (possibly plus 1 second because of your interval code). If you need help getting started with buttons clicks throwing functions check out the mc.onPress method.
The only code necessary for a stop button, is something that stops your interval counter from continuing to count. I believe you already have something doing that when "clear" your timer at zero.
The only code necessary for a start button, is something that restarts your interval counter. You do something of the sort when you first start your timerInterval.
This won't work if someone decides to click on the start button after you have finished the countdown or if someone decides to click the start button multiple times.
In the first case, the countdown will continue into negative numbers, so you may want to write an if statement that doesn't allow that to happen (inside of the start button function).
And in the second case, the countdown will get faster and faster each time the button is pressed. Creating a boolean that keeps track of whether the program is stopped could possibly help with that problem.
To clarify a statement I made above about the interval code: Your code will forever decrement every 1000 milliseconds. The text box is only ever being refreshed when you decrement, so if you try to reset with exactly 5 minutes and zero seconds, you will see the numbers jump to 4:59 and then keep decrementing. If you reset to 5 minutes and 1 second, the numbers will appear to jump to 5:00 and then decrement from there.
I hope this helps!
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Test extends MovieClip {
private var _timer:Timer = null;
private var _repeatCount:int = 0;
private var _totalMinutes:int = 5;
public function Test() : void {
addEventListener(Event.ADDED_TO_STAGE, _Init);
}
private function _Init(e:Event) : void {
_repeatCount = _totalMinutes * 60;
_timer = new Timer(1000, _repeatCount);
_timer.addEventListener(TimerEvent.TIMER, _OnTimerFired);
_timer.start();
}
private function _OnTimerFired(e:TimerEvent) : void {
var minRem:int = (_repeatCount - _timer.currentCount) / 60 ;
var secRem:int = (_repeatCount - _timer.currentCount) % 60;
trace(minRem + ":" + secRem);
}
}
}
I have created stopwatch which consist of two classes. First is stopwatchModel. Second is stopwatchView. My stopwatch is working but it is showing less time than how much time it last for real. It looks like my stopwatch is slower than reality.
StopwatchModel
private function initStopwatchModel():void{
timer = new Timer(100,0);
timer.addEventListener(TimerEvent.TIMER,onTimer);
}
private function onTimer(e:TimerEvent):void{
decsec++;
if (decsec == 10){
sec++;
decsec=0;
if (sec == 60){
sec = 0;
min++;
}
}
playerTimeString = min + ":" + sec + ":" + decsec + "0";
dispatchEvent(new Event("NEW_TIME"));
}
StopwatchView
private function initModelEventListeners(){
_model.addEventListener("NEW_TIME",onNewTime);
}
//update textoveho pola, vzdy ked sa zmeni cas
private function onNewTime(e:Event):void{
textFieldStopWatch.text = _model.playerTimeString;
}
Thank you for answer
Because timer is not fully accurate but it is somehow dependent on the frame rate so it finds the closest interval that is multiple to one frame time.
I would recommend you to save getTimer() return using http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#getTimer() when the application starts and then measure it on timer and calculate the difference - this will work for sure.
The problem is also documented at http://www.computus.org/journal/?p=22
You should be using the getTimer function, not the Timer class. See for example https://stackoverflow.com/a/12495538/842685
I have a generative art app, and I'd like it to draw as many cycles as possible each frame without reducing the framerate. Is there a way to tell how much time is left until the screen updates/refreshes?
I figure if I can approximate how many milliseconds each cycle takes, then I can run cycles until the amount of time left is less than the average or the peak cycle time, then let the screen refresh, then run another set of cycles.
If you want your app to run at N frames per second, then you can draw in a loop for 1/N seconds*, where N is typically the stage framerate (which you can get and set):
import flash.utils.getTimer;
import flash.events.Event;
private var _time_per_frame:uint;
... Somewhere in your main constructor:
stage.frameRate = 30;
_time_per_frame = 1000 / stage.frameRate;
addEventListener(Event.ENTER_FRAME, handle_enter_frame);
...
private function handle_enter_frame(e:Event):void
{
var t0:uint = getTimer();
while (getTimer()-t0 < _time_per_frame) {
// ... draw some stuff
}
}
Note that this is somewhat of a simplification, and may cause a slower resultant framerate than specified by stage.frameRate, because Flash needs some time to perform the rendering in between frames. But if you're blitting (drawing to a Bitmap on screen) as opposed to drawing in vector or adding Shapes to the screen, then I think the above should actually be pretty accurate.
If the code results in slower-than-desired framerates, you could try something as simple as only taking half the allotted time for a frame, leaving the other half for Flash to render:
_time_per_frame = 500 / stage.frameRate;
There are also FPS monitors around that you could use to monitor your framerate while drawing. Google as3 framerate monitor.
Put this code to main object and check - it will trace time between each frame start .
addEventListener(Event.ENTER_FRAME , oef);
var step:Number = 0;
var last:Number = Date.getTime();
function oef(e:Event):void{
var time:Number = Date.getTime();
step = time - last;
last = time;
trace(step);
}