# HG changeset patch # User Artem Tikhomirov # Date 1313497991 -7200 # Node ID 5a6ab50b4cbf6ed3c939f3b7ca0368594a74227d # Parent a620f0663a37cb69a7244b637bd82fb0be4384be Improve memory footprint of tag collection (about 14 Mb saved for cpython repo without HashMap.Entry and Entry[]) diff -r a620f0663a37 -r 5a6ab50b4cbf test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java --- a/test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java Tue Aug 16 04:03:29 2011 +0200 +++ b/test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java Tue Aug 16 14:33:11 2011 +0200 @@ -1,14 +1,27 @@ package org.tmatesoft.hg.test; -import java.io.*; -import java.util.*; -import java.util.Map.Entry; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; -import org.tmatesoft.hg.core.*; +import org.tmatesoft.hg.core.HgChangeset; +import org.tmatesoft.hg.core.HgChangesetHandler; +import org.tmatesoft.hg.core.HgException; +import org.tmatesoft.hg.core.HgLogCommand; +import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.internal.Pool; -import org.tmatesoft.hg.repo.*; +import org.tmatesoft.hg.repo.HgChangelog; +import org.tmatesoft.hg.repo.HgDataFile; +import org.tmatesoft.hg.repo.HgLookup; +import org.tmatesoft.hg.repo.HgManifest; +import org.tmatesoft.hg.repo.HgRepository; +import org.tmatesoft.hg.repo.HgTags; import org.tmatesoft.hg.repo.HgTags.TagInfo; -import org.tmatesoft.hg.util.*; +import org.tmatesoft.hg.util.CancelledException; +import org.tmatesoft.hg.util.Path; /** * @author Marc Strapetz @@ -17,34 +30,51 @@ // Static ================================================================= - public static void main(String[] args) throws HgException, CancelledException { + public static void main(String[] args) throws Exception { + MapTagsToFileRevisions m = new MapTagsToFileRevisions(); + System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); + m.main(); + m = null; + System.gc(); + System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); + } + + private void main() throws HgException, CancelledException { final long start = System.currentTimeMillis(); final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); final HgTags tags = repository.getTags(); // // build cache - final Map> file2tag2rev = new HashMap>(); - System.out.printf("Collecting manifests for %d tags\n", tags.getTags().size()); + // + final TagInfo[] allTags = new TagInfo[tags.getTags().size()]; + tags.getTags().values().toArray(allTags); + // file2rev2tag value is array of revisions, always of allTags.length. Revision index in the array + // is index of corresponding TagInfo in allTags; + final Map file2rev2tag = new HashMap(); + System.out.printf("Collecting manifests for %d tags\n", allTags.length); // effective translation of changeset revisions to their local indexes final HgChangelog.RevisionMap clogrmap = repository.getChangelog().new RevisionMap().init(); - int[] tagLocalRevs = new int[tags.getTags().size()]; - int i = 0; - for (TagInfo tag : tags.getTags().values()) { - final Nodeid tagRevision = tag.revision(); - int tagLocalRev = clogrmap.localRevision(tagRevision); - tagLocalRevs[i++] = tagLocalRev; + int[] tagLocalRevs = new int[allTags.length]; + for (int i = 0; i < allTags.length; i++) { + final Nodeid tagRevision = allTags[i].revision(); + tagLocalRevs[i] = clogrmap.localRevision(tagRevision); } - System.out.printf("Found tag revisions to analyze: %d\n", System.currentTimeMillis() - start); + System.out.printf("Prepared tag revisions to analyze: %d ms\n", System.currentTimeMillis() - start); // repository.getManifest().walk(new HgManifest.Inspector() { - private List tagsAtRev; - final Pool filenamePool = new Pool(); - final Pool nodeidPool = new Pool(); + private final ArrayList tagIndexAtRev = new ArrayList(); + private final Pool filenamePool = new Pool(); + private final Pool nodeidPool = new Pool(); public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) { Nodeid cset = clogrmap.revision(changelogRevision); - tagsAtRev = tags.tags(cset); - if (tagsAtRev.isEmpty()) { + tagIndexAtRev.clear(); + for (int i = 0; i < allTags.length; i++) { + if (cset.equals(allTags[i].revision())) { + tagIndexAtRev.add(i); + } + } + if (tagIndexAtRev.isEmpty()) { System.out.println("Can't happen, provided we iterate over revisions with tags only"); } return true; @@ -53,12 +83,15 @@ public boolean next(Nodeid nid, String fname, String flags) { fname = filenamePool.unify(fname); nid = nodeidPool.unify(nid); - Map m = file2tag2rev.get(fname); + Nodeid[] m = file2rev2tag.get(fname); if (m == null) { - file2tag2rev.put(fname, m = new HashMap()); + file2rev2tag.put(fname, m = new Nodeid[allTags.length]); } - for (String tag : tagsAtRev) { - m.put(tags.getTags().get(tag), nid); + for (int tagIndex : tagIndexAtRev) { + if (m[tagIndex] != null) { + System.out.printf("There's another revision (%s) associated with tag %s already while we try to associate %s\n", m[tagIndex].shortNotation(), allTags[tagIndex].name(), nid.shortNotation()); + } + m[tagIndex] = nid; } return true; } @@ -68,26 +101,26 @@ } }, tagLocalRevs); - System.out.printf("Cache built: %d\n", System.currentTimeMillis() - start); + System.out.printf("Cache built: %d ms\n", System.currentTimeMillis() - start); // // look up specific file. This part is fast. final Path targetPath = Path.create("README"); HgDataFile fileNode = repository.getFileNode(targetPath); + final Nodeid[] allTagsOfTheFile = file2rev2tag.get(targetPath.toString()); // TODO if fileNode.isCopy, repeat for each getCopySourceName() for (int localFileRev = 0; localFileRev < fileNode.getRevisionCount(); localFileRev++) { Nodeid fileRev = fileNode.getRevision(localFileRev); int changesetLocalRev = fileNode.getChangesetLocalRevision(localFileRev); List associatedTags = new LinkedList(); - final Map allTagsOfTheFile = file2tag2rev.get(targetPath.toString()); - for (Entry e : allTagsOfTheFile.entrySet()) { - Nodeid fileRevAtTag = e.getValue(); - if (fileRev.equals(fileRevAtTag)) { - associatedTags.add(e.getKey().name()); + for (int i = 0; i < allTagsOfTheFile.length; i++) { + if (fileRev.equals(allTagsOfTheFile[i])) { + associatedTags.add(allTags[i].name()); } } System.out.printf("%3d%7d%s\n", localFileRev, changesetLocalRev, associatedTags); } - System.out.printf("Total time: %d", System.currentTimeMillis() - start); + System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); + System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); } public static void main2(String[] args) throws HgException, CancelledException {