[OpenJDK Rasterizer] RFR: Marlin renderer #2

Laurent Bourgès bourges.laurent at gmail.com
Tue Jun 9 20:36:28 UTC 2015


Hi Jim,

Your proposal is interesting: I would have loved doing such smart array
cache for general use !
Do you think such a general ArrayCache would be helpful for other java2d or
jdk algorithms needing intensive array allocation ?

However, I focused mostly my work on getting the maximum performance and
also not changing too much the original pisces code (to let you review it
more easily).

Here's a suggestion on how I would set up the array caching code, mainly
> with regard to making it easier to make sure we are managing then
> consistently, but also to allow for more flexible tuning later.
>

I agree the array management code may look complicated (but less than
C/C++).
As I am using netbeans, I am abusing of its 'Find Usages' feature :
Usages of Renderer.edgeBuckets [11 occurrences]
sun.java2d.marlin.Renderer
addLine
  394:  final int[] _edgeBuckets      = edgeBuckets;
Renderer
  472:  edgeBuckets = edgeBuckets_initial;
init

*  523:  edgeBuckets = rdrCtx.getIntArray(edgeBucketsLength);*dispose
  589:  if (edgeBuckets == edgeBuckets_initial) {
  591:  IntArrayCache.fill(edgeBuckets,      buckets_minY,

*  597:  rdrCtx.putIntArray(edgeBuckets,      buckets_minY,*
  599:  edgeBuckets = edgeBuckets_initial;
  605:  } else if (edgeBuckets != edgeBuckets_initial) {

*  607:  rdrCtx.putIntArray(edgeBuckets, 0, 0);*
  608:  edgeBuckets = edgeBuckets_initial;
_endRendering
  708:  final int[] _edgeBuckets = edgeBuckets;

So I can quickly check if I am using the appropriate IntArrayCache (clean
variant) !


> First, make all interactions go through the cache object itself - get,
> grow, put.  This gets rid of a number of static methods with a bunch of
> similar names and groups the management methods in a class hierarchy.
>

It seems a good approach but requires me a big refactoring: a Cache_V2 will
gather many Cache_V1 (including bucket / size management). Moreover, it
raises another issue: for now all caches are gathered into the
ArrayCacheHolder to wrap them with a single WeakReference => small memory
footprint + early GC cleanup.

That's the aim of the RendererContext.getArrayCachesHolder() method which
permits dynamic ArrayCachesHolder retrieval or creation. Actually a Cache
is needed to both get/grow but also release an array and meanwhile, it is
possible that GC had freed the Cache memory !

But this point is more problematic below:

Second, have each consumer of arrays use its own cache object.  Some of
> them may be the same object reference between different "users", and some
> of them may be different objects but share their underlying arrays with
> each other, but a given piece of code could be traced to always
> get/grow/put its arrays into the same cache object.  That way it's easier
> to see that you aren't mixing/matching clean/dirty arrays.
>

It seems a bit verbose: 1 cache field per array = adding a lot of class
fields ! Maybe the same cache reference could be still used for "friend'
arrays like: edgeBuckets/edgeBucketCounts, crossings/aux_crossings, ...


> DirtyFooCache
>     foo[] get(size)
>     foo[] grow(foo[], newsize)  // or widen?
>     void put(foo[])
>
> CleanFooCache
>     foo[] get(size)
>     foo[] grow(foo[], newsize, <used parts>)
>     void put(foo[], <used parts>)
>

Looks like a good design.

>
> Then code that manages an array named bar would be managed as:
> (It may be the same instance as another FooCache
>  or it may share its arrays with another FooCache
>  but the "barCache" reference is only ever used for the bar array...)
>     [Clean|Dirty]FooCache barCache = make/get/share a Cache instance;
>     foo[] bar;
>     ...
>     bar = barCache.get(initSize);
>     ...
>     bar = barCache.grow/widen(bar, newSize[, usage if clean]);
>     ...
>     barCache.put(bar[, usage if clean]);
>     bar = null;
>
> It's easier to verify that bar is being managed consistently if it always
> goes back to its own bar object.  You can then decide if too different uses
> of foo[] arrays should share the same arrays or not based on profiling.
> You can also potentially have different growth algorithms for 2 different
> arrays of the same type, but possibly even sharing the same underlying
> arrays.  Any degree of customization is possible underneath the covers
> behind a FooCache basic interface.
>

I like your proposal but I maximized the array sharing ie Cache instances
for following reasons:
- maximize array reuse (bucket approach) = reduce the memory footprint =>
lower GC overhead because less memory is wasted by cached arrays
- each RendererContext has its own Cache instances: in multithreaded
environment (web server), it becomes critical to have the smaller memory
footprint and avoid concurrency issue = no shared cache between threads
- all that work can be seen as an Thread Local Array Allocation (TLAA) that
could be part of the GC algorithm itself to benefit to the all VM: dirty vs
clean arrays, reusing vs allocation + GC, partial cleaning (Arrays 2.0 ?)
...


> I'd also either make the growth heuristics an argument to
> creating/fetching a FooCache instance or make it subject to a helper
> "CacheSizeManager" or "CacheSizeStrategy" object in such a way that
> different uses of IntCache might be able to have different growth
> strategies - and to possibly even manage different sizing strategies on top
> of the same set of underlying arrays (i.e. one has buckets that grow by <<2
> and another by <<1 and for the even buckets, they share arrays, for
> instance).
>

It led me to imagine a nice Array Cache framework at the jdk or jvm level
... at least not exclusive to Marlin !


> The main thing for the near term, is that it would be nice to have each
> array use its own cache object so that we can easily verify that it is
> being consistent with its handling of arrays...
>

If you are not happy with the latest webrev (better naming convention), we
should discuss again how to do all these changes in a progressive manner.

Cheers,
Laurent
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/graphics-rasterizer-dev/attachments/20150609/df0577ee/attachment.html>


More information about the graphics-rasterizer-dev mailing list