After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 604965 - Gst.Application.GstResolveType is very slow
Gst.Application.GstResolveType is very slow
Status: RESOLVED FIXED
Product: GStreamer
Classification: Platform
Component: gst-sharp
git master
Other All
: Normal normal
: 0.9.3
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2009-12-19 00:38 UTC by Maarten Bosmans
Modified: 2010-01-04 09:04 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Register some more basic GStreamer GTypes as managed types (1.14 KB, patch)
2009-12-26 11:36 UTC, Maarten Bosmans
committed Details | Review
Only look for types in assemblies that reference gstreamer-sharp (3.50 KB, patch)
2009-12-26 11:43 UTC, Maarten Bosmans
committed Details | Review
Only call GetTypes() once for each assembly (4.26 KB, patch)
2009-12-26 11:48 UTC, Maarten Bosmans
committed Details | Review
Handle the case where not all types of an assembly can be loaded (1.24 KB, patch)
2009-12-26 11:50 UTC, Maarten Bosmans
committed Details | Review
Load cache on Applicxation.Init, some more tweaks (3.22 KB, patch)
2009-12-28 22:42 UTC, Maarten Bosmans
committed Details | Review
Rollup of all 5 previous patches (5.22 KB, patch)
2009-12-28 22:45 UTC, Maarten Bosmans
rejected Details | Review

Description Maarten Bosmans 2009-12-19 00:38:10 UTC
After helping Richard with his bug, I found that GstResolveType was a major source for delay in my application. For example ElementFactory.Make("dshowvideosink") takes 1700ms.

Moreover, I found that it never found a matching type and thus always returns null, making it a useless excercise in assembly loading. It looks like it needs GTypeNameAttribute present on elements, but that attribute is never used in the gstreamer-sharp source.

Just removing Gst.GLib.GType.ResolveType += GstResolveType; from RegisterManagedTypes reduced initialization and setup of the pipeline in my app by 2 seconds.

Can you explain what the purpose of GstResolveType is? (a comment in the source would even be great)

Except for slowness, I see two issues with the current code:
 -  the second Type[] ts = asm.GetTypes (); line should probably be Type[] ts = ref_asm.GetTypes ();
 - Going only one level deep for referenced assemblies seems arbitrary and should be extended to go recursively, or a comment added to explain the choice made.
Comment 1 Sebastian Dröge (slomo) 2009-12-19 07:06:45 UTC
It is used by the element bindings, e.g. gstreamer-sharp/coreplugins/generated/queue.cs . It's necessary to get a sane mapping of the elements to a properly namespaced managed type. Without the attribute the element bindings must all be inside the Gst namespace.

The code is greatly influenced by the same code in glib-sharp, for mapping a GstFooBar native type to Gst.FooBar managed type. The reason for the going one level deep but not more IIRC was, that going into a real recursion would take far too long.

Do you see any ways how we could speed this up?
Comment 2 Maarten Bosmans 2009-12-20 19:05:15 UTC
Thanks for the explanation.

Does that mean that it is sufficient to only check gstreamer-sharp.dll for Gst* types? Or is this mechanism also used for elements implemented in C#, so other assemblies have to be searched as well?
In any case, all the System.* assemblies can be skipped, because those will certainly not contain any of the GObject types. That alone would speed it up, I think. I'll prepare a patch and measure the speedup.

I noticed that a request to resolve GstBus and GstMessage also went through GstResolveType in my app. Is this correct, or is the mchanism only supposed to be for elements. It didn't find a matching type though. This looks logical, because in the source I can't find a [GTypeName ("GstBus")] anywhere. But for these types the whole lookup still takes 400ms, quite a waste of resources.

There is also still a bug in that assembly.GetTypes() can raise an Exception. I'll include a fix for that in a patch, when I know how to rework GstResolveType.

The only other thing I can think of to speed this up, is some sort of cache. Is that something you would think of as fruitfull to persue?

So, a lot of questions. Hopefully you can answer them.
Comment 3 Sebastian Dröge (slomo) 2009-12-22 09:52:40 UTC
(In reply to comment #2)
> Thanks for the explanation.
> 
> Does that mean that it is sufficient to only check gstreamer-sharp.dll for Gst*
> types? Or is this mechanism also used for elements implemented in C#, so other
> assemblies have to be searched as well?
> In any case, all the System.* assemblies can be skipped, because those will
> certainly not contain any of the GObject types. That alone would speed it up, I
> think. I'll prepare a patch and measure the speedup.

Well, you could have your own bindings for GStreamer elements in your application for example. For elements that are not bound by us or even for elements that your application ships.

> I noticed that a request to resolve GstBus and GstMessage also went through
> GstResolveType in my app. Is this correct, or is the mchanism only supposed to
> be for elements. It didn't find a matching type though. This looks logical,
> because in the source I can't find a [GTypeName ("GstBus")] anywhere. But for
> these types the whole lookup still takes 400ms, quite a waste of resources.

It's only meant for elements and other plugin features. GstBus and GstMessage can be resolved by glib-sharp already and I think it's a bug that it calls the ResolveType stuff although it has a resolution already. Could you investigate? (I'm on holidays, can't work on this until early January)

> There is also still a bug in that assembly.GetTypes() can raise an Exception.
> I'll include a fix for that in a patch, when I know how to rework
> GstResolveType.

Great, thanks :)

> The only other thing I can think of to speed this up, is some sort of cache. Is
> that something you would think of as fruitfull to persue?

If it really takes that long and no other solution can be found a cache sounds ok. Let's first try to fix it different though, caching will be complex :)
Comment 4 Maarten Bosmans 2009-12-22 10:54:55 UTC
I did some profiling. Initializing a pipeline with a playbin and a sink results in 4 calls to GstResolveType.

GstDshowVideoSink  2250 ms
GstBus              740 ms
GstMessage          730 ms
GstPlaySink         710 ms

None of which can be resolved to a managed type.

Skipping mscorlib and all assemblies starting with "System." lowers the time to 1600ms for the first and 100ms for subsequent calls.

The remaining time is mainly for Assembly.GetTypes(), which is pretty slow (800ms for gtk-sharp alone, it has over 1800 types) the first time, but .Net seems to do come caching itself, because it is a lot faster for further calls on the same assembly.

I implemented caching using a Dictionary to store all types with a GTypeNameAttribute and got <15ms for the last three calls, but the first is still over 1500ms.

So one way to avoid the overhead is to make sure all the types are known and in a assembly that is checked for types first. I'll look into why GstResolveType is called for GstBus/GstMessage. I don't know what a GstPlaySink is. Are you willing to accept bindings for GstDshowVideoSink, or do you want to leave Bad/Ugly alone for now?

Another option would be to only load assemblies which (eventually) depend on gstreamer-sharp. This would avoid calling GetTypes() on mscorlib, System.* and gtk-sharp for example.
Am I right in thinking that any assembly that would be useful to  Gst.Application.GstResolveType  would have to depend on gstreamer-sharp?
Comment 5 Sebastian Dröge (slomo) 2009-12-23 09:16:01 UTC
(In reply to comment #4)
> I did some profiling. Initializing a pipeline with a playbin and a sink results
> in 4 calls to GstResolveType.
> 
> GstDshowVideoSink  2250 ms
> GstBus              740 ms
> GstMessage          730 ms
> GstPlaySink         710 ms
> 
> None of which can be resolved to a managed type.

Yeah, GstBus/GstMessage should never get into our type resolver at all :)

> Skipping mscorlib and all assemblies starting with "System." lowers the time to
> 1600ms for the first and 100ms for subsequent calls.
> 
> The remaining time is mainly for Assembly.GetTypes(), which is pretty slow
> (800ms for gtk-sharp alone, it has over 1800 types) the first time, but .Net
> seems to do come caching itself, because it is a lot faster for further calls
> on the same assembly.
> 
> I implemented caching using a Dictionary to store all types with a
> GTypeNameAttribute and got <15ms for the last three calls, but the first is
> still over 1500ms.

Sounds good, yes.

> So one way to avoid the overhead is to make sure all the types are known and in
> a assembly that is checked for types first. I'll look into why GstResolveType
> is called for GstBus/GstMessage. I don't know what a GstPlaySink is. Are you
> willing to accept bindings for GstDshowVideoSink, or do you want to leave
> Bad/Ugly alone for now?

GstPlaySink is an internal element of playbin2 which is exported since 0.10.25. Adding bindings for this is a good idea, same for the dshow sink.

> Another option would be to only load assemblies which (eventually) depend on
> gstreamer-sharp. This would avoid calling GetTypes() on mscorlib, System.* and
> gtk-sharp for example.
> Am I right in thinking that any assembly that would be useful to 
> Gst.Application.GstResolveType  would have to depend on gstreamer-sharp?

Yes because they need Gst.Element or Gst.TypeFind or Gst.Index at least. Good idea :)
Comment 6 Maarten Bosmans 2009-12-26 11:36:24 UTC
Created attachment 150396 [details] [review]
Register some more basic GStreamer GTypes as managed types

This patch makes sure GstResolveType does not get called for GstBus, GstMEssage, etc.

Because GType.LookupType first tries to resolve using the ResolveType delegate and only then uses GetQualifiedName (which succeedes for Bus and Message) to lookup a type, the types need to be registered manually to avoid getting GstResolveType called for them.
Comment 7 Maarten Bosmans 2009-12-26 11:43:34 UTC
Created attachment 150397 [details] [review]
Only look for types in assemblies that reference gstreamer-sharp

Instead searching all types in all loaded assemblies and references one level deep for the GTypeNameAttribute, only call GetTypes on assemblies which have gsteamer-sharp in their chain of dependencies.

This excludes all the System.* and gtk-sharp DLLs from being examined and reduces my previous reported times of 2250 and 700ms to 360ms for the first and 70ms for any following calls of GstResolveType.

Note that it makes use of System.Collections.Generic, which is only supported in .NET 2.0 and later. Is this OK? If I recall correctly, gtk-sharp is dropping support for the .NET 1.1 profile, so I guess it would be OK.
Comment 8 Maarten Bosmans 2009-12-26 11:48:38 UTC
Created attachment 150398 [details] [review]
Only call GetTypes() once for each assembly

The 360ms for the first call to GstResolveType cannot be avoided without a completely different way of resolving plugin element types, as it is the time to call Assembly.GetTypes() on the gstreamer-sharp assembly.

For subsequent calls however, instead of searching all the type each time, another Dictionary can be used to speed this up. This patch reduces the time from the previously reported 70ms to ~1ms.

In my usecase of just a simple PlayBin2 with a custom videosink it results in a noticably better response to pressing the play button.
Comment 9 Maarten Bosmans 2009-12-26 11:50:41 UTC
Created attachment 150399 [details] [review]
Handle the case where not all types of an assembly can be loaded

This last patch in the series is a bugfix for a crash in the case not all types of an assembly can be loaded.
Comment 10 Sebastian Dröge (slomo) 2009-12-27 09:25:06 UTC
I'll look at those patches in detail in the next days. Good work though :)
Here are some small comments...

(In reply to comment #6)

> Because GType.LookupType first tries to resolve using the ResolveType delegate
> and only then uses GetQualifiedName (which succeedes for Bus and Message) to
> lookup a type, the types need to be registered manually to avoid getting
> GstResolveType called for them.

Oh, my original patch to gtk-sharp did it the other way around. Only call the ResolveType delegate as a fallback. Hm, need to talk to Mike.

(In reply to comment #7)

> Note that it makes use of System.Collections.Generic, which is only supported
> in .NET 2.0 and later. Is this OK? If I recall correctly, gtk-sharp is dropping
> support for the .NET 1.1 profile, so I guess it would be OK.

Yes, that's fine. We're using 2.0 too already.

(In reply to comment #8)
> Created an attachment (id=150398) [details] [review]
> Only call GetTypes() once for each assembly
> 
> The 360ms for the first call to GstResolveType cannot be avoided without a
> completely different way of resolving plugin element types, as it is the time
> to call Assembly.GetTypes() on the gstreamer-sharp assembly.

Gst.Application.Init() could already call the GetTypes() I guess. It will take a long time already anyway because of gst_init() and then it's a bit more deterministic.

> For subsequent calls however, instead of searching all the type each time,
> another Dictionary can be used to speed this up. This patch reduces the time
> from the previously reported 70ms to ~1ms.
> 
> In my usecase of just a simple PlayBin2 with a custom videosink it results in a
> noticably better response to pressing the play button.

~1ms sounds perfect, nobody can notice this without tools :) I don't think you need to optimize that part more... but maybe call the first GetTypes() in Gst.Application.Init() really :)
Comment 11 Maarten Bosmans 2009-12-28 22:42:59 UTC
Created attachment 150511 [details] [review]
Load cache on Applicxation.Init, some more tweaks

preload cache at Application.Init time, so that the expensive Assembly.GetTypes() calls occur deterministically.
Comment 12 Maarten Bosmans 2009-12-28 22:45:03 UTC
Created attachment 150512 [details] [review]
Rollup of all 5 previous patches

This one patch covers the same changes as the five previous patches, for ease of review and committing
Comment 13 Sebastian Dröge (slomo) 2009-12-30 10:39:21 UTC
Comment on attachment 150512 [details] [review]
Rollup of all 5 previous patches

I prefer small and separate patches for review :)

I'll review them all in the next days, thanks for your work though :)
Comment 14 Sebastian Dröge (slomo) 2010-01-04 09:03:35 UTC
commit 21ad48628ecf5b68d88aed04d91ef8cbdf1830c0
Author: Maarten Bosmans <mkbosmans@gmail.com>
Date:   Mon Dec 28 22:10:00 2009 +0100

    Load cache on Application.Init, some more tweaks

commit 7a1154182baf1742a4a08db0120b50cc27d7e7e8
Author: Maarten Bosmans <mkbosmans@gmail.com>
Date:   Sat Dec 26 12:23:48 2009 +0100

    Handle the case where not all types of an assembly can be loaded

commit 7cd7afbfa64ebc0a712f6d7fbfd9ccb230deacef
Author: Maarten Bosmans <mkbosmans@gmail.com>
Date:   Thu Dec 24 23:30:50 2009 +0100

    Only call GetTypes() once for each assembly
    
    All types with a GTypeNameAttribute are stored in a Dictionary

commit 0ab40256cdfc17d8f89f6e2caa0b74ea54837e57
Author: Maarten Bosmans <mkbosmans@gmail.com>
Date:   Thu Dec 24 17:59:18 2009 +0100

    Only look for types in assemblies that reference gstreamer-sharp

commit 8b1869533d514f674261a7e73f93c749cdee914b
Author: Maarten Bosmans <mkbosmans@gmail.com>
Date:   Thu Dec 24 12:53:51 2009 +0100

    Register some more basic GStreamer GTypes as managed types