Mercurial > hg > graal-jvmci-8
diff graal/com.oracle.truffle.object/src/com/oracle/truffle/object/debug/ShapeProfiler.java @ 18408:2c3666f44855
Truffle: initial commit of object API implementation
author | Andreas Woess <andreas.woess@jku.at> |
---|---|
date | Tue, 18 Nov 2014 23:19:43 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/debug/ShapeProfiler.java Tue Nov 18 23:19:43 2014 +0100 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.object.debug; + +import java.io.*; +import java.text.*; +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.truffle.api.object.*; +import com.oracle.truffle.object.*; + +public class ShapeProfiler { + private static final String LINE_SEPARATOR = "***********************************************"; + private static final String BULLET = "* "; + private static final String TOKEN_SEPARATOR = "\t"; + private final ConcurrentLinkedQueue<DynamicObject> queue; + + public ShapeProfiler() { + queue = new ConcurrentLinkedQueue<>(); + } + + public void track(DynamicObject obj) { + queue.add(obj); + } + + public void dump(PrintWriter out) { + ShapeStats globalStats = new ShapeStats("Cumulative results for all shapes"); + for (DynamicObject obj : queue) { + Shape shape = obj.getShape(); + globalStats.profile(shape); + } + + globalStats.dump(out); + } + + public void dump(PrintWriter out, int topResults) { + if (topResults > 0) { + IdentityHashMap<Shape, ShapeStats> shapeMap = new IdentityHashMap<>(); + + for (DynamicObject obj : queue) { + Shape shape = obj.getShape(); + ShapeStats stats = shapeMap.get(shape); + if (stats == null) { + shapeMap.put(shape, stats = new ShapeStats(createLabel(shape))); + } + stats.profile(shape); + } + + List<ShapeStats> allStats = new ArrayList<>(shapeMap.values()); + Collections.sort(allStats, new Comparator<ShapeStats>() { + public int compare(ShapeStats a, ShapeStats b) { + return Long.compare(b.jsObjects, a.jsObjects); + } + }); + + ShapeStats avgStats = new ShapeStats("Cumulative results for top " + topResults + " shapes"); + for (int i = 0; i < topResults; i++) { + ShapeStats stats = allStats.get(i); + stats.setLabel("Shape " + (i + 1) + ": " + stats.getLabel()); + stats.dump(out); + avgStats.add(stats); + } + avgStats.dump(out); + } + // Dump also cumulative results. + dump(out); + } + + private static String createLabel(Shape shape) { + String label = shape.toString(); + return label.substring(label.indexOf('{') + 1, label.lastIndexOf('}')); + } + + private static class ShapeStats { + private String label; + private long jsObjects; + private long oac; + private long oas; + private long ofs; + private long pac; + private long pas; + private long pfs; + + public ShapeStats(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public void profile(Shape shape) { + jsObjects++; + oac += shape.getObjectArrayCapacity(); + oas += shape.getObjectArraySize(); + ofs += shape.getObjectFieldSize(); + pac += shape.getPrimitiveArrayCapacity(); + pas += shape.getPrimitiveArraySize(); + pfs += shape.getPrimitiveFieldSize(); + } + + public void add(ShapeStats stats) { + jsObjects += stats.jsObjects; + oac += stats.oac; + oas += stats.oas; + ofs += stats.ofs; + oac += stats.oac; + oas += stats.oas; + ofs += stats.ofs; + } + + public void dump(PrintWriter out) { + DecimalFormat format = new DecimalFormat("###.####"); + out.println(LINE_SEPARATOR); + out.println(BULLET + label); + out.println(LINE_SEPARATOR); + out.println(BULLET + "Allocated objects:\t" + jsObjects); + out.println(BULLET + "Total object array capacity:\t" + oac); + out.println(BULLET + "Total object array size:\t" + oas); + out.println(BULLET + "Total object field size:\t" + ofs); + out.println(BULLET + "Average object array capacity:\t" + avgOAC(format)); + out.println(BULLET + "Average object array size:\t" + avgOAS(format)); + out.println(BULLET + "Average object field size:\t" + avgOFS(format)); + out.println(LINE_SEPARATOR); + out.println(BULLET + "Total primitive array capacity:\t" + pac); + out.println(BULLET + "Total primitive array size:\t" + pas); + out.println(BULLET + "Total primitive field size:\t" + pfs); + out.println(BULLET + "Average primitive array capacity:\t" + avgPAC(format)); + out.println(BULLET + "Average primitive array size:\t" + avgPAS(format)); + out.println(BULLET + "Average primitive field size:\t" + avgPFS(format)); + out.println(LINE_SEPARATOR); + out.println(BULLET + toString()); + out.println(LINE_SEPARATOR + "\n"); + out.flush(); + } + + @Override + public String toString() { + DecimalFormat format = new DecimalFormat("###.####"); + // @formatter:off + return "{" + label + "}" + TOKEN_SEPARATOR + + jsObjects + TOKEN_SEPARATOR + + avgOAC(format) + TOKEN_SEPARATOR + + avgOAS(format) + TOKEN_SEPARATOR + + avgOFS(format) + TOKEN_SEPARATOR + + avgPAC(format) + TOKEN_SEPARATOR + + avgPAS(format) + TOKEN_SEPARATOR + + avgPFS(format); + // @formatter:on + } + + private String avgOAC(DecimalFormat format) { + return format.format((double) oac / jsObjects); + } + + private String avgOAS(DecimalFormat format) { + return format.format((double) oas / jsObjects); + } + + private String avgOFS(DecimalFormat format) { + return format.format((double) ofs / jsObjects); + } + + private String avgPAC(DecimalFormat format) { + return format.format((double) pac / jsObjects); + } + + private String avgPAS(DecimalFormat format) { + return format.format((double) pas / jsObjects); + } + + private String avgPFS(DecimalFormat format) { + return format.format((double) pfs / jsObjects); + } + } + + public static ShapeProfiler getInstance() { + return shapeProf; + } + + private static final ShapeProfiler shapeProf; + static { + if (ObjectStorageOptions.Profile) { + shapeProf = new ShapeProfiler(); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + getInstance().dump(new PrintWriter(System.out), ObjectStorageOptions.ProfileTopResults); + } + }); + } else { + shapeProf = null; + } + } +}