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