/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun * Microsystems, Inc. All Rights Reserved. */ import java.io.*; import java.util.*; import java.util.Iterator; import org.netbeans.insane.scanner.CountingVisitor; import org.netbeans.insane.scanner.ScannerUtils; /** * Takes a .cdx file and models the behaviour/layout of a mmap image. * * * @author Petr Nejedly */ public class ClassIndexModel implements Serializable { private static final int VERSION = 2; private static final String BIN_SUFFIX=".cdx"; // NOI18N /** Creates a new instance of ClassIndex */ public ClassIndexModel() { } private void read(String file) throws IOException { File indexFile=new File(file.concat(BIN_SUFFIX)); InputStream indexStream=new BufferedInputStream(new FileInputStream(indexFile), 65536); if (VERSION != readInt(indexStream)) return; readString(indexStream); // storage ID, skip it readMap(indexStream, fqnRoot); readMap(indexStream, snRoot); indexStream.close(); } private void readMap(InputStream indexStream, Node n) throws IOException { int count = readInt(indexStream); System.out.println("count=" + count); for (int i = 0; i < count; i++) { String key = readString(indexStream); int count2 = readInt(indexStream); long[] value = new long[count2]; for (int j = 0; j < count2; j++) { value[j] = readLong(indexStream); if (value[j] > Integer.MAX_VALUE) System.out.println("BIG"); } n.add(key, count2); } } private Node fqnRoot = new Node("", 0); private Node snRoot = new Node("", 0); public static void main(String[] args) throws Exception { ClassIndexModel model = new ClassIndexModel(); model.read("/tmp/cdx/rt15"); int fqnBlocks = model.fqnRoot.recursiveBlocks(); int snBlocks = model.snRoot.recursiveBlocks(); model.fqnRoot.dump(""); System.out.println("\n\n"); model.snRoot.dump(""); System.out.println("\n\n"); System.out.println("Bytes: " + Node.BLOCK_SIZE*(fqnBlocks+snBlocks) + ", fqn blocks=" + fqnBlocks + ", snBlocks=" + snBlocks); System.out.println("chars: " + (model.fqnRoot.chars() + model.snRoot.chars())); System.out.println(" (" + model.fqnRoot.chars() + " + " + model.snRoot.chars() + ")"); System.out.println("O/1 blocks: " + model.fqnRoot.zeroOne() + ", " + model.snRoot.zeroOne()); int[] prefixLens = new int[30]; int[] childrenCounts = new int[30]; int[] valueCounts = new int[30]; model.fqnRoot.sizesDistribution(prefixLens, childrenCounts, valueCounts); model.snRoot.sizesDistribution(prefixLens, childrenCounts, valueCounts); printDist("Prefixes: ", prefixLens); printDist("Children: ", childrenCounts); printDist("Values: ", valueCounts); } private static class Node { String prefix; Map children = new TreeMap(); int values; Node(String prefix, int values) { this.prefix = prefix; this.values = values; } // The numbers in method below are for following cell layout: // 1B header + 7B prefx bytes (longer prefix means intermediate cells) // 3* (1B + 3B) 3 elements of jumptable (more elements mean more cells linked) // 4B value, if more values, append more cells public static int BLOCK_SIZE=24; public int blocks() { int pathBlocks = (prefix.length()+6) / 7; if (pathBlocks == 0) pathBlocks = 1; int valueBlocks = values <= 1 ? 0 : 1 + values/3; int jumpBlocks = children.size() <= 3 ? 0 : ((children.size() - 1) / 3); return pathBlocks + valueBlocks + jumpBlocks; } public int recursiveBlocks() { int ret = blocks(); for (Iterator it = children.values().iterator(); it.hasNext(); ) { ret += ((Node)it.next()).recursiveBlocks(); } return ret; } public int zeroOne() { int ret = children.size() == 0 && values == 1 ? 1 : 0; for (Iterator it = children.values().iterator(); it.hasNext(); ) { ret += ((Node)it.next()).zeroOne(); } return ret; } public int chars() { int ret = prefix.length(); for (Iterator it = children.values().iterator(); it.hasNext(); ) { ret += ((Node)it.next()).chars(); } return ret; } public void sizesDistribution(int[] prefixLens, int[] childrenCounts, int[] valueCounts) { tick(prefixLens, prefix.length()); tick(childrenCounts, children.size()); tick(valueCounts, values); for (Iterator it = children.values().iterator(); it.hasNext(); ) { ((Node)it.next()).sizesDistribution(prefixLens, childrenCounts, valueCounts); } } public void add(String prefix, int values) { // XXX - proper algo! //children.add(new Node(prefix, values)); Character first = new Character(prefix.charAt(0)); Node current = (Node)children.get(first); // first starting with given letter if (current == null) { children.put(first, new Node(prefix, values)); return; } // have "smtg", adding "smtgLonger" // XXX: special case - have "smtg", adding "smtg" if (prefix.startsWith(current.prefix)) { current.add(prefix.substring(current.prefix.length()), values); return; } // have "smtgA" and adding either "smtg" or "smtgB" int common = commonLen(prefix, current.prefix); if (common == prefix.length()) { // "smtg" case Node inter = new Node(prefix, values); children.put(first, inter); // replaces current current.prefix = current.prefix.substring(common); inter.children.put(new Character(current.prefix.charAt(0)), current); } else { // "smtgB" case Node inter = new Node(prefix.substring(0, common), 0); children.put(first, inter); // replaces current current.prefix = current.prefix.substring(common); inter.children.put(new Character(current.prefix.charAt(0)), current); prefix = prefix.substring(common); inter.children.put(new Character(prefix.charAt(0)), new Node(prefix, values)); } } public void dump(String indent) { for(Iterator it = children.keySet().iterator(); it.hasNext(); ) { Character key = (Character)it.next(); Node value = (Node)children.get(key); System.out.println(indent + key + " => " + value.prefix + " (" + value.children.size() + "/" + value.values + ")"); value.dump(indent.concat(" ")); } } static int commonLen(String s1, String s2) { int i = 0; for (; i= array.length) value = array.length-1; array[value]++; } } static void printDist(String header, int[] array) { System.out.print(header); for (int i=0; i= 0xe0) { b = (b & 0x0f) << 12; b |= (inputStream.read() & 0x3f) << 6; b |= inputStream.read() & 0x3f; } else if (b >= 0xc0) { b = (b & 0x1f) << 6; b |= inputStream.read() & 0x3f; } sb.append((char)b); } while (--length > 0); return sb.toString().intern(); } }