Bonsoir, je recherche un moyen de timer toutes les méthodes d'un programme sans pour autant les modifier à la main une à une.
J'ai essayé en utilisant BCEL (en adaptant un peu un code chinois), cela fonctionne bien sauf sur les méthodes contenant des "try - catch".
Si vous connaissez un moyen pour régler ce problème (ou un autre système), je vous en serais éterneeeeeeellement reconnaissant

Voilà le code de l'agent que j'utilise actuellement. Fonctionne bien sauf si une classe possède un code du genre
try
{
// instruction non vide
}
catch (Exception e) {}
--------------------------------------------------------------------
import
java.io.ByteArrayInputStream;import
java.io.ByteArrayOutputStream;import
java.io.InputStream;import
java.lang.instrument.ClassFileTransformer;import
java.lang.instrument.IllegalClassFormatException;import
java.lang.instrument.Instrumentation;import
java.security.ProtectionDomain;import
org.apache.bcel.Constants;import
org.apache.bcel.classfile.ClassParser;import
org.apache.bcel.classfile.JavaClass;import
org.apache.bcel.classfile.Method;import
org.apache.bcel.generic.ClassGen;import
org.apache.bcel.generic.ConstantPoolGen;import
org.apache.bcel.generic.InstructionConstants;import
org.apache.bcel.generic.InstructionFactory;import
org.apache.bcel.generic.InstructionList;import
org.apache.bcel.generic.MethodGen;import
org.apache.bcel.generic.ObjectType;import
org.apache.bcel.generic.PUSH;import
org.apache.bcel.generic.Type;
/**
*Classréécrivant*/public
class Timer implements ClassFileTransformer {
privatestaticfinal String EXT_NAME = "_copie";publicbyte[] transform(ClassLoader loader, String className, Class cBR, ProtectionDomain pD,
byte[] classfileBuffer)throws IllegalClassFormatException {
try{
// Charge la classe couranteString classFileName = className +
".class";InputStream is = Timer.
class.getClassLoader().getResourceAsStream(classFileName);JavaClass jclass =
new ClassParser(is, classFileName).parse();// Initialise le ClassGenClassGen cgen =
new ClassGen(jclass);// Ajoute le timer pour chaque méthode de la classeMethod[] methods = jclass.getMethods();
for (int index = 0; index < methods.length; index++) {
try{
// Pas de timer sur constructeur (... pour le moment !)if (!methods[index].getName().equals("<init>"))addTimer(cgen, methods[index]);
}
catch (Exception e) {e.printStackTrace();}}
// Renvoie le code la classe ByteArrayOutputStream bos =
new ByteArrayOutputStream();cgen.getJavaClass().dump(bos);
return bos.toByteArray();}
catch (Exception e) {
e.printStackTrace();
}
returnnull;}
privatestaticvoid addTimer(ClassGen cgen, Method method) {
// ----------------- DES INITIALISATIONS...InstructionFactory ifact =
new InstructionFactory(cgen);InstructionList ilist =
new InstructionList();ConstantPoolGen pgen = cgen.getConstantPool();
String cname = cgen.getClassName();
MethodGen wrapgen =
new MethodGen(method, cname, pgen);wrapgen.setInstructionList(ilist);
// ----------------- RENOMME LA METHODE ORIGINALE// Méthode à modifierMethodGen methgen =
new MethodGen(method, cname, pgen);// Suppression de la méthodecgen.removeMethod(method);
String iname = methgen.getName() +
EXT_NAME;methgen.setName(iname);
// Ajout de la méhode, renomméecgen.addMethod(methgen.getMethod());
// ----------------- PREPARE LA NOUVELLE METHODE// Type de retour de la méthodeType result = methgen.getReturnType();
// Paramètres de la méthodeType[] parameters = methgen.getArgumentTypes();
int stackIndex = methgen.isStatic() ? 0 : 1;for (int i = 0; i < parameters.length; i++)stackIndex += parameters[i].getSize();
// Enregistre le temps au début de la méthodeilist.append(ifact.createInvoke(
"java.lang.System","currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC));ilist.append(InstructionFactory.createStore(Type.
LONG, stackIndex));// Méthode static ou non TODO Voir pour constructeurs iciint offset = 0;short invoke = Constants.INVOKESTATIC;if (!methgen.isStatic()) {
ilist.append(InstructionFactory.createLoad(Type.
OBJECT, 0));offset = 1;
invoke = Constants.
INVOKEVIRTUAL;}
// Les paramètresfor (int i = 0; i < parameters.length; i++) {
Type type = parameters[i];
ilist.append(InstructionFactory.createLoad(type, offset));
offset += type.getSize();
}
// Signature de la méthodeilist.append(ifact.createInvoke(cname, iname, result, parameters, invoke));
// ???if (result != Type.VOID)ilist.append(InstructionFactory.createStore(result, stackIndex+2));
// ----------------- AFFICHAGE DU TEMPS ECOULEilist.append(ifact.createFieldAccess(
"java.lang.System","out", new ObjectType("java.io.PrintStream"),Constants.
GETSTATIC));ilist.append(InstructionConstants.
DUP);ilist.append(InstructionConstants.
DUP);String text = cgen.getClassName() +
"\t"+ methgen.getName() +"\t";ilist.append(
new PUSH(pgen, text));ilist.append(ifact.createInvoke(
"java.io.PrintStream","print", Type.VOID, new Type[] { Type.STRING },Constants.
INVOKEVIRTUAL));ilist.append(ifact.createInvoke(
"java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.
INVOKESTATIC));ilist.append(InstructionFactory.
createLoad(Type.
LONG, stackIndex));ilist.append(InstructionConstants.
LSUB);ilist.append(ifact.createInvoke(
"java.io.PrintStream","print", Type.VOID, new Type[] { Type.LONG },Constants.
INVOKEVIRTUAL));ilist.append(
new PUSH(pgen, " ms."));ilist.append(ifact.createInvoke(
"java.io.PrintStream","println", Type.VOID, new Type[] { Type.STRING },Constants.
INVOKEVIRTUAL));// ----------------- RENVOI LE RETOUR DE LA METHODE ORIGINALEif (result != Type.VOID) ilist.append(InstructionFactory.createLoad(result, stackIndex+2));
ilist.append(InstructionFactory.createReturn(result));
// ----------------- POUR FINIR...wrapgen.stripAttributes(
true);wrapgen.setMaxStack();
wrapgen.setMaxLocals();
cgen.addMethod(wrapgen.getMethod());
ilist.dispose();
}
/***Correspondau"Main"del'agent.Utiliserl'appel:<br />*java-javaagent:test.jarpackage.MainClass*@paramoptions*@paramins*/publicstaticvoid premain(String options, Instrumentation ins) {
ins.addTransformer(
new Timer());}
}