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