1 /* 2 * Copyright (c) 2015, 2018, 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 40 /** 41 * This class gathers global rendering statistics for debugging purposes only 42 */ 43 public final class RendererStats implements MarlinConst { 44 45 static RendererStats createInstance(final Object parent, final String name) 46 { 47 final RendererStats stats = new RendererStats(name); 48 49 // Keep a strong reference to dump it later: 50 RendererStatsHolder.getInstance().add(parent, stats); 51 52 return stats; 53 } 54 55 public static void dumpStats() { 56 RendererStatsHolder.dumpStats(); 57 } 58 59 // context name (debugging purposes) 60 final String name; 61 // stats 62 final StatLong stat_cache_rowAA 63 = new StatLong("cache.rowAA"); 64 final StatLong stat_cache_rowAAChunk 65 = new StatLong("cache.rowAAChunk"); 66 final StatLong stat_cache_tiles 67 = new StatLong("cache.tiles"); 68 final StatLong stat_rdr_addLine 69 = new StatLong("renderer.addLine"); 70 final StatLong stat_rdr_addLine_skip 71 = new StatLong("renderer.addLine.skip"); 72 final StatLong stat_rdr_curveBreak 73 = new StatLong("renderer.curveBreakIntoLinesAndAdd"); 74 final StatLong stat_rdr_curveBreak_dec 75 = new StatLong("renderer.curveBreakIntoLinesAndAdd.dec"); 76 final StatLong stat_rdr_curveBreak_inc 77 = new StatLong("renderer.curveBreakIntoLinesAndAdd.inc"); 78 final StatLong stat_rdr_quadBreak 79 = new StatLong("renderer.quadBreakIntoLinesAndAdd"); 80 final StatLong stat_rdr_quadBreak_dec 81 = new StatLong("renderer.quadBreakIntoLinesAndAdd.dec"); 82 final StatLong stat_rdr_edges 83 = new StatLong("renderer.edges"); 84 final StatLong stat_rdr_edges_count 85 = new StatLong("renderer.edges.count"); 86 final StatLong stat_rdr_edges_resizes 87 = new StatLong("renderer.edges.resize"); 88 final StatLong stat_rdr_activeEdges 89 = new StatLong("renderer.activeEdges"); 90 final StatLong stat_rdr_activeEdges_updates 91 = new StatLong("renderer.activeEdges.updates"); 92 final StatLong stat_rdr_activeEdges_adds 93 = new StatLong("renderer.activeEdges.adds"); 94 final StatLong stat_rdr_activeEdges_adds_high 95 = new StatLong("renderer.activeEdges.adds_high"); 96 final StatLong stat_rdr_crossings_updates 97 = new StatLong("renderer.crossings.updates"); 98 final StatLong stat_rdr_crossings_sorts 99 = new StatLong("renderer.crossings.sorts"); 100 final StatLong stat_rdr_crossings_bsearch 101 = new StatLong("renderer.crossings.bsearch"); 102 final StatLong stat_rdr_crossings_msorts 103 = new StatLong("renderer.crossings.msorts"); 104 final StatLong stat_str_polystack_curves 105 = new StatLong("stroker.polystack.curves"); 106 final StatLong stat_str_polystack_types 107 = new StatLong("stroker.polystack.types"); 108 final StatLong stat_cpd_polystack_curves 109 = new StatLong("closedPathDetector.polystack.curves"); 110 final StatLong stat_cpd_polystack_types 111 = new StatLong("closedPathDetector.polystack.types"); 112 final StatLong stat_pcf_idxstack_indices 113 = new StatLong("pathClipFilter.stack.indices"); 114 // growable arrays 115 final StatLong stat_array_dasher_dasher 116 = new StatLong("array.dasher.dasher.d_float"); 117 final StatLong stat_array_dasher_firstSegmentsBuffer 118 = new StatLong("array.dasher.firstSegmentsBuffer.d_float"); 119 final StatLong stat_array_marlincache_rowAAChunk 120 = new StatLong("array.marlincache.rowAAChunk.resize"); 121 final StatLong stat_array_marlincache_touchedTile 122 = new StatLong("array.marlincache.touchedTile.int"); 123 final StatLong stat_array_renderer_alphaline 124 = new StatLong("array.renderer.alphaline.int"); 125 final StatLong stat_array_renderer_crossings 126 = new StatLong("array.renderer.crossings.int"); 127 final StatLong stat_array_renderer_aux_crossings 128 = new StatLong("array.renderer.aux_crossings.int"); 129 final StatLong stat_array_renderer_edgeBuckets 130 = new StatLong("array.renderer.edgeBuckets.int"); 131 final StatLong stat_array_renderer_edgeBucketCounts 132 = new StatLong("array.renderer.edgeBucketCounts.int"); 133 final StatLong stat_array_renderer_edgePtrs 134 = new StatLong("array.renderer.edgePtrs.int"); 135 final StatLong stat_array_renderer_aux_edgePtrs 136 = new StatLong("array.renderer.aux_edgePtrs.int"); 137 final StatLong stat_array_str_polystack_curves 138 = new StatLong("array.stroker.polystack.curves.d_float"); 139 final StatLong stat_array_str_polystack_types 140 = new StatLong("array.stroker.polystack.curveTypes.d_byte"); 141 final StatLong stat_array_cpd_polystack_curves 142 = new StatLong("array.closedPathDetector.polystack.curves.d_float"); 143 final StatLong stat_array_cpd_polystack_types 144 = new StatLong("array.closedPathDetector.polystack.curveTypes.d_byte"); 145 final StatLong stat_array_pcf_idxstack_indices 146 = new StatLong("array.pathClipFilter.stack.indices.d_int"); 147 // histograms 148 final Histogram hist_rdr_edges_count 149 = new Histogram("renderer.edges.count"); 150 final Histogram hist_rdr_crossings 151 = new Histogram("renderer.crossings"); 152 final Histogram hist_rdr_crossings_ratio 153 = new Histogram("renderer.crossings.ratio"); 154 final Histogram hist_rdr_crossings_adds 155 = new Histogram("renderer.crossings.adds"); 156 final Histogram hist_rdr_crossings_msorts 157 = new Histogram("renderer.crossings.msorts"); 158 final Histogram hist_rdr_crossings_msorts_adds 159 = new Histogram("renderer.crossings.msorts.adds"); 160 final Histogram hist_str_polystack_curves 161 = new Histogram("stroker.polystack.curves"); 162 final Histogram hist_tile_generator_alpha 163 = new Histogram("tile_generator.alpha"); 164 final Histogram hist_tile_generator_encoding 165 = new Histogram("tile_generator.encoding"); 166 final Histogram hist_tile_generator_encoding_dist 167 = new Histogram("tile_generator.encoding.dist"); 168 final Histogram hist_tile_generator_encoding_ratio 169 = new Histogram("tile_generator.encoding.ratio"); 170 final Histogram hist_tile_generator_encoding_runLen 171 = new Histogram("tile_generator.encoding.runLen"); 172 final Histogram hist_cpd_polystack_curves 173 = new Histogram("closedPathDetector.polystack.curves"); 174 final Histogram hist_pcf_idxstack_indices 175 = new Histogram("pathClipFilter.stack.indices"); 176 // all stats 177 final StatLong[] statistics = new StatLong[]{ 178 stat_cache_rowAA, 179 stat_cache_rowAAChunk, 180 stat_cache_tiles, 181 stat_rdr_addLine, 182 stat_rdr_addLine_skip, 183 stat_rdr_curveBreak, 184 stat_rdr_curveBreak_dec, 185 stat_rdr_curveBreak_inc, 186 stat_rdr_quadBreak, 187 stat_rdr_quadBreak_dec, 188 stat_rdr_edges, 189 stat_rdr_edges_count, 190 stat_rdr_edges_resizes, 191 stat_rdr_activeEdges, 192 stat_rdr_activeEdges_updates, 193 stat_rdr_activeEdges_adds, 194 stat_rdr_activeEdges_adds_high, 195 stat_rdr_crossings_updates, 196 stat_rdr_crossings_sorts, 197 stat_rdr_crossings_bsearch, 198 stat_rdr_crossings_msorts, 199 stat_str_polystack_types, 200 stat_str_polystack_curves, 201 stat_cpd_polystack_curves, 202 stat_cpd_polystack_types, 203 stat_pcf_idxstack_indices, 204 hist_rdr_edges_count, 205 hist_rdr_crossings, 206 hist_rdr_crossings_ratio, 207 hist_rdr_crossings_adds, 208 hist_rdr_crossings_msorts, 209 hist_rdr_crossings_msorts_adds, 210 hist_tile_generator_alpha, 211 hist_tile_generator_encoding, 212 hist_tile_generator_encoding_dist, 213 hist_tile_generator_encoding_ratio, 214 hist_tile_generator_encoding_runLen, 215 hist_str_polystack_curves, 216 hist_cpd_polystack_curves, 217 hist_pcf_idxstack_indices, 218 stat_array_dasher_dasher, 219 stat_array_dasher_firstSegmentsBuffer, 220 stat_array_marlincache_rowAAChunk, 221 stat_array_marlincache_touchedTile, 222 stat_array_renderer_alphaline, 223 stat_array_renderer_crossings, 224 stat_array_renderer_aux_crossings, 225 stat_array_renderer_edgeBuckets, 226 stat_array_renderer_edgeBucketCounts, 227 stat_array_renderer_edgePtrs, 228 stat_array_renderer_aux_edgePtrs, 229 stat_array_str_polystack_curves, 230 stat_array_str_polystack_types, 231 stat_array_cpd_polystack_curves, 232 stat_array_cpd_polystack_types, 233 stat_array_pcf_idxstack_indices 234 }; 235 // monitors 236 final Monitor mon_pre_getAATileGenerator 237 = new Monitor("MarlinRenderingEngine.getAATileGenerator()"); 238 final Monitor mon_rdr_addLine 239 = new Monitor("Renderer.addLine()"); 240 final Monitor mon_rdr_endRendering 241 = new Monitor("Renderer.endRendering()"); 242 final Monitor mon_rdr_endRendering_Y 243 = new Monitor("Renderer._endRendering(Y)"); 244 final Monitor mon_rdr_copyAARow 245 = new Monitor("Renderer.copyAARow()"); 246 final Monitor mon_pipe_renderTiles 247 = new Monitor("AAShapePipe.renderTiles()"); 248 final Monitor mon_ptg_getAlpha 249 = new Monitor("MarlinTileGenerator.getAlpha()"); 250 final Monitor mon_debug 251 = new Monitor("DEBUG()"); 252 // all monitors 253 final Monitor[] monitors = new Monitor[]{ 254 mon_pre_getAATileGenerator, 255 mon_rdr_addLine, 256 mon_rdr_endRendering, 257 mon_rdr_endRendering_Y, 258 mon_rdr_copyAARow, 259 mon_pipe_renderTiles, 260 mon_ptg_getAlpha, 261 mon_debug 262 }; 263 // offheap stats 264 long totalOffHeapInitial = 0L; 265 // live accumulator 266 long totalOffHeap = 0L; 267 long totalOffHeapMax = 0L; 268 // cache stats 269 CacheStats[] cacheStats = null; 270 271 private RendererStats(final String name) { 272 this.name = name; 273 } 274 275 void dump() { 276 logInfo("RendererContext: " + name); 277 278 if (DO_MONITORS) { 279 for (Monitor monitor : monitors) { 280 if (monitor.count != 0) { 281 logInfo(monitor.toString()); 282 } 283 } 284 // As getAATileGenerator percents: 285 final long total = mon_pre_getAATileGenerator.sum; 286 if (total != 0L) { 287 for (Monitor monitor : monitors) { 288 logInfo(monitor.name + " : " 289 + ((100d * monitor.sum) / total) + " %"); 290 } 291 } 292 if (DO_FLUSH_MONITORS) { 293 for (Monitor m : monitors) { 294 m.reset(); 295 } 296 } 297 } 298 299 if (DO_STATS) { 300 for (StatLong stat : statistics) { 301 if (stat.count != 0) { 302 logInfo(stat.toString()); 303 if (DO_FLUSH_STATS) { 304 stat.reset(); 305 } 306 } 307 } 308 309 logInfo("OffHeap footprint: initial: " + totalOffHeapInitial 310 + " bytes - max: " + totalOffHeapMax + " bytes"); 311 if (DO_FLUSH_STATS) { 312 totalOffHeapMax = 0L; 313 } 314 315 logInfo("Array caches for RendererContext: " + name); 316 317 long totalInitialBytes = totalOffHeapInitial; 318 long totalCacheBytes = 0L; 319 320 if (cacheStats != null) { 321 for (CacheStats stat : cacheStats) { 322 totalCacheBytes += stat.dumpStats(); 323 totalInitialBytes += stat.getTotalInitialBytes(); 324 if (DO_FLUSH_STATS) { 325 stat.reset(); 326 } 327 } 328 } 329 logInfo("Heap footprint: initial: " + totalInitialBytes 330 + " bytes - cache: " + totalCacheBytes + " bytes"); 331 } 332 } 333 334 static final class RendererStatsHolder { 335 336 // singleton 337 private static volatile RendererStatsHolder SINGLETON = null; 338 339 static synchronized RendererStatsHolder getInstance() { 340 if (SINGLETON == null) { 341 SINGLETON = new RendererStatsHolder(); 342 } 343 return SINGLETON; 344 } 345 346 static void dumpStats() { 347 if (SINGLETON != null) { 348 SINGLETON.dump(); 349 } 350 } 351 352 /* RendererStats collection as hard references 353 (only used for debugging purposes) */ 354 private final ConcurrentLinkedQueue<RendererStats> allStats 355 = new ConcurrentLinkedQueue<RendererStats>(); 356 357 private RendererStatsHolder() { 358 AccessController.doPrivileged( 359 (PrivilegedAction<Void>) () -> { 360 final Thread hook = new Thread( 361 MarlinUtils.getRootThreadGroup(), 362 new Runnable() { 363 @Override 364 public void run() { 365 dump(); 366 } 367 }, 368 "MarlinStatsHook" 369 ); 370 hook.setContextClassLoader(null); 371 Runtime.getRuntime().addShutdownHook(hook); 372 373 if (USE_DUMP_THREAD) { 374 final Timer statTimer = new Timer("RendererStats"); 375 statTimer.scheduleAtFixedRate(new TimerTask() { 376 @Override 377 public void run() { 378 dump(); 379 } 380 }, DUMP_INTERVAL, DUMP_INTERVAL); 381 } 382 return null; 383 } 384 ); 385 } 386 387 void add(final Object parent, final RendererStats stats) { 388 allStats.add(stats); 389 390 // Register a cleaning function to ensure removing dead entries: 391 CleanerFactory.cleaner().register(parent, () -> remove(stats)); 392 } 393 394 void remove(final RendererStats stats) { 395 stats.dump(); // dump anyway 396 allStats.remove(stats); 397 } 398 399 void dump() { 400 for (RendererStats stats : allStats) { 401 stats.dump(); 402 } 403 } 404 } 405 }