No More "Cool" Features Please Until Crippling Stuff Is Addressed

Launch day is finally here with a flurry of activity. It all looks wonderful and full of promise. But today my enthusiasm-swing’o’meter has barely registered. 4.0 for our standalone project can only be described as a non-event, when really it shouldn’t have been.

I’m a committed customer on a serious long-term project trying to communicate the issues that I’ve faced over 18 months of working in Unity all day nearly every day in the hope it leads to making a great product even better.

Issue 1: Incomplete Feature Implementations ( Grayed out as no longer relevant )
Okay, so the Linux build target is going to be really helpful if it all works. But earlier today I read in the Cursor API documentation that hardware cursors are only available on Windows and Mac. So that’s a piece of unusable functionality for us if it’s incomplete ( needs to include Linux, or perhaps the documentation is out of date ), much like the pathfinding was in 3.x and remains to this day. I’ve also discovered that only 32x32 cursors appear to be supported, and we have a lot of 48x48 or 64x64 cursors ( see a post on page 3 for more info ). These are but two of a number of features be they new or existing that the community have voiced their opinions on as being incomplete.

Issue 2: Mono 2.6 and Cripplingly Slow GC
The community has also complained exhaustively about the slow garbage collector. Many developers end up spending hundreds of hours rewriting code to avoid allocations - a hidden cost that has to be factored in. Unfortunately we can’t self-fix a closed API that returns new arrays or makes internal allocations that only serve to feed the problem. So we’re left tackling a periodic glitch in game play when the gc kicks in, causing the frame rate to hang for a brief but noticeable period, ruining the gaming experience. All those lovely 4.0 graphics are useless without an engine that runs smoothly - a claim made here. UT, please accept this as a request to eradicate allocations in the API by providing overloads that accept existing arrays for population and cleaning up sloppy code ( e.g. non cached lookups like .transform ), stop using sealed classes, and/or assign more resources to upgrading to Mono 2.8+.

Please note: obviously the title is intentionally a little bit silly to grab attention. We live in a world of commercial realities, and development of new features can and of course does happen in parallel to bug fixing because there is more than 1 developer. The community recognizes the need to be competitive, innovate and make sales to fund future development. The crux of this complaint is that we believe a greater priority needs to be given to more comprehensive implementations and fixing existing issues, a number of which have been around for a few years.

UPDATE 1
The thread has evolved beyond this OP to crystallize into two important questions:

  1. Has coding work started on a migration to Mono 2.8 ( not just talking about it ), or is it a case of it not being a priority right now, and 2.6 is considered good enough for the majority of users. If coding has started, what is the planned version number for release?

  2. Can the API be improved by 4.1 to eradicate allocations AND/OR open it up to allow the community to fix it?

UPDATE 2
There is a thorough response from Lucas@UT answering these questions. The focus of the discussion is now Issue 2.

UPDATE 3
If you notice allocations within API calls, please follow these steps:

a. Read all posts from this point in this topic to check a similar bug hasn’t already been reported.

b. Submit a bug report with the first line reading “[Function Call] API call causes C# allocation”. For example “Terrain.CullAllTerrains API call causes C# allocation

c. Make a post in this topic including the bug report id ( from your email confirmation ) and a deep profiler image highlighting the allocation

BEFORE POSTING
Please consider following the steps to escalation to keep the discussion focused.

On the .NET/Mono Garbage Collection, one slight problem - even using something like Visual Studio (as I do in my day job), the programmer has zero control over when the GC fires. The problem is the same as that in Java.

…However, you can have your classes inherit from IDisposable (causes the classes to be required to provide a public override void Dispose() method) to null any special resources that you are no longer using so that you can get the reference count for that class down to 0, so that the GC will be significantly more tempted to fire.

This is a problem I traverse every day in my day job. While you could do what you said and simply not allocate resources (one day, that I’ve got to see…), in the end it’s much easier and more effective to apply good software development practices.

I’m sure you’re right in claiming that Mono 2.8 would solve some issues, but it won’t avert the fact that the GC has some fundamental problems associated with it across the board, and across languages for that matter.

Yup, familiar with the general lack of control managed frameworks offer ( 10 years .NET experience prior to coming to Unity ). But do UT have the option to change that in mono given its open nature? That would be my suggestion if they didn’t want to update to mono 2.8.

Allocations are well managed upfront and nearly eradicated on a per frame basis during game play in Folk Tale. Now it’s mostly the odd third party component which hopefully a thread I ran a while back helped improve, unity’s own API where arrays are returned, or just unoptimized classes that call non cached variables ( came across one in pro water specular today ).

While mono 2.8 might get you a better garbage collector, it’s not actually true that you don’t control when garbage collection happens.
You can make garbage collection happen by calling GC.Collect(); It’s considered bad practice of course, but this way you can determine when it happens. If you do it every frame, you will have very little to collect, and therefor very little performance hit. As part of my normal work, we worked with Microsoft, and this was the only solution that worked all day, every day for our application that required us to limit pausing (non-game).

GC.Collect(0). Yup, being able to call it on demand is nice and all. But if you’re going to do that, you also need a means of preventing it firing off when it likes. The issue with mono 2.6 however is that it doesn’t matter whether you manually collect or let it do it automatically, the operation is simply far too slow when it happens.

I tested all time execution plans. GC performs badly under all, meaning avoiding unnecessary and regular allocation ( which will ultimately be treated as garbage ) is your only real option.

Honestly, losing your hat over not having a hardware cursor is over the top - is that really enough to completely spoil your excitement about 4.0? The garbage collection thingy I agree is a bit more of an issue, but ultimately overall it’s not a huge problem.

The opening post could hardly be described as losing One’s hat, even if it has taken 4 years to add a mandatory feature required by RTS games. We already have a hardware cursor solution that covers Windows and Mac. I was looking forward to adopting an integrated solution that covered all target platforms. The feature was highlighted to illustrate that partial feature coverage of target platform groups ( standalone = pc, mac, linux ) is not all that helpful. An equal comparison was made to the partial implementation of pathfinding in 3.x. Navmesh pathfinding solutions are only usable in a limited number of scenarios, and for that reason more comprehensive solutions include grid and list graph implementations as well.

Garbage Collection is a huge problem if you are working on a full-blown standalone game with long uninterrupted game play. It makes a project non-shippable without serious changes that compromise game design because of a quality defect. Sure, it’s not a problem on say turn based games where game play is broken into separate sections, or on a short platformer level with regular level loads. But in a sandbox RTS game with potentially hours of uninterrupted play, it is ultimately a huge problem.

Are you absolutely certain about that? The API is there, but I’ve heard it said that - in Unity at least - it doesn’t actually do anything, or that it’s only an advisory that the GC is free to ignore.

I very much agree with you.
I wasn’t aware of the specific hardware cursor problem, as I haven’t bothered to look at Unity 4 yet, nor do I need a cursor for what I’m working on currently, but I can see how that would be an issue. The only thing I can say is that I think Linux is still a developer preview/beta release, so maybe they will put some effort into this before it goes full release?
However, with regards to GC, I noticed this early on, and basically designed my game around an almost completely static memory footprint, which has been a pain to do nonetheless for something that has gotten quite a bit larger than what I initially planned, and as a result constantly uses more memory in each level than it probably could/should as a result.

Personally I see this as a fundamental problem with non open source middleware, and it would go a long way for Unity to make a concerted effort to not become like most middleware providers, which often ends up doing more harm than good, simply because of the constant need to add half done features and close off access to the internals to suit a business model, and limit upgrades on third party stuff (mono) simply because of whatever constraints/inefficiencies there are in their own development pipeline (or other reason?).

The up side is that Unity does a lot of things for us that make things easy, the down side is that if they are incomplete or don’t run well, our game is at the mercy of their system. Personally I don’t think a game engine product can follow the development methods of most other software, because often times a partially introduced feature in production software means you just need to do workarounds or some sort of extra steps to get something done. However, since the engine is integrated into our end product, half done or poorly implemented features are, in many cases, a much larger issue.

This thread is Stupid. The OP’s complete development life has ended dramatically because of a Hardware Cursor and a Garbage Collector.

Unity guys better stop production immediately as the OP has discovered crippling, AND I MEAN CRIPEELLING, errors that have changed the balance of power in the Universe.

Yeah I know, but, a bullshit thread deserves a bullshit reply.

yeah, this is stupid! Besides his particular arguments, unity is perfect!! Everything in unity works as expected, and I never had to make work around for an oft publicized and advertised feature anything in unity… ever! /sarcasm

while the GC problem has been spoken about, I want to also add that many of the half implemented features should be fixed, and optimized. I dont need more fancy bells and whistles, just fix whats there. I’m looking at svn support, asset bundles and path finding in particular, but there are other things that bug me that I’m not even thinking of now.

Actually Amon, this is not a stupid thread. Granted some of the complaint was pointless, the idea behind the complaint is completely valid. Way too much time has been put into making ‘cool’ features, and not providing some solutions for existing problems.

GC is a problem.

I dont have the problem atm, but thats cause I spent weeks re-writing code to avoid destroying anything. I also removed a bunch of cool features. I suspect, that if I ever get to the point where I can work on games full time, I will drop Unity.

The thread isnt that stupid if you have been lurking these forums. There have been posts that pop up from time to time where someone is complaining about very specific features that dont work as expected. This isnt a new thing and it will probably never go away, but I feel there is merit in the idea “Have all features working as expected, then work on new stuff”. But pre-existing features dont always sell product.

This.

The original poster’s choice of specifics might not be the ones I would have picked but his broad point is spot on. The GC is a problem and Asset Server is an unholy mess. I’ve only just recently set it up locally and now I realize just what a lot of work the guy who manages our Asset Server for work has to do. A couple of guys at work were reporting bugs in Asset Server nearly a year ago - really basic things like a failed commit blocking all incoming commits for 48 hrs - and the same basic bugs are still in there.

The problem isn’t only that they focus on headline features, it’s that they focus on anything which gets headlines. So anything a big developer needs gets priority, because a big developer using Unity gets them headlines. Mechanim gets priority because it gets headlines. Asset Server? Presumably a lot of the larger developers already use SVN, so this is way down the list. I’m not sure why the GC is such a low priority, but evidently there’s no publicity in it.

How about we still have cool new features AND old stuff gets fixed?

You know what they say… cant have your cake and eat it too

I really love using Unity, I really love Unity Technologies (UT), I’m amazed at the frequency of updates, there keenness to address bugs (when reported) and the value for money this can represent, especially compared to the last IDE I was using (Adobe/Macromedia Director = no update to 3D engine in 10 years).

However I completely agree with your premise. It is really frustrating to see incomplete features rushed out with new releases and then often forgotten about. Myself i’d site color32 as a good example. It was really cool that they added this to address part of the performance issue of having to use floats for colors as its not native for the common image data formats. However they still only let you update 24 or 32bit images and the color32 version of setpixels() isn’t overloaded to take a sub-rect! I haven’t been able to test out the navMesh since it was introduced, but again I felt far too many features were missing from it to call it complete and suspect many have not or will ever been retro-actively added. Again its just a missed opportunity.

I’d also make the point that i’m disappointed that UT seem to be so ‘game-centric’ focused too. As exciting and cool as many of the features of 4.0 and many 3.x releases were, i’d really welcome some effort on their part to support the wider market of developers using their IDE for non-game centric projects. A perfect example of this would be improved video support, at least offering mp4 (and streaming). For a recent high-profile project I needed to add a video tutorial, as it was browser based I had no choice to use the horrible ogv format. Not only did it produce larger files with poorer quality, but meant I couldn’t leverage say youtTube to store the video and stream it down. So I ended up having a youTube version and a dedicated ogv version for playback within the browser player.

I’m not really up on the whole mono versions, but I am confused as to why a major release version hasn’t switched to a more updated version. To my mind a major release is the perfect time to do this, due to the potential backward compatibility it might break ( which has often been an arguement for not updating to a newer version of mono).

In fact Unity’s whole major vs dot releases is something I don’t understand at all. From my perspective some of the 3.x releases were far more exciting and more feature packed than the 4.0 release. My expectation is that a major release introduces the most new and exciting features, then to releases fixes bugs, streamlines and improves existing features, but that doesn’t really seem to be the case with UT.

So all said and done I would very much like to see a release that focuses on improving what we’ve got before adding more stuff, most of which is sadly irrelevant for my day to day client work.

Well, you can do GC.Collect() …and optionally, GC.Collect(Int generationCount). If, to improve performance, you absolutely need to control a collection cycle, I say, sure. However, a question arises from your response: is it truly necessary to invoke the GC every frame? The engineer in me partially agrees with you, “yes, in certain circumstances.” (Specifically, something that some other engineer has coded particularly horridly. Maybe I’m missing something…but under what well-designed circumstances would it be necessary? This is a genuine question. I truly don’t see the perspective underlying that statement.)

However, the engineer in me also disagrees; I’ve done some work with C++, and one of the basic instruction patterns you have to use in that language, due to the low-level nature, is the Allocate, Use, Deallocate pattern. That is, define a resource, perform some operations. When the app no longer requires that resource, free it because something else probably needs that memory (thus, a more performant program that dosen’t starve the OS or other applications of resources…not that that is a serious concern in most modern OSes, let alone Unity.)

A good many programmers I’ve worked with (sadly enough) have mistaken the GC as an amenity that lops the D off of the AUD pattern. This is not the case; if you read the salient documentation, you find that it’s controlled by references. The GC was made smart enough to not deallocate something that is being used by something else in case it is still needed, to prevent those pesky NullRef exceptions that we C/C++/C# programmers hate (yes, you can still get NullRefs in C# if you’re not careful, or simply miss a spot!)

The reason in my post I brought up the IDisposable interface was that, since C# has no actual destructor in the same way that C++ does (there are finalizers, but it’s far from the same thing, given the control the GC has over itself), we need some way to clean up this reference count. Having objects be disposed when they are done hardly ensures that the GC will immediately clean them up, but as you said - if to improve performance you need to insta-perform a cleanup, well, you can always do GC.Collect(); GC.WaitForPendingFinalizers();

However, the GC is a nice convenience too. It does some of this stuff on a ‘when it thinks it should basis’, and there’s many situations where - if you’ve coded correctly - you really don’t need to concern yourself with invoking garbage collection. A small bit of design/architecture can make your game performant, with little need to directly invoke garbage collection.

Easy reader version: Use the right tool for the right job.

As far as I understand how GC works, it [almost] doesn’t matter how much garbage it collects. The thing that matters is how big is the dependency graph of objects that are still in use. The ideal case is all the allocated objects are garbage.

Calling GC.Collect() is considered bad practice, because it may move potential garbage from generation 0 to higher generations. But since the current Mono’s GC doesn’t support generations, calling GC.Collect() manually, I guess, is not a big deal.

It does work.

There are a lot of things that would be nice if they were finished but even before then I would prefer to see some decently complete documentation. Spending hours scouring the web or diving into the dll’s because some api functionality isn’t adequately covered has caused more lost time than anything else for me.