PackWriter: Collect stats by object type

Frequently enough I'm wondering how much of a pack is commits vs.
trees, and the total line doesn't really tell us this because its
a gross total from the pack. Computing the counts per object type
is simple during packing, as PackWriter already has everything in
memory broken up by object type.  Its virtually free to get these
values and track them.

Change-Id: Id5e6b1902ea909c72f103a0fbca5d8bc316f9ab3
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Shawn O. Pearce 2011-03-18 07:27:41 -07:00
parent 62fe7c7313
commit bb1956e647
1 changed files with 120 additions and 8 deletions

View File

@ -168,6 +168,8 @@ public class PackWriter {
private final Statistics stats;
private Statistics.ObjectType typeStats;
private List<ObjectToPack> sortedByName;
private byte packcsum[];
@ -650,14 +652,17 @@ public void writePack(ProgressMonitor compressMonitor,
writeMonitor.beginTask(JGitText.get().writingObjects, (int) objCnt);
long writeStart = System.currentTimeMillis();
long headerStart = out.length();
out.writeFileHeader(PACK_VERSION_GENERATED, objCnt);
out.flush();
long headerEnd = out.length();
writeObjects(out);
if (!edgeObjects.isEmpty() || !cachedPacks.isEmpty())
stats.thinPackBytes = out.length() - (headerEnd - headerStart);
if (!edgeObjects.isEmpty() || !cachedPacks.isEmpty()) {
for (Statistics.ObjectType typeStat : stats.objectTypes) {
if (typeStat == null)
continue;
stats.thinPackBytes += typeStat.bytes;
}
}
for (CachedPack pack : cachedPacks) {
long deltaCnt = pack.getDeltaCount();
@ -672,6 +677,16 @@ public void writePack(ProgressMonitor compressMonitor,
stats.totalBytes = out.length();
stats.reusedPacks = Collections.unmodifiableList(cachedPacks);
for (Statistics.ObjectType typeStat : stats.objectTypes) {
if (typeStat == null)
continue;
typeStat.cntDeltas += typeStat.reusedDeltas;
stats.reusedObjects += typeStat.reusedObjects;
stats.reusedDeltas += typeStat.reusedDeltas;
stats.totalDeltas += typeStat.cntDeltas;
}
reader.release();
writeMonitor.endTask();
}
@ -1015,12 +1030,21 @@ private void writeObjects(PackOutputStream out) throws IOException {
private void writeObjects(PackOutputStream out, List<ObjectToPack> list)
throws IOException {
if (list.isEmpty())
return;
typeStats = stats.objectTypes[list.get(0).getType()];
long beginOffset = out.length();
if (reuseSupport != null) {
reuseSupport.writeObjects(out, list);
} else {
for (ObjectToPack otp : list)
out.writeObject(otp);
}
typeStats.bytes += out.length() - beginOffset;
typeStats.cntObjects = list.size();
}
void writeObject(PackOutputStream out, ObjectToPack otp) throws IOException {
@ -1039,10 +1063,10 @@ void writeObject(PackOutputStream out, ObjectToPack otp) throws IOException {
reuseSupport.copyObjectAsIs(out, otp, reuseValidate);
out.endObject();
otp.setCRC(out.getCRC32());
stats.reusedObjects++;
typeStats.reusedObjects++;
if (otp.isDeltaRepresentation()) {
stats.totalDeltas++;
stats.reusedDeltas++;
typeStats.reusedDeltas++;
typeStats.deltaBytes += out.length() - otp.getOffset();
}
return;
} catch (StoredObjectRepresentationNotAvailableException gone) {
@ -1138,7 +1162,8 @@ private void writeDeltaObjectDeflate(PackOutputStream out,
DeflaterOutputStream dst = new DeflaterOutputStream(out, deflater);
delta.writeTo(dst, null);
dst.finish();
stats.totalDeltas++;
typeStats.cntDeltas++;
typeStats.deltaBytes += out.length() - otp.getOffset();
}
private TemporaryBuffer.Heap delta(final ObjectToPack otp)
@ -1579,6 +1604,74 @@ private boolean reuseDeltaFor(ObjectToPack otp) {
/** Summary of how PackWriter created the pack. */
public static class Statistics {
/** Statistics about a single class of object. */
public static class ObjectType {
long cntObjects;
long cntDeltas;
long reusedObjects;
long reusedDeltas;
long bytes;
long deltaBytes;
/**
* @return total number of objects output. This total includes the
* value of {@link #getDeltas()}.
*/
public long getObjects() {
return cntObjects;
}
/**
* @return total number of deltas output. This may be lower than the
* actual number of deltas if a cached pack was reused.
*/
public long getDeltas() {
return cntDeltas;
}
/**
* @return number of objects whose existing representation was
* reused in the output. This count includes
* {@link #getReusedDeltas()}.
*/
public long getReusedObjects() {
return reusedObjects;
}
/**
* @return number of deltas whose existing representation was reused
* in the output, as their base object was also output or
* was assumed present for a thin pack. This may be lower
* than the actual number of reused deltas if a cached pack
* was reused.
*/
public long getReusedDeltas() {
return reusedDeltas;
}
/**
* @return total number of bytes written. This size includes the
* object headers as well as the compressed data. This size
* also includes all of {@link #getDeltaBytes()}.
*/
public long getBytes() {
return bytes;
}
/**
* @return number of delta bytes written. This size includes the
* object headers for the delta objects.
*/
public long getDeltaBytes() {
return deltaBytes;
}
}
Set<ObjectId> interestingObjects;
Set<ObjectId> uninterestingObjects;
@ -1611,6 +1704,16 @@ public static class Statistics {
long timeWriting;
ObjectType[] objectTypes;
{
objectTypes = new ObjectType[5];
objectTypes[Constants.OBJ_COMMIT] = new ObjectType();
objectTypes[Constants.OBJ_TREE] = new ObjectType();
objectTypes[Constants.OBJ_BLOB] = new ObjectType();
objectTypes[Constants.OBJ_TAG] = new ObjectType();
}
/**
* @return unmodifiable collection of objects to be included in the
* pack. May be null if the pack was hand-crafted in a unit
@ -1708,6 +1811,15 @@ public long getThinPackBytes() {
return thinPackBytes;
}
/**
* @param typeCode
* object type code, e.g. OBJ_COMMIT or OBJ_TREE.
* @return information about this type of object in the pack.
*/
public ObjectType byObjectType(int typeCode) {
return objectTypes[typeCode];
}
/**
* @return time in milliseconds spent enumerating the objects that need
* to be included in the output. This time includes any restarts