8013871: mem usage histograms enabled with compiler logging level set to more specific than or equals to info when --print-mem-usage flag is used

Fri, 03 May 2013 16:01:33 +0200

author
lagergren
date
Fri, 03 May 2013 16:01:33 +0200
changeset 248
829b06307fb2
parent 247
5a3f7867e19c
child 249
c0f0033d7b08

8013871: mem usage histograms enabled with compiler logging level set to more specific than or equals to info when --print-mem-usage flag is used
Reviewed-by: jlaskey, hannesw

src/jdk/nashorn/internal/codegen/Compiler.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/Global.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptEnvironment.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/options/Options.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/resources/Options.properties file | annotate | diff | comparison | revisions
src/jdk/nashorn/tools/Shell.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java	Fri May 03 15:33:54 2013 +0200
     1.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java	Fri May 03 16:01:33 2013 +0200
     1.3 @@ -42,10 +42,13 @@
     1.4  import java.security.PrivilegedActionException;
     1.5  import java.security.PrivilegedExceptionAction;
     1.6  import java.util.Arrays;
     1.7 +import java.util.Collections;
     1.8 +import java.util.Comparator;
     1.9  import java.util.EnumSet;
    1.10  import java.util.HashMap;
    1.11  import java.util.HashSet;
    1.12  import java.util.LinkedList;
    1.13 +import java.util.List;
    1.14  import java.util.Map;
    1.15  import java.util.Map.Entry;
    1.16  import java.util.Set;
    1.17 @@ -56,6 +59,8 @@
    1.18  import jdk.nashorn.internal.codegen.types.Type;
    1.19  import jdk.nashorn.internal.ir.FunctionNode;
    1.20  import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
    1.21 +import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
    1.22 +import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
    1.23  import jdk.nashorn.internal.runtime.CodeInstaller;
    1.24  import jdk.nashorn.internal.runtime.DebugLogger;
    1.25  import jdk.nashorn.internal.runtime.ScriptEnvironment;
    1.26 @@ -289,6 +294,40 @@
    1.27          this(env, null, sequence(env._lazy_compilation), env._strict);
    1.28      }
    1.29  
    1.30 +    private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
    1.31 +        final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
    1.32 +        osc.calculateObjectSize(functionNode);
    1.33 +
    1.34 +        final List<ClassHistogramElement> list = osc.getClassHistogram();
    1.35 +
    1.36 +        final StringBuilder sb = new StringBuilder();
    1.37 +        final long totalSize = osc.calculateObjectSize(functionNode);
    1.38 +        sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB");
    1.39 +        LOG.info(sb);
    1.40 +
    1.41 +        Collections.sort(list, new Comparator<ClassHistogramElement>() {
    1.42 +            @Override
    1.43 +            public int compare(ClassHistogramElement o1, ClassHistogramElement o2) {
    1.44 +                final long diff = o1.getBytes() - o2.getBytes();
    1.45 +                if (diff < 0) {
    1.46 +                    return 1;
    1.47 +                } else if (diff > 0) {
    1.48 +                    return -1;
    1.49 +                } else {
    1.50 +                    return 0;
    1.51 +                }
    1.52 +            }
    1.53 +        });
    1.54 +        for (final ClassHistogramElement e : list) {
    1.55 +            final String line = String.format("    %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
    1.56 +            LOG.info(line);
    1.57 +            if (e.getBytes() < totalSize / 20) {
    1.58 +                LOG.info("    ...");
    1.59 +                break; // never mind, so little memory anyway
    1.60 +            }
    1.61 +        }
    1.62 +    }
    1.63 +
    1.64      /**
    1.65       * Execute the compilation this Compiler was created with
    1.66       * @param functionNode function node to compile from its current state
    1.67 @@ -312,6 +351,10 @@
    1.68          for (final CompilationPhase phase : sequence) {
    1.69              newFunctionNode = phase.apply(this, newFunctionNode);
    1.70  
    1.71 +            if (env._print_mem_usage) {
    1.72 +                printMemoryUsage(phase.toString(), newFunctionNode);
    1.73 +            }
    1.74 +
    1.75              final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
    1.76              time += duration;
    1.77  
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java	Fri May 03 16:01:33 2013 +0200
     2.3 @@ -0,0 +1,113 @@
     2.4 +/*
     2.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.  Oracle designates this
    2.11 + * particular file as subject to the "Classpath" exception as provided
    2.12 + * by Oracle in the LICENSE file that accompanied this code.
    2.13 + *
    2.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.17 + * version 2 for more details (a copy is included in the LICENSE file that
    2.18 + * accompanied this code).
    2.19 + *
    2.20 + * You should have received a copy of the GNU General Public License version
    2.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.23 + *
    2.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.25 + * or visit www.oracle.com if you need additional information or have any
    2.26 + * questions.
    2.27 + */
    2.28 +
    2.29 +package jdk.nashorn.internal.ir.debug;
    2.30 +
    2.31 +import java.util.Comparator;
    2.32 +
    2.33 +/**
    2.34 + * Class histogram element for IR / Java object instrumentation
    2.35 + */
    2.36 +public class ClassHistogramElement {
    2.37 +    /**
    2.38 +     * Instance comparator
    2.39 +     */
    2.40 +    public static final Comparator<ClassHistogramElement> COMPARE_INSTANCES = new Comparator<ClassHistogramElement>() {
    2.41 +        @Override
    2.42 +        public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
    2.43 +            return (int)Math.abs(o1.instances - o2.instances);
    2.44 +        }
    2.45 +    };
    2.46 +
    2.47 +    /**
    2.48 +     * Bytes comparator
    2.49 +     */
    2.50 +    public static final Comparator<ClassHistogramElement> COMPARE_BYTES = new Comparator<ClassHistogramElement>() {
    2.51 +        @Override
    2.52 +        public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
    2.53 +            return (int)Math.abs(o1.bytes - o2.bytes);
    2.54 +        }
    2.55 +    };
    2.56 +
    2.57 +    /**
    2.58 +     * Classname comparator
    2.59 +     */
    2.60 +    public static final Comparator<ClassHistogramElement> COMPARE_CLASSNAMES = new Comparator<ClassHistogramElement>() {
    2.61 +        @Override
    2.62 +        public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
    2.63 +            return o1.clazz.getCanonicalName().compareTo(o2.clazz.getCanonicalName());
    2.64 +        }
    2.65 +    };
    2.66 +
    2.67 +    private final Class<?> clazz;
    2.68 +    private long instances;
    2.69 +    private long bytes;
    2.70 +
    2.71 +    /**
    2.72 +     * Constructor
    2.73 +     * @param clazz class for which to construct histogram
    2.74 +     */
    2.75 +    public ClassHistogramElement(final Class<?> clazz) {
    2.76 +        this.clazz = clazz;
    2.77 +    }
    2.78 +
    2.79 +    /**
    2.80 +     * Add an instance
    2.81 +     * @param sizeInBytes byte count
    2.82 +     */
    2.83 +    public void addInstance(final long sizeInBytes) {
    2.84 +        instances++;
    2.85 +        this.bytes += sizeInBytes;
    2.86 +    }
    2.87 +
    2.88 +    /**
    2.89 +     * Get size in bytes
    2.90 +     * @return size in bytes
    2.91 +     */
    2.92 +    public long getBytes() {
    2.93 +        return bytes;
    2.94 +    }
    2.95 +
    2.96 +    /**
    2.97 +     * Get class
    2.98 +     * @return class
    2.99 +     */
   2.100 +    public Class<?> getClazz() {
   2.101 +        return clazz;
   2.102 +    }
   2.103 +
   2.104 +    /**
   2.105 +     * Get number of instances
   2.106 +     * @return number of instances
   2.107 +     */
   2.108 +    public long getInstances() {
   2.109 +        return instances;
   2.110 +    }
   2.111 +
   2.112 +    @Override
   2.113 +    public String toString() {
   2.114 +        return "ClassHistogramElement[class=" + clazz.getCanonicalName() + ", instances=" + instances + ", bytes=" + bytes + "]";
   2.115 +    }
   2.116 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java	Fri May 03 16:01:33 2013 +0200
     3.3 @@ -0,0 +1,457 @@
     3.4 +/*
     3.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.  Oracle designates this
    3.11 + * particular file as subject to the "Classpath" exception as provided
    3.12 + * by Oracle in the LICENSE file that accompanied this code.
    3.13 + *
    3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.17 + * version 2 for more details (a copy is included in the LICENSE file that
    3.18 + * accompanied this code).
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License version
    3.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.23 + *
    3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.25 + * or visit www.oracle.com if you need additional information or have any
    3.26 + * questions.
    3.27 + */
    3.28 +
    3.29 +package jdk.nashorn.internal.ir.debug;
    3.30 +
    3.31 +import java.lang.management.ManagementFactory;
    3.32 +import java.lang.management.MemoryPoolMXBean;
    3.33 +import java.lang.reflect.Array;
    3.34 +import java.lang.reflect.Field;
    3.35 +import java.lang.reflect.Modifier;
    3.36 +import java.util.ArrayDeque;
    3.37 +import java.util.ArrayList;
    3.38 +import java.util.Arrays;
    3.39 +import java.util.Deque;
    3.40 +import java.util.IdentityHashMap;
    3.41 +import java.util.LinkedList;
    3.42 +import java.util.List;
    3.43 +import java.util.Map;
    3.44 +
    3.45 +/**
    3.46 + * Contains utility methods for calculating the memory usage of objects. It
    3.47 + * only works on the HotSpot JVM, and infers the actual memory layout (32 bit
    3.48 + * vs. 64 bit word size, compressed object pointers vs. uncompressed) from
    3.49 + * best available indicators. It can reliably detect a 32 bit vs. 64 bit JVM.
    3.50 + * It can only make an educated guess at whether compressed OOPs are used,
    3.51 + * though; specifically, it knows what the JVM's default choice of OOP
    3.52 + * compression would be based on HotSpot version and maximum heap sizes, but if
    3.53 + * the choice is explicitly overridden with the <tt>-XX:{+|-}UseCompressedOops</tt> command line
    3.54 + * switch, it can not detect
    3.55 + * this fact and will report incorrect sizes, as it will presume the default JVM
    3.56 + * behavior.
    3.57 + *
    3.58 + * @author Attila Szegedi
    3.59 + */
    3.60 +public class ObjectSizeCalculator {
    3.61 +
    3.62 +    /**
    3.63 +     * Describes constant memory overheads for various constructs in a JVM implementation.
    3.64 +     */
    3.65 +    public interface MemoryLayoutSpecification {
    3.66 +
    3.67 +        /**
    3.68 +         * Returns the fixed overhead of an array of any type or length in this JVM.
    3.69 +         *
    3.70 +         * @return the fixed overhead of an array.
    3.71 +         */
    3.72 +        int getArrayHeaderSize();
    3.73 +
    3.74 +        /**
    3.75 +         * Returns the fixed overhead of for any {@link Object} subclass in this JVM.
    3.76 +         *
    3.77 +         * @return the fixed overhead of any object.
    3.78 +         */
    3.79 +        int getObjectHeaderSize();
    3.80 +
    3.81 +        /**
    3.82 +         * Returns the quantum field size for a field owned by an object in this JVM.
    3.83 +         *
    3.84 +         * @return the quantum field size for an object.
    3.85 +         */
    3.86 +        int getObjectPadding();
    3.87 +
    3.88 +        /**
    3.89 +         * Returns the fixed size of an object reference in this JVM.
    3.90 +         *
    3.91 +         * @return the size of all object references.
    3.92 +         */
    3.93 +        int getReferenceSize();
    3.94 +
    3.95 +        /**
    3.96 +         * Returns the quantum field size for a field owned by one of an object's ancestor superclasses
    3.97 +         * in this JVM.
    3.98 +         *
    3.99 +         * @return the quantum field size for a superclass field.
   3.100 +         */
   3.101 +        int getSuperclassFieldPadding();
   3.102 +    }
   3.103 +
   3.104 +    private static class CurrentLayout {
   3.105 +        private static final MemoryLayoutSpecification SPEC =
   3.106 +                getEffectiveMemoryLayoutSpecification();
   3.107 +    }
   3.108 +
   3.109 +    /**
   3.110 +     * Given an object, returns the total allocated size, in bytes, of the object
   3.111 +     * and all other objects reachable from it.  Attempts to to detect the current JVM memory layout,
   3.112 +     * but may fail with {@link UnsupportedOperationException};
   3.113 +     *
   3.114 +     * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
   3.115 +     *          anything special, it measures the size of all objects
   3.116 +     *          reachable through it (which will include its class loader, and by
   3.117 +     *          extension, all other Class objects loaded by
   3.118 +     *          the same loader, and all the parent class loaders). It doesn't provide the
   3.119 +     *          size of the static fields in the JVM class that the Class object
   3.120 +     *          represents.
   3.121 +     * @return the total allocated size of the object and all other objects it
   3.122 +     *         retains.
   3.123 +     * @throws UnsupportedOperationException if the current vm memory layout cannot be detected.
   3.124 +     */
   3.125 +    public static long getObjectSize(final Object obj) throws UnsupportedOperationException {
   3.126 +        return obj == null ? 0 : new ObjectSizeCalculator(CurrentLayout.SPEC).calculateObjectSize(obj);
   3.127 +    }
   3.128 +
   3.129 +    // Fixed object header size for arrays.
   3.130 +    private final int arrayHeaderSize;
   3.131 +    // Fixed object header size for non-array objects.
   3.132 +    private final int objectHeaderSize;
   3.133 +    // Padding for the object size - if the object size is not an exact multiple
   3.134 +    // of this, it is padded to the next multiple.
   3.135 +    private final int objectPadding;
   3.136 +    // Size of reference (pointer) fields.
   3.137 +    private final int referenceSize;
   3.138 +    // Padding for the fields of superclass before fields of subclasses are
   3.139 +    // added.
   3.140 +    private final int superclassFieldPadding;
   3.141 +
   3.142 +    private final Map<Class<?>, ClassSizeInfo> classSizeInfos = new IdentityHashMap<>();
   3.143 +
   3.144 +
   3.145 +    private final Map<Object, Object> alreadyVisited = new IdentityHashMap<>();
   3.146 +    private final Map<Class<?>, ClassHistogramElement> histogram = new IdentityHashMap<>();
   3.147 +
   3.148 +    private final Deque<Object> pending = new ArrayDeque<>(16 * 1024);
   3.149 +    private long size;
   3.150 +
   3.151 +    /**
   3.152 +     * Creates an object size calculator that can calculate object sizes for a given
   3.153 +     * {@code memoryLayoutSpecification}.
   3.154 +     *
   3.155 +     * @param memoryLayoutSpecification a description of the JVM memory layout.
   3.156 +     */
   3.157 +    public ObjectSizeCalculator(final MemoryLayoutSpecification memoryLayoutSpecification) {
   3.158 +        memoryLayoutSpecification.getClass();
   3.159 +        arrayHeaderSize = memoryLayoutSpecification.getArrayHeaderSize();
   3.160 +        objectHeaderSize = memoryLayoutSpecification.getObjectHeaderSize();
   3.161 +        objectPadding = memoryLayoutSpecification.getObjectPadding();
   3.162 +        referenceSize = memoryLayoutSpecification.getReferenceSize();
   3.163 +        superclassFieldPadding = memoryLayoutSpecification.getSuperclassFieldPadding();
   3.164 +    }
   3.165 +
   3.166 +    /**
   3.167 +     * Given an object, returns the total allocated size, in bytes, of the object
   3.168 +     * and all other objects reachable from it.
   3.169 +     *
   3.170 +     * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
   3.171 +     *          anything special, it measures the size of all objects
   3.172 +     *          reachable through it (which will include its class loader, and by
   3.173 +     *          extension, all other Class objects loaded by
   3.174 +     *          the same loader, and all the parent class loaders). It doesn't provide the
   3.175 +     *          size of the static fields in the JVM class that the Class object
   3.176 +     *          represents.
   3.177 +     * @return the total allocated size of the object and all other objects it
   3.178 +     *         retains.
   3.179 +     */
   3.180 +    public synchronized long calculateObjectSize(final Object obj) {
   3.181 +        // Breadth-first traversal instead of naive depth-first with recursive
   3.182 +        // implementation, so we don't blow the stack traversing long linked lists.
   3.183 +        histogram.clear();
   3.184 +        try {
   3.185 +            for (Object o = obj;;) {
   3.186 +                visit(o);
   3.187 +                if (pending.isEmpty()) {
   3.188 +                    return size;
   3.189 +                }
   3.190 +                o = pending.removeFirst();
   3.191 +            }
   3.192 +        } finally {
   3.193 +            alreadyVisited.clear();
   3.194 +            pending.clear();
   3.195 +            size = 0;
   3.196 +        }
   3.197 +    }
   3.198 +
   3.199 +    /**
   3.200 +     * Get the class histograpm
   3.201 +     * @return class histogram element list
   3.202 +     */
   3.203 +    public List<ClassHistogramElement> getClassHistogram() {
   3.204 +        return new ArrayList<>(histogram.values());
   3.205 +    }
   3.206 +
   3.207 +    private ClassSizeInfo getClassSizeInfo(final Class<?> clazz) {
   3.208 +        ClassSizeInfo csi = classSizeInfos.get(clazz);
   3.209 +        if(csi == null) {
   3.210 +            csi = new ClassSizeInfo(clazz);
   3.211 +            classSizeInfos.put(clazz, csi);
   3.212 +        }
   3.213 +        return csi;
   3.214 +    }
   3.215 +
   3.216 +    private void visit(final Object obj) {
   3.217 +        if (alreadyVisited.containsKey(obj)) {
   3.218 +            return;
   3.219 +        }
   3.220 +        final Class<?> clazz = obj.getClass();
   3.221 +        if (clazz == ArrayElementsVisitor.class) {
   3.222 +            ((ArrayElementsVisitor) obj).visit(this);
   3.223 +        } else {
   3.224 +            alreadyVisited.put(obj, obj);
   3.225 +            if (clazz.isArray()) {
   3.226 +                visitArray(obj);
   3.227 +            } else {
   3.228 +                getClassSizeInfo(clazz).visit(obj, this);
   3.229 +            }
   3.230 +        }
   3.231 +    }
   3.232 +
   3.233 +    private void visitArray(final Object array) {
   3.234 +        final Class<?> arrayClass = array.getClass();
   3.235 +        final Class<?> componentType = arrayClass.getComponentType();
   3.236 +        final int length = Array.getLength(array);
   3.237 +        if (componentType.isPrimitive()) {
   3.238 +            increaseByArraySize(arrayClass, length, getPrimitiveFieldSize(componentType));
   3.239 +        } else {
   3.240 +            increaseByArraySize(arrayClass, length, referenceSize);
   3.241 +            // If we didn't use an ArrayElementsVisitor, we would be enqueueing every
   3.242 +            // element of the array here instead. For large arrays, it would
   3.243 +            // tremendously enlarge the queue. In essence, we're compressing it into
   3.244 +            // a small command object instead. This is different than immediately
   3.245 +            // visiting the elements, as their visiting is scheduled for the end of
   3.246 +            // the current queue.
   3.247 +            switch (length) {
   3.248 +            case 0: {
   3.249 +                break;
   3.250 +            }
   3.251 +            case 1: {
   3.252 +                enqueue(Array.get(array, 0));
   3.253 +                break;
   3.254 +            }
   3.255 +            default: {
   3.256 +                enqueue(new ArrayElementsVisitor((Object[]) array));
   3.257 +            }
   3.258 +            }
   3.259 +        }
   3.260 +    }
   3.261 +
   3.262 +    private void increaseByArraySize(final Class<?> clazz, final int length, final long elementSize) {
   3.263 +        increaseSize(clazz, roundTo(arrayHeaderSize + length * elementSize, objectPadding));
   3.264 +    }
   3.265 +
   3.266 +    private static class ArrayElementsVisitor {
   3.267 +        private final Object[] array;
   3.268 +
   3.269 +        ArrayElementsVisitor(final Object[] array) {
   3.270 +            this.array = array;
   3.271 +        }
   3.272 +
   3.273 +        public void visit(final ObjectSizeCalculator calc) {
   3.274 +            for (final Object elem : array) {
   3.275 +                if (elem != null) {
   3.276 +                    calc.visit(elem);
   3.277 +                }
   3.278 +            }
   3.279 +        }
   3.280 +    }
   3.281 +
   3.282 +    void enqueue(final Object obj) {
   3.283 +        if (obj != null) {
   3.284 +            pending.addLast(obj);
   3.285 +        }
   3.286 +    }
   3.287 +
   3.288 +    void increaseSize(final Class<?> clazz, final long objectSize) {
   3.289 +        ClassHistogramElement he = histogram.get(clazz);
   3.290 +        if(he == null) {
   3.291 +            he = new ClassHistogramElement(clazz);
   3.292 +            histogram.put(clazz, he);
   3.293 +        }
   3.294 +        he.addInstance(objectSize);
   3.295 +        size += objectSize;
   3.296 +    }
   3.297 +
   3.298 +    static long roundTo(final long x, final int multiple) {
   3.299 +        return ((x + multiple - 1) / multiple) * multiple;
   3.300 +    }
   3.301 +
   3.302 +    private class ClassSizeInfo {
   3.303 +        // Padded fields + header size
   3.304 +        private final long objectSize;
   3.305 +        // Only the fields size - used to calculate the subclasses' memory
   3.306 +        // footprint.
   3.307 +        private final long fieldsSize;
   3.308 +        private final Field[] referenceFields;
   3.309 +
   3.310 +        public ClassSizeInfo(final Class<?> clazz) {
   3.311 +            long newFieldsSize = 0;
   3.312 +            final List<Field> newReferenceFields = new LinkedList<>();
   3.313 +            for (Field f : clazz.getDeclaredFields()) {
   3.314 +                if (Modifier.isStatic(f.getModifiers())) {
   3.315 +                    continue;
   3.316 +                }
   3.317 +                final Class<?> type = f.getType();
   3.318 +                if (type.isPrimitive()) {
   3.319 +                    newFieldsSize += getPrimitiveFieldSize(type);
   3.320 +                } else {
   3.321 +                    f.setAccessible(true);
   3.322 +                    newReferenceFields.add(f);
   3.323 +                    newFieldsSize += referenceSize;
   3.324 +                }
   3.325 +            }
   3.326 +            final Class<?> superClass = clazz.getSuperclass();
   3.327 +            if (superClass != null) {
   3.328 +                final ClassSizeInfo superClassInfo = getClassSizeInfo(superClass);
   3.329 +                newFieldsSize += roundTo(superClassInfo.fieldsSize, superclassFieldPadding);
   3.330 +                newReferenceFields.addAll(Arrays.asList(superClassInfo.referenceFields));
   3.331 +            }
   3.332 +            this.fieldsSize = newFieldsSize;
   3.333 +            this.objectSize = roundTo(objectHeaderSize + newFieldsSize, objectPadding);
   3.334 +            this.referenceFields = newReferenceFields.toArray(
   3.335 +                    new Field[newReferenceFields.size()]);
   3.336 +        }
   3.337 +
   3.338 +        void visit(final Object obj, final ObjectSizeCalculator calc) {
   3.339 +            calc.increaseSize(obj.getClass(), objectSize);
   3.340 +            enqueueReferencedObjects(obj, calc);
   3.341 +        }
   3.342 +
   3.343 +        public void enqueueReferencedObjects(final Object obj, final ObjectSizeCalculator calc) {
   3.344 +            for (Field f : referenceFields) {
   3.345 +                try {
   3.346 +                    calc.enqueue(f.get(obj));
   3.347 +                } catch (IllegalAccessException e) {
   3.348 +                    final AssertionError ae = new AssertionError(
   3.349 +                            "Unexpected denial of access to " + f);
   3.350 +                    ae.initCause(e);
   3.351 +                    throw ae;
   3.352 +                }
   3.353 +            }
   3.354 +        }
   3.355 +    }
   3.356 +
   3.357 +    private static long getPrimitiveFieldSize(final Class<?> type) {
   3.358 +        if (type == boolean.class || type == byte.class) {
   3.359 +            return 1;
   3.360 +        }
   3.361 +        if (type == char.class || type == short.class) {
   3.362 +            return 2;
   3.363 +        }
   3.364 +        if (type == int.class || type == float.class) {
   3.365 +            return 4;
   3.366 +        }
   3.367 +        if (type == long.class || type == double.class) {
   3.368 +            return 8;
   3.369 +        }
   3.370 +        throw new AssertionError("Encountered unexpected primitive type " +
   3.371 +                type.getName());
   3.372 +    }
   3.373 +
   3.374 +    /**
   3.375 +     * Return the current memory usage
   3.376 +     * @return current memory usage derived from system configuration
   3.377 +     */
   3.378 +    public static MemoryLayoutSpecification getEffectiveMemoryLayoutSpecification() {
   3.379 +        final String vmName = System.getProperty("java.vm.name");
   3.380 +        if (vmName == null || !vmName.startsWith("Java HotSpot(TM) ")) {
   3.381 +            throw new UnsupportedOperationException(
   3.382 +                    "ObjectSizeCalculator only supported on HotSpot VM");
   3.383 +        }
   3.384 +
   3.385 +        final String dataModel = System.getProperty("sun.arch.data.model");
   3.386 +        if ("32".equals(dataModel)) {
   3.387 +            // Running with 32-bit data model
   3.388 +            return new MemoryLayoutSpecification() {
   3.389 +                @Override public int getArrayHeaderSize() {
   3.390 +                    return 12;
   3.391 +                }
   3.392 +                @Override public int getObjectHeaderSize() {
   3.393 +                    return 8;
   3.394 +                }
   3.395 +                @Override public int getObjectPadding() {
   3.396 +                    return 8;
   3.397 +                }
   3.398 +                @Override public int getReferenceSize() {
   3.399 +                    return 4;
   3.400 +                }
   3.401 +                @Override public int getSuperclassFieldPadding() {
   3.402 +                    return 4;
   3.403 +                }
   3.404 +            };
   3.405 +        } else if (!"64".equals(dataModel)) {
   3.406 +            throw new UnsupportedOperationException("Unrecognized value '" +
   3.407 +                    dataModel + "' of sun.arch.data.model system property");
   3.408 +        }
   3.409 +
   3.410 +        final String strVmVersion = System.getProperty("java.vm.version");
   3.411 +        final int vmVersion = Integer.parseInt(strVmVersion.substring(0,
   3.412 +                strVmVersion.indexOf('.')));
   3.413 +        if (vmVersion >= 17) {
   3.414 +            long maxMemory = 0;
   3.415 +            for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
   3.416 +                maxMemory += mp.getUsage().getMax();
   3.417 +            }
   3.418 +            if (maxMemory < 30L * 1024 * 1024 * 1024) {
   3.419 +                // HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total
   3.420 +                // for all memory pools (yes, including code cache).
   3.421 +                return new MemoryLayoutSpecification() {
   3.422 +                    @Override public int getArrayHeaderSize() {
   3.423 +                        return 16;
   3.424 +                    }
   3.425 +                    @Override public int getObjectHeaderSize() {
   3.426 +                        return 12;
   3.427 +                    }
   3.428 +                    @Override public int getObjectPadding() {
   3.429 +                        return 8;
   3.430 +                    }
   3.431 +                    @Override public int getReferenceSize() {
   3.432 +                        return 4;
   3.433 +                    }
   3.434 +                    @Override public int getSuperclassFieldPadding() {
   3.435 +                        return 4;
   3.436 +                    }
   3.437 +                };
   3.438 +            }
   3.439 +        }
   3.440 +
   3.441 +        // In other cases, it's a 64-bit uncompressed OOPs object model
   3.442 +        return new MemoryLayoutSpecification() {
   3.443 +            @Override public int getArrayHeaderSize() {
   3.444 +                return 24;
   3.445 +            }
   3.446 +            @Override public int getObjectHeaderSize() {
   3.447 +                return 16;
   3.448 +            }
   3.449 +            @Override public int getObjectPadding() {
   3.450 +                return 8;
   3.451 +            }
   3.452 +            @Override public int getReferenceSize() {
   3.453 +                return 8;
   3.454 +            }
   3.455 +            @Override public int getSuperclassFieldPadding() {
   3.456 +                return 8;
   3.457 +            }
   3.458 +        };
   3.459 +    }
   3.460 +}
     4.1 --- a/src/jdk/nashorn/internal/objects/Global.java	Fri May 03 15:33:54 2013 +0200
     4.2 +++ b/src/jdk/nashorn/internal/objects/Global.java	Fri May 03 16:01:33 2013 +0200
     4.3 @@ -1625,7 +1625,6 @@
     4.4          this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug"));
     4.5      }
     4.6  
     4.7 -    @SuppressWarnings("resource")
     4.8      private static Object printImpl(final boolean newLine, final Object... objects) {
     4.9          final PrintWriter out = Global.getEnv().getOut();
    4.10  
     5.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Fri May 03 15:33:54 2013 +0200
     5.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Fri May 03 16:01:33 2013 +0200
     5.3 @@ -171,7 +171,6 @@
     5.4       * @param str  text to write
     5.5       * @param crlf write a carriage return/new line after text
     5.6       */
     5.7 -    @SuppressWarnings("resource")
     5.8      public static void err(final String str, final boolean crlf) {
     5.9          final PrintWriter err = Context.getCurrentErr();
    5.10          if (err != null) {
     6.1 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri May 03 15:33:54 2013 +0200
     6.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Fri May 03 16:01:33 2013 +0200
     6.3 @@ -140,6 +140,9 @@
     6.4      /** Print resulting bytecode for script */
     6.5      public final boolean _print_code;
     6.6  
     6.7 +    /** Print memory usage for IR after each phase */
     6.8 +    public final boolean _print_mem_usage;
     6.9 +
    6.10      /** Print function will no print newline characters */
    6.11      public final boolean _print_no_newline;
    6.12  
    6.13 @@ -211,6 +214,7 @@
    6.14          _print_ast            = options.getBoolean("print.ast");
    6.15          _print_lower_ast      = options.getBoolean("print.lower.ast");
    6.16          _print_code           = options.getBoolean("print.code");
    6.17 +        _print_mem_usage      = options.getBoolean("print.mem.usage");
    6.18          _print_no_newline     = options.getBoolean("print.no.newline");
    6.19          _print_parse          = options.getBoolean("print.parse");
    6.20          _print_lower_parse    = options.getBoolean("print.lower.parse");
     7.1 --- a/src/jdk/nashorn/internal/runtime/options/Options.java	Fri May 03 15:33:54 2013 +0200
     7.2 +++ b/src/jdk/nashorn/internal/runtime/options/Options.java	Fri May 03 16:01:33 2013 +0200
     7.3 @@ -243,7 +243,7 @@
     7.4       */
     7.5      public String getString(final String key) {
     7.6          final Option<?> option = get(key);
     7.7 -        if(option != null) {
     7.8 +        if (option != null) {
     7.9              final String value = (String)option.getValue();
    7.10              if(value != null) {
    7.11                  return value.intern();
     8.1 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties	Fri May 03 15:33:54 2013 +0200
     8.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties	Fri May 03 16:01:33 2013 +0200
     8.3 @@ -247,6 +247,12 @@
     8.4      desc="Print bytecode."    \
     8.5  }
     8.6  
     8.7 +nashorn.option.print.mem.usage = {                            \
     8.8 +    name="--print-mem-usage",                                 \
     8.9 +    is_undocumented=true,                                     \
    8.10 +    desc="Print memory usage of IR after each compile stage." \
    8.11 +}
    8.12 +
    8.13  nashorn.option.print.no.newline = {                     \
    8.14      name="--print-no-newline",                          \
    8.15      is_undocumented=true,                               \
     9.1 --- a/src/jdk/nashorn/tools/Shell.java	Fri May 03 15:33:54 2013 +0200
     9.2 +++ b/src/jdk/nashorn/tools/Shell.java	Fri May 03 16:01:33 2013 +0200
     9.3 @@ -173,9 +173,9 @@
     9.4  
     9.5          if (env._fx) {
     9.6              return runFXScripts(context, global, files);
     9.7 -        } else {
     9.8 -            return runScripts(context, global, files);
     9.9          }
    9.10 +
    9.11 +        return runScripts(context, global, files);
    9.12      }
    9.13  
    9.14      /**

mercurial