ThinkGeo.com    |     Documentation    |     Premium Support

MultiTile LayerOverlay is ~75x slower than SingleTile for a small shapefile (15.0.0-beta127)

Summary

A LayerOverlay containing a single small shapefile (1.1 MB, ~8,400 line features) takes 7.5 seconds to draw in TileType.MultiTile . The same overlay, same data, same extent, in TileType.SingleTile takes 40–195 ms .

Environment

  • ThinkGeo.UI.Wpf 15.0.0-beta127 (Core, Gdal, SqlServer, PostgreSql, Printers, FileGeoDatabase all same version)
  • .NET 10 ( net10.0-windows7.0 ), WPF, x64, Windows 11
  • Data: ESRI shapefile, polyline, 1.1 MB .shp , ~8,400 features, valid and current .idx

Overlay setup

var overlay = new LayerOverlay
{
    DrawingQuality = DrawingQuality.Standard,
    TileType = TileType.MultiTile,
    TileBuffer = 2,
    TileCache = new FileRasterTileCache(cachePath, cacheId)
};
shapeFileLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
overlay.Layers.Add(layerKey, shapeFileLayer);

Steps to reproduce

  1. LayerOverlay with MultiTile , TileBuffer = 2 , a FileRasterTileCache .
  2. Add one ShapeFileFeatureLayer (1.1 MB, ~8,400 polylines, valid .idx ).
  3. ZoomLevel01.ApplyUntilZoomLevel = Level20 .
  4. Set CurrentExtent to a single street (~1:1000), so the viewport isn’t cached yet.
  5. Measure between the overlay’s Drawing and Drawn events.

What happens

Hooking FeatureLayer.DrawingFeatures and logging e.FeaturesToDraw.Count() shows the layer asked to draw ~60 separate times , 2–16 features each:

18:38:16.827  drawing 11 features
18:38:16.864  drawing  9 features
18:38:17.008  drawing  7 features
...  (~60 total)
18:38:24.330  Overlay drawn: StaticOverlay in 7509 ms

~500 features in ~60 batches, 30–450 ms each (~125 ms average). Eight line features cannot take 125 ms to render, so this looks like fixed per-tile cost, not rendering.

Workaround and comparison

Extent (features drawn) MultiTile SingleTile
street zoom (~500 across ~60 tiles) 7509 ms 79–101 ms
mid zoom (3,345 features) 68 ms
full extent (8,370 features) 87–120 ms

The last row is the striking one: SingleTile draws all 8,370 features in ~90 ms , while MultiTile needed 7.5 s for ~500.

Already ruled out

  • .idx exists and is not stale (logged at load)
  • Not cache invalidation — traced every namespace-rotation call site; none fire here
  • Not our refresh call — switching from RefreshAsync() (all overlays) to a targeted refresh didn’t change it; the extent change itself triggers the redraw
  • Stock ShapeFileFeatureSource , one visible layer

Is ~125 ms/tile expected here, or a bug in the MultiTile path in beta127?

Additionally, we tested with PreloadDataMultiTile, since it is described as “1 query per view” and “multi-threaded” — exactly what our problem looked like. It did not help, and from our logs it does not appear to do either of those things in 15.0.0-beta127.

Numbers (same data, same extents, same machine)

TileType Time to draw the overlay (street zoom)
MultiTile + FileRasterTileCache 7509 ms
MultiTile, no TileCache 2728 – 6610 ms
PreloadDataMultiTile + FileRasterTileCache 5158 – 7866 ms
SingleTile 79 – 101 ms

“1 query per view” — we still see one fetch per tile

We hooked FeatureLayer.DrawingFeatures and logged e.FeaturesToDraw.Count() . With PreloadDataMultiTile we still get ~40 separate calls per view, each with a small subset:

09:42:00.665  Layer rbn_seg: drawing 104 features
09:42:00.730  Layer rbn_seg: drawing  87 features
09:42:00.956  Layer rbn_seg: drawing  96 features
09:42:01.003  Layer rbn_seg: drawing  61 features
...  (about 40 of these per view)
09:42:08.495  Overlay drawn: StaticOverlay in 7866 ms

If the data were queried once per view and shared between tiles, we would expect one large fetch, not ~40 small ones. This looks the same as plain MultiTile.

These counts also add up to far more than the file contains (~8,400 features): each feature seems to be fetched and drawn again in every tile its bounding box touches. With TileBuffer = 2 that multiplies considerably.

“Multi-threaded” — the draws look strictly sequential

The DrawingFeatures callbacks never overlap. They are evenly spaced, 50–250 ms apart, one after another. We never see two tiles drawn at the same time. Per-tile cost was also higher than plain MultiTile (~200 ms for 9–27 features), the opposite of what a preloading mode should do.

What we are using now

TileType.SingleTile , no TileCache:

Features drawn in one pass Time
1,156 64 ms
3,345 68 ms
6,068 83 ms
8,370 (whole file) 87 – 120 ms

The entire dataset in one pass costs ~90 ms, while tiled modes need seconds for a single view.

SingleTile looks awful when panning, though. So if you could have a look that would be wonderful.

Thanks!
J

Hi Julian,

Thanks for the detailed report! It’s reproduced on our side with a 13,800-line street shapefile.

You were right that tiles ran strictly one after another at UI-thread pace. That’s the 30–450 ms per tile and the sequential DrawingFeatures calls. It’s fixed in 15.0.0-beta132: the tile pipeline now stays on the thread pool and only presenting the bitmap touches the UI thread. The 42-tile view on our machine: MultiTile + FileRasterTileCache 1.2 s -> 0.2 s, MultiTile without cache 0.15 s -> 0.07 s. SingleTile unchanged.

On PreloadDataMultiTile: “1 query per view” refers to the data source — features are read once, then each tile’s DrawingFeatures is served from memory, so one call per tile is expected. “Multi-threaded” is now actually true.

One change: DrawnTile is now raised on a background thread (DrawingTile still on the UI thread), so use the Dispatcher if a handler touches UI.

Please give beta132 a try and let us know what you see.

Thanks,
Ben

Thanks Ben! Ill check it out on monday when I get paid for it👌