Replace Environment.TickCount in time calculations

devast
edited September 2010 in DotNet
After 4 days of struggling trying to find reason of jerky movement in my program (unity networking example port to photon) i found two very bad things with timing in photon/unity.

Photon use Environment.TickCount in PhotonPeer class to estimate server time. Two things go wrong here:
1. TickCount property is VERY inexact. I made little program that shows TickCount value and its delta is about 15-16 ticks (while unity time could be 11-21 ms).
2. And this one i think just a unity bug which i can't overcome. Using very same program from 1. i noticed that when you BUILD the project and run it, TickCount update rate goes down and practically i'm getting same value for 4-5(!!!) monobehaviour updates, while Time.time goes ok. This makes totally impossible to use photon timing routine for interpolation, because time is just not updating.

I made small addition to the PhotonUnity3d lib (btw, why this lib is only given in compiled variant?) and replaced all calls to Environment.TickCount to delegate LocalTime which returns integer and as name suggests give you the local time (you may guess i've used (int)(Time.time * 1000) in my client). That solved the problem. I've not fully tested the code yet, but my visual debugging info shows me jerkiness went away.

One may wander why not to replace Environment.TickCount calls to System.Diagnostics.Stopwatch functionality? Answer is - it doesn't work in unity web builds. So i found delegate to be perfect in this situation.

Comments

  • That comes as a surprise. The reasoning behind using TickCount was that it's cheap. Obviously it's too cheap.

    I'm trying to reproduce your findings but on Windows 7, I failed so far.
    Attached is my simple code to get a count of updates per TickCount value. It gave me 1 max, which seems fine.

    I'm going to check out on Mac now and in Unity 2.6 and 3 beta 7.
  • With the code above, I can't reproduce/track the issue at all.
    Am I missing something?

    Anyhow: It seems that some implementations might be buggy (we just don't know which) so I will add a delegate for this in the next release.

    And the client library is provided as binary only, because we don't want changes in there. We try to make it run on any platform but giving support when something is changed in those libs is pretty much impossible.

    We value feedback and are open for changes. Just let us know.
  • devast
    edited September 2010
    Here's the code i've used for testing
    using UnityEngine;
    using System.Collections;
    using System.Diagnostics;
    
    public class TooManyTimes : MonoBehaviour 
    {
    	System.Collections.Generic.Queue<string> times = new System.Collections.Generic.Queue<string>();
    	Stopwatch sw;
    
    	void Start()
    	{
    		sw = Stopwatch.StartNew();
    	}
    	
    	void Update () 
    	{
    		string timeline = "" + Time.time + "\t" + System.Environment.TickCount
    			+ "\t\t" + (double)sw.ElapsedTicks / Stopwatch.Frequency;
    		times.Enqueue(timeline);
    		if (times.Count > 70) times.Dequeue();
    	}
    	
    	void OnGUI()
    	{
    		int i = 0;
    		int j = 0;
    		foreach (string str in times)
    		{
    			GUI.Label(new Rect(j * Screen.width / 2, i * 20, Screen.width / 2, 20), str);
    			i++;
    			if (i % 35 == 0)
    			{				
    				j++;
    				i = 0;
    			}
    		}
    	}
    }
    

    Throw it on any gameobject, build the project and printscreen the result. I'm just printing TickCounts every update. Note that two other methods (unity time and stopwatch) works perfect, while TickCount not.
    Btw i'm using windowsXP. Also tested this in unity 3 beta, same results though.
  • I made two screenshots showing the problem.
  • If you can, please share your test code.
    Also let me know which Unity version you are using on which platform. Just to have an idea.
  • Here is unity project. Build it and see what happens.
    I'm using unity 2.6.1 on winXP

    ---

    One minute ago i found another interesting thing! Web build actually works! (it updates 15-16 per update but still works!). And standalone build works as i described in first post (see pictures above).
  • Not I got it: it's only in the standalone player builds. I verified this in Unity 2.6.1 and also in Unity 3b7. A very tricky bug! I began to think I missed something in my code...

    I reported a bug for Unity 3 but I guess it won't be fix anytime soon.
    The workaround will be a new lib where you can set a GetLocalTimeInMs delegate or so.
  • I reported a bug for Unity 3 but I guess it won't be fix anytime soon.
    That's why i decided to find a workaround. ;)
    The workaround will be a new lib where you can set a GetLocalTimeInMs delegate or so.
    I think you can assign some kind default delegate which return TickCount to not brake existing code.

    Thx for collaboration Tobias! Photon is a nice piece of software, keep it up! ;)