[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[cdt-patch] Patch for ElfBinaryParser/Elf to optimize project creation
|
Folks,
Fix to address PR 52095 which discusses the need to cache informtation
for the common case of project creation. This patch should be applied
to the 1.2 stream only and for 2.0 we should consider adjustments to
the BinaryParser API to allow more of the initial information to flow
through to implementors, or lazy caching, so as to avoid having each
binary parser do the work themselves.
Performance testing the results:
without patch opening large project: 6minutes 10sec
with patch opening large project: 3minutes 30sec
For the ChangeLog
- Cache the last byte array passed to the ElfParser.isBinary()
call and use it to avoid having to re-open and re-read the
file contents of a binary object. PR 52095
Thanks,
Thomas
Index: utils/org/eclipse/cdt/utils/elf/Elf.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java,v
retrieving revision 1.15.2.2
diff -u -r1.15.2.2 Elf.java
--- utils/org/eclipse/cdt/utils/elf/Elf.java 22 Jan 2004 16:41:32 -0000 1.15.2.2
+++ utils/org/eclipse/cdt/utils/elf/Elf.java 15 Feb 2004 14:37:11 -0000
@@ -140,6 +140,54 @@
e_shnum = efile.readShortE();
e_shstrndx = efile.readShortE();
}
+
+ protected ELFhdr(byte [] bytes) throws IOException {
+ if(bytes.length <= e_ident.length) {
+ throw new IOException("Not ELF format");
+ }
+ System.arraycopy(bytes, 0, e_ident, 0, e_ident.length);
+ if ( e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E' ||
+ e_ident[ELFhdr.EI_MAG2] != 'L' || e_ident[ELFhdr.EI_MAG3] != 'F' )
+ throw new IOException("Not ELF format");
+ boolean isle = (e_ident[ELFhdr.EI_DATA] == ELFhdr.ELFDATA2LSB);
+ int offset = e_ident.length;
+ e_type = makeShort(bytes, offset, isle); offset += 2;
+ e_machine = makeShort(bytes, offset, isle); offset += 2;
+ e_version = makeInt(bytes, offset, isle); offset += 4;
+ e_entry = makeInt(bytes, offset, isle); offset += 4;
+ e_phoff = makeInt(bytes, offset, isle); offset += 4;
+ e_shoff = makeInt(bytes, offset, isle); offset += 4;
+ e_flags = makeInt(bytes, offset, isle); offset += 4;
+ e_ehsize = makeShort(bytes, offset, isle); offset += 2;
+ e_phentsize = makeShort(bytes, offset, isle); offset += 2;
+ e_phnum = makeShort(bytes, offset, isle); offset += 2;
+ e_shentsize = makeShort(bytes, offset, isle); offset += 2;
+ e_shnum = makeShort(bytes, offset, isle); offset += 2;
+ e_shstrndx = makeShort(bytes, offset, isle); offset += 2;
+ }
+
+ private final short makeShort(byte [] val, int offset, boolean isle) throws IOException {
+ if (val.length < offset + 2)
+ throw new IOException();
+ if ( isle ) {
+ return (short)((val[offset + 1] << 8) + val[offset + 0]);
+ } else {
+ return (short)((val[offset + 0] << 8) + val[offset + 1]);
+ }
+ }
+
+ private final long makeInt(byte [] val, int offset, boolean isle) throws IOException
+ {
+ if (val.length < offset + 4)
+ throw new IOException();
+ if ( isle ) {
+ return ((val[offset + 3] << 24) + (val[offset + 2] << 16) + (val[offset + 1] << 8) + val[offset + 0]);
+ } else {
+ return ((val[offset + 0] << 24) + (val[offset + 1] << 16) + (val[offset + 2] << 8) + val[offset + 3]);
+ }
+ }
+
+
}
public class Section {
@@ -590,6 +638,10 @@
}
}
}
+
+ //A hollow entry, to be used with caution in controlled situations
+ protected Elf () {
+ }
public Elf (String file, long offset) throws IOException {
commonSetup( file, offset, true );
@@ -647,11 +699,10 @@
}
}
-
public Attribute getAttributes() throws IOException {
- Attribute attrib = new Attribute();
-
- switch( ehdr.e_type ) {
+ Attribute attrib = new Attribute();
+
+ switch( ehdr.e_type ) {
case Elf.ELFhdr.ET_CORE:
attrib.type = Attribute.ELF_TYPE_CORE;
break;
@@ -744,21 +795,33 @@
// getSections
// find .debug using toString
Section [] sec = getSections();
- for (int i = 0; i < sec.length; i++) {
- String s = sec[i].toString();
- attrib.bDebug = (s.startsWith(".debug") || s. equals(".stab"));
- if (attrib.bDebug) {
- break;
+ if(sec != null) {
+ for (int i = 0; i < sec.length; i++) {
+ String s = sec[i].toString();
+ attrib.bDebug = (s.startsWith(".debug") || s. equals(".stab"));
+ if (attrib.bDebug) {
+ break;
+ }
}
}
return attrib;
}
-
public static Attribute getAttributes(String file) throws IOException {
Elf elf = new Elf(file);
Attribute attrib = elf.getAttributes();
elf.dispose();
+ return attrib;
+ }
+
+ public static Attribute getAttributes(byte [] array) throws IOException {
+
+ Elf emptyElf = new Elf();
+ emptyElf.ehdr = emptyElf.new ELFhdr(array);
+ emptyElf.sections = new Elf.Section[0];
+ Attribute attrib = emptyElf.getAttributes();
+ emptyElf.dispose();
+
return attrib;
}
Index: utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java,v
retrieving revision 1.2.2.1
diff -u -r1.2.2.1 ElfParser.java
--- utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java 18 Nov 2003 17:16:39 -0000 1.2.2.1
+++ utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java 15 Feb 2004 14:37:11 -0000
@@ -22,6 +22,9 @@
/**
*/
public class ElfParser extends AbstractCExtension implements IBinaryParser {
+ byte [] fCachedByteArray;
+ IPath fCachedPathEntry;
+ boolean fCachedIsAR;
/**
* @see org.eclipse.cdt.core.model.IBinaryParser#getBinary(IPath)
@@ -33,7 +36,30 @@
BinaryFile binary = null;
try {
- Elf.Attribute attribute = Elf.getAttributes(path.toOSString());
+ Elf.Attribute attribute = null;
+
+ //Try our luck with the cached entry first, then clear it
+ if(fCachedPathEntry != null && fCachedPathEntry.equals(path)) {
+ try {
+ //Don't bother with ELF stuff if this is an archive
+ if(fCachedIsAR) {
+ return new BinaryArchive(path);
+ }
+ //Well, if it wasn't an archive, go for broke
+ attribute = Elf.getAttributes(fCachedByteArray);
+ } catch(Exception ex) {
+ attribute = null;
+ } finally {
+ fCachedPathEntry = null;
+ fCachedByteArray = null;
+ }
+ }
+
+ //Take a second run at it if the cache failed.
+ if(attribute == null) {
+ attribute = Elf.getAttributes(path.toOSString());
+ }
+
if (attribute != null) {
switch (attribute.getType()) {
case Attribute.ELF_TYPE_EXE :
@@ -72,7 +98,24 @@
* @see org.eclipse.cdt.core.IBinaryParser#isBinary(byte[], org.eclipse.core.runtime.IPath)
*/
public boolean isBinary(byte[] array, IPath path) {
- return Elf.isElfHeader(array) || AR.isARHeader(array);
+ boolean isBinaryReturnValue = false;
+
+ if(Elf.isElfHeader(array)) {
+ isBinaryReturnValue = true;
+ fCachedIsAR = false;
+ } else if(AR.isARHeader(array)) {
+ isBinaryReturnValue = true;
+ fCachedIsAR = true;
+ }
+
+ //If it is a binary, then cache the array in anticipation that we will be asked to do something with it
+ if(isBinaryReturnValue && array.length > 0) {
+ fCachedPathEntry = path;
+ fCachedByteArray = new byte[array.length];
+ System.arraycopy(array, 0, fCachedByteArray, 0, array.length);
+ }
+
+ return isBinaryReturnValue;
}
}