4

I have a code using third-party-tool iterating over a collection of points.

for (int i = 0; i < pcoll.PointCount; i++) { /* ... */ }

When doing profiling via dotTrace I noticed that the PointCount-proerty is accessed every iteration (see picture above)

.

I expected that the value for this property is optimized away by the compiler but obviously that doesn't happen. Maybe this is actually a problem within the COM-based 3rd-party lib or also within dotTrace self when collecting the information.

I'm not sure if this topic wouldn't fit better to Gis.StackExchange. However maybe someone has any idea under which circumstances optimzation won't take place or how it might happen.

Filburt
  • 17,626
  • 12
  • 64
  • 115
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • 1
    I'm not positive but I think it has something to do with properties are methods in C#. So it may not be able to know statically the value of `pcoll.PointCount` EDIT. Looking at the stack trace that is whats happening its calling the get methods. You can't optimize these unless they can be in-lined. – t3dodson Jun 29 '15 at 11:17
  • `int pointCount = pcoll.PointCount; for (int i = 0; i < pointCount ; i++) { /*.. */ }` Now it is cached and the property is accessed only once. – Tim Schmelter Jun 29 '15 at 11:21
  • @TomDDD Inlining is the lesser point - the bigger one is that the compiler cannot know if it's safe to store the value of `PointCount`, because that's only possible if `pcoll` is immutable, and `PointCount` is pure - and the compiler has no way of knowing that. Usually, compilers ignore the first point (that is, they ignore cross-thread access - accessing it in the same thread might prevent the "optimization as well"), but the second point is solid - the compiler simply isn't allowed to do that kind of optimization, ever. – Luaan Jun 29 '15 at 11:33

3 Answers3

7

Simply put, how is the compiler to know whether pcoll.PointCount will change between invocations? It can't safely make the assumption that the value will remain unchanged, so it can't optimise this code by caching the value of the first call to pcoll.PointCount.

David Arno
  • 42,717
  • 16
  • 86
  • 131
2

It may have changed in the meantime.

Indeed, one of the reasons to test i < pcoll.PointCount every iteration rather than just using foreach(var point in pcoll) is precisely because you think the collection might change in the meantime, and enumerators don't guarantee to cope with changes to the collection they enumerate.

This differs from, for example, an array accessed through a local variable, because the only way the Length of an array accessed through a local variable can change, is if the change is made locally.

Even there though, it's worth remembering that the compiler often skips some obvious optimisations because it's known that the jitter makes the same optimisation too.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • Actually the reason for not using `foreach` is the `PointCollection`-class provided by ESRI does not implement an enumerator. SThis is of course quite annoying but that´s it. – MakePeaceGreatAgain Jun 29 '15 at 11:35
  • Really? http://help.arcgis.com/en/webapi/silverlight/apiref/ESRI.ArcGIS.Client~ESRI.ArcGIS.Client.Geometry.PointCollection.html says it is descended from `ObservableCollection`. Does the `GetEnumerator()` throw an exception? It remains that one of the reasons for doing a `for` is if you want to guard against similar changes to the collection. – Jon Hanna Jun 29 '15 at 12:13
  • Sorry, I ment the `IPointCollection`-interface (see here: http://help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/index.html#/IPointCollection_Interface/002m00000275000000/) where we do not even have any `PointCollection`-class at all, only some kind of Multipart-geometries (e.g. MultiPoint). But I actually ment the first – MakePeaceGreatAgain Jun 29 '15 at 12:21
  • Hmm. That **would be** annoying. – Jon Hanna Jun 29 '15 at 12:23
  • I do not know why the guys from ESRI decided to NOT implement IEnumerator at all (also for other classes they do not), maybe mutability might be a reason – MakePeaceGreatAgain Jun 29 '15 at 12:27
1

The expected optimization is true for fields. But property has setter/getter (accessing property is in fact calling them as methods), so compiler will have hard time to try to optimize it.

To fix, make it a field or read it once

var max = pcoll.PointCount;
for (int i = 0; i < max; i++) { /* ... */ }
Sinatr
  • 20,892
  • 15
  • 90
  • 319