1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.java2d.marlin; 27 28 import java.security.AccessController; 29 import java.security.PrivilegedAction; 30 import java.util.Timer; 31 import java.util.TimerTask; 32 import java.util.concurrent.ConcurrentLinkedQueue; 33 import jdk.internal.ref.CleanerFactory; 34 import sun.java2d.marlin.ArrayCacheConst.CacheStats; 35 import static sun.java2d.marlin.MarlinUtils.logInfo; 36 import sun.java2d.marlin.stats.Histogram; 37 import sun.java2d.marlin.stats.Monitor; 38 import sun.java2d.marlin.stats.StatLong; 39 import sun.awt.util.ThreadGroupUtils; 40 41 /** 42 * This class gathers global rendering statistics for debugging purposes only 43 */ 44 public final class RendererStats implements MarlinConst { 45 46 static RendererStats createInstance(final Object parent, final String name) 47 { 48 final RendererStats stats = new RendererStats(name); 49 50 // Keep a strong reference to dump it later: 51 RendererStatsHolder.getInstance().add(parent, stats); 52 53 return stats; 54 } 55 56 public static void dumpStats() { 57 RendererStatsHolder.dumpStats(); 58 } 59 60 // context name (debugging purposes) 61 final String name; 62 // stats 63 final StatLong stat_cache_rowAA 64 = new StatLong("cache.rowAA"); 65 final StatLong stat_cache_rowAAChunk 66 = new StatLong("cache.rowAAChunk"); 67 final StatLong stat_cache_tiles 68 = new StatLong("cache.tiles"); 69 final StatLong stat_rdr_poly_stack_curves 70 = new StatLong("renderer.poly.stack.curves"); 71 final StatLong stat_rdr_poly_stack_types 72 = new StatLong("renderer.poly.stack.types"); 73 final StatLong stat_rdr_addLine 74 = new StatLong("renderer.addLine"); 75 final StatLong stat_rdr_addLine_skip 76 = new StatLong("renderer.addLine.skip"); 77 final StatLong stat_rdr_curveBreak 78 = new StatLong("renderer.curveBreakIntoLinesAndAdd"); 79 final StatLong stat_rdr_curveBreak_dec 80 = new StatLong("renderer.curveBreakIntoLinesAndAdd.dec"); 81 final StatLong stat_rdr_curveBreak_inc 82 = new StatLong("renderer.curveBreakIntoLinesAndAdd.inc"); 83 final StatLong stat_rdr_quadBreak 84 = new StatLong("renderer.quadBreakIntoLinesAndAdd"); 85 final StatLong stat_rdr_quadBreak_dec 86 = new StatLong("renderer.quadBreakIntoLinesAndAdd.dec"); 87 final StatLong stat_rdr_edges 88 = new StatLong("renderer.edges"); 89 final StatLong stat_rdr_edges_count 90 = new StatLong("renderer.edges.count"); 91 final StatLong stat_rdr_edges_resizes 92 = new StatLong("renderer.edges.resize"); 93 final StatLong stat_rdr_activeEdges 94 = new StatLong("renderer.activeEdges"); 95 final StatLong stat_rdr_activeEdges_updates 96 = new StatLong("renderer.activeEdges.updates"); 97 final StatLong stat_rdr_activeEdges_adds 98 = new StatLong("renderer.activeEdges.adds"); 99 final StatLong stat_rdr_activeEdges_adds_high 100 = new StatLong("renderer.activeEdges.adds_high"); 101 final StatLong stat_rdr_crossings_updates 102 = new StatLong("renderer.crossings.updates"); 103 final StatLong stat_rdr_crossings_sorts 104 = new StatLong("renderer.crossings.sorts"); 105 final StatLong stat_rdr_crossings_bsearch 106 = new StatLong("renderer.crossings.bsearch"); 107 final StatLong stat_rdr_crossings_msorts 108 = new StatLong("renderer.crossings.msorts"); 109 // growable arrays 110 final StatLong stat_array_dasher_dasher 111 = new StatLong("array.dasher.dasher.d_float"); 112 final StatLong stat_array_dasher_firstSegmentsBuffer 113 = new StatLong("array.dasher.firstSegmentsBuffer.d_float"); 114 final StatLong stat_array_stroker_polystack_curves 115 = new StatLong("array.stroker.polystack.curves.d_float"); 116 final StatLong stat_array_stroker_polystack_curveTypes 117 = new StatLong("array.stroker.polystack.curveTypes.d_byte"); 118 final StatLong stat_array_marlincache_rowAAChunk 119 = new StatLong("array.marlincache.rowAAChunk.resize"); 120 final StatLong stat_array_marlincache_touchedTile 121 = new StatLong("array.marlincache.touchedTile.int"); 122 final StatLong stat_array_renderer_alphaline 123 = new StatLong("array.renderer.alphaline.int"); 124 final StatLong stat_array_renderer_crossings 125 = new StatLong("array.renderer.crossings.int"); 126 final StatLong stat_array_renderer_aux_crossings 127 = new StatLong("array.renderer.aux_crossings.int"); 128 final StatLong stat_array_renderer_edgeBuckets 129 = new StatLong("array.renderer.edgeBuckets.int"); 130 final StatLong stat_array_renderer_edgeBucketCounts 131 = new StatLong("array.renderer.edgeBucketCounts.int"); 132 final StatLong stat_array_renderer_edgePtrs 133 = new StatLong("array.renderer.edgePtrs.int"); 134 final StatLong stat_array_renderer_aux_edgePtrs 135 = new StatLong("array.renderer.aux_edgePtrs.int"); 136 // histograms 137 final Histogram hist_rdr_edges_count 138 = new Histogram("renderer.edges.count"); 139 final Histogram hist_rdr_poly_stack_curves 140 = new Histogram("renderer.polystack.curves"); 141 final Histogram hist_rdr_crossings 142 = new Histogram("renderer.crossings"); 143 final Histogram hist_rdr_crossings_ratio 144 = new Histogram("renderer.crossings.ratio"); 145 final Histogram hist_rdr_crossings_adds 146 = new Histogram("renderer.crossings.adds"); 147 final Histogram hist_rdr_crossings_msorts 148 = new Histogram("renderer.crossings.msorts"); 149 final Histogram hist_rdr_crossings_msorts_adds 150 = new Histogram("renderer.crossings.msorts.adds"); 151 final Histogram hist_tile_generator_alpha 152 = new Histogram("tile_generator.alpha"); 153 final Histogram hist_tile_generator_encoding 154 = new Histogram("tile_generator.encoding"); 155 final Histogram hist_tile_generator_encoding_dist 156 = new Histogram("tile_generator.encoding.dist"); 157 final Histogram hist_tile_generator_encoding_ratio 158 = new Histogram("tile_generator.encoding.ratio"); 159 final Histogram hist_tile_generator_encoding_runLen 160 = new Histogram("tile_generator.encoding.runLen"); 161 // all stats 162 final StatLong[] statistics = new StatLong[]{ 163 stat_cache_rowAA, 164 stat_cache_rowAAChunk, 165 stat_cache_tiles, 166 stat_rdr_poly_stack_types, 167 stat_rdr_poly_stack_curves, 168 stat_rdr_addLine, 169 stat_rdr_addLine_skip, 170 stat_rdr_curveBreak, 171 stat_rdr_curveBreak_dec, 172 stat_rdr_curveBreak_inc, 173 stat_rdr_quadBreak, 174 stat_rdr_quadBreak_dec, 175 stat_rdr_edges, 176 stat_rdr_edges_count, 177 stat_rdr_edges_resizes, 178 stat_rdr_activeEdges, 179 stat_rdr_activeEdges_updates, 180 stat_rdr_activeEdges_adds, 181 stat_rdr_activeEdges_adds_high, 182 stat_rdr_crossings_updates, 183 stat_rdr_crossings_sorts, 184 stat_rdr_crossings_bsearch, 185 stat_rdr_crossings_msorts, 186 hist_rdr_edges_count, 187 hist_rdr_poly_stack_curves, 188 hist_rdr_crossings, 189 hist_rdr_crossings_ratio, 190 hist_rdr_crossings_adds, 191 hist_rdr_crossings_msorts, 192 hist_rdr_crossings_msorts_adds, 193 hist_tile_generator_alpha, 194 hist_tile_generator_encoding, 195 hist_tile_generator_encoding_dist, 196 hist_tile_generator_encoding_ratio, 197 hist_tile_generator_encoding_runLen, 198 stat_array_dasher_dasher, 199 stat_array_dasher_firstSegmentsBuffer, 200 stat_array_stroker_polystack_curves, 201 stat_array_stroker_polystack_curveTypes, 202 stat_array_marlincache_rowAAChunk, 203 stat_array_marlincache_touchedTile, 204 stat_array_renderer_alphaline, 205 stat_array_renderer_crossings, 206 stat_array_renderer_aux_crossings, 207 stat_array_renderer_edgeBuckets, 208 stat_array_renderer_edgeBucketCounts, 209 stat_array_renderer_edgePtrs, 210 stat_array_renderer_aux_edgePtrs 211 }; 212 // monitors 213 final Monitor mon_pre_getAATileGenerator 214 = new Monitor("MarlinRenderingEngine.getAATileGenerator()"); 215 final Monitor mon_rdr_addLine 216 = new Monitor("Renderer.addLine()"); 217 final Monitor mon_rdr_endRendering 218 = new Monitor("Renderer.endRendering()"); 219 final Monitor mon_rdr_endRendering_Y 220 = new Monitor("Renderer._endRendering(Y)"); 221 final Monitor mon_rdr_copyAARow 222 = new Monitor("Renderer.copyAARow()"); 223 final Monitor mon_pipe_renderTiles 224 = new Monitor("AAShapePipe.renderTiles()"); 225 final Monitor mon_ptg_getAlpha 226 = new Monitor("MarlinTileGenerator.getAlpha()"); 227 final Monitor mon_debug 228 = new Monitor("DEBUG()"); 229 // all monitors 230 final Monitor[] monitors = new Monitor[]{ 231 mon_pre_getAATileGenerator, 232 mon_rdr_addLine, 233 mon_rdr_endRendering, 234 mon_rdr_endRendering_Y, 235 mon_rdr_copyAARow, 236 mon_pipe_renderTiles, 237 mon_ptg_getAlpha, 238 mon_debug 239 }; 240 // offheap stats 241 long totalOffHeapInitial = 0L; 242 // live accumulator 243 long totalOffHeap = 0L; 244 long totalOffHeapMax = 0L; 245 // cache stats 246 CacheStats[] cacheStats = null; 247 248 private RendererStats(final String name) { 249 this.name = name; 250 } 251 252 void dump() { 253 logInfo("RendererContext: " + name); 254 255 if (DO_MONITORS) { 256 for (Monitor monitor : monitors) { 257 if (monitor.count != 0) { 258 logInfo(monitor.toString()); 259 } 260 } 261 // As getAATileGenerator percents: 262 final long total = mon_pre_getAATileGenerator.sum; 263 if (total != 0L) { 264 for (Monitor monitor : monitors) { 265 logInfo(monitor.name + " : " 266 + ((100d * monitor.sum) / total) + " %"); 267 } 268 } 269 if (DO_FLUSH_MONITORS) { 270 for (Monitor m : monitors) { 271 m.reset(); 272 } 273 } 274 } 275 276 if (DO_STATS) { 277 for (StatLong stat : statistics) { 278 if (stat.count != 0) { 279 logInfo(stat.toString()); 280 if (DO_FLUSH_STATS) { 281 stat.reset(); 282 } 283 } 284 } 285 286 logInfo("OffHeap footprint: initial: " + totalOffHeapInitial 287 + " bytes - max: " + totalOffHeapMax + " bytes"); 288 if (DO_FLUSH_STATS) { 289 totalOffHeapMax = 0L; 290 } 291 292 logInfo("Array caches for RendererContext: " + name); 293 294 long totalInitialBytes = totalOffHeapInitial; 295 long totalCacheBytes = 0L; 296 297 if (cacheStats != null) { 298 for (CacheStats stat : cacheStats) { 299 totalCacheBytes += stat.dumpStats(); 300 totalInitialBytes += stat.getTotalInitialBytes(); 301 if (DO_FLUSH_STATS) { 302 stat.reset(); 303 } 304 } 305 } 306 logInfo("Heap footprint: initial: " + totalInitialBytes 307 + " bytes - cache: " + totalCacheBytes + " bytes"); 308 } 309 } 310 311 static final class RendererStatsHolder { 312 313 // singleton 314 private static volatile RendererStatsHolder SINGLETON = null; 315 316 static synchronized RendererStatsHolder getInstance() { 317 if (SINGLETON == null) { 318 SINGLETON = new RendererStatsHolder(); 319 } 320 return SINGLETON; 321 } 322 323 static void dumpStats() { 324 if (SINGLETON != null) { 325 SINGLETON.dump(); 326 } 327 } 328 329 /* RendererStats collection as hard references 330 (only used for debugging purposes) */ 331 private final ConcurrentLinkedQueue<RendererStats> allStats 332 = new ConcurrentLinkedQueue<RendererStats>(); 333 334 private RendererStatsHolder() { 335 AccessController.doPrivileged( 336 (PrivilegedAction<Void>) () -> { 337 final Thread hook = new Thread( 338 ThreadGroupUtils.getRootThreadGroup(), 339 new Runnable() { 340 @Override 341 public void run() { 342 dump(); 343 } 344 }, 345 "MarlinStatsHook" 346 ); 347 hook.setContextClassLoader(null); 348 Runtime.getRuntime().addShutdownHook(hook); 349 350 if (USE_DUMP_THREAD) { 351 final Timer statTimer = new Timer("RendererStats"); 352 statTimer.scheduleAtFixedRate(new TimerTask() { 353 @Override 354 public void run() { 355 dump(); 356 } 357 }, DUMP_INTERVAL, DUMP_INTERVAL); 358 } 359 return null; 360 } 361 ); 362 } 363 364 void add(final Object parent, final RendererStats stats) { 365 allStats.add(stats); 366 367 // Register a cleaning function to ensure removing dead entries: 368 CleanerFactory.cleaner().register(parent, () -> remove(stats)); 369 } 370 371 void remove(final RendererStats stats) { 372 stats.dump(); // dump anyway 373 allStats.remove(stats); 374 } 375 376 void dump() { 377 for (RendererStats stats : allStats) { 378 stats.dump(); 379 } 380 } 381 } 382 } --- EOF ---