TPTP

1.4 "Probe Insertion"

Probes bzw. Probe Insertions dienen der Festlegung von Reaktionen auf während der Laufzeit eines Programms auftretenden Ereignisse und lassen sich in vieler Hinsicht in Bezug auf ihre Wirkung anpassen.


Durchführung einer Probe Insertion:

Als Grundlage für die Tests mit "TPTP Probe Insertion" wurde das Tutorial auf eclipse.org verwendet, um zunächst zwei beispielhafte Szenarien zu konstruieren.

Die Anleitung beschreibt verständlich die Erstellung der "Probekit Source Files" und wie diese zu editieren sind, geht jedoch nicht speziell auf den Inhalt des in den Probe-Dateien verwendeten Quellcodes ein. Die unter Punkt 6.0 Ressources ebenfalls als Download zur Verfügung gestellten Dateien können alternativ heruntergeladen und direkt in das vorhandene Java-Projekt eingebunden werden.

Das Beispiel "ProbekitExample" simuliert eine einfache Kundenbestellung in der Klasse "Order", indem vereinfacht folgende Methoden mit ihren zugehörigen Objekten nacheinander aufgerufen werden:

Sinn und Zweck der "Probe Insertion" ist es, in völlig frei definierbarer Form das Verhalten eines Programms anhand seiner Methodenaufrufe während der Laufzeit des Programms darzustellen. Der TPTP-Agent erkennt zu Zeitpunkten eines Methodenaufrufs verschiedene Events, auf welche jeweils mit benutzerdefiniertem Java-Code reagiert werden kann.
Folgende "Fragment"-Typen (Zustände, in denen sich eine Methode befinden kann) lassen sich in der "Probekit Source File"-Ansicht über die rechte Maustaste auf Profile -> New -> Fragment in das Profil hinzufügen:

Anschließend müssen "Data Items" definieren werden, welche lediglich Platzhalter für Methodennamen, Klassennamen, Exception-Typen und eine Liste anderer Objekte sind. Diese können dann in dem dem Fragment zugehörigen Java-Code angesprochen werden.
Der Java-Code, welcher unter "Probe" ganz oben im Baum definiert werden kann, gilt dann für alle Fragmente des Probe-Profils.
Unter "Targets" kann ein globaler Filter gesetzt werden, der bestimmte Methodennamen mit ein- bzw. ausschließt. Das Arbeiten mit Wildcards ermöglicht hierbei ein sehr flexibles Setzen von Regeln. Sind keine globalen Filter erwünscht, können diese später für das zu überwachende Programm explizit gesetzt werden.

Um "Probe Insertion" auf ein beliebiges Programm anzuwenden, muss ein Probe-Profil für die main()-Methode über "Profile As" -> "Profile Configurations..." konfiguriert werden:

Wie zuvor erwähnt unterscheiden sie sich von den globalen Filtern, welche sich im Probe-Profil selbst definieren lassen.


Das Tutorial beschreibt zwei unterschiedliche Beispiele der Event-Analyse und -Darstellung:

I. "EntryExit"

Der "EntryExit" erkennt, wenn eine Methode betreten bzw. verlassen wurde, reagiert entsprechend mit einer Ausgabe des jeweiligen Methodennamens und deren Status und fügt zudem Leerzeichen so ein, dass ein strukturierter Ausführungsbaum auf der Java-Konsole ausgegeben wird:

run_tree1

II. "Profiling Chart Probe"

Mit Hilfe der Java-Bibliothek JFreeChart, welche hier in der zur Zeit der Erstellung dieses Dokumentes aktuellsten Version 1.0.11 heruntergeladen werden kann, wird es möglich, die durch das Profiling abgefangenen Daten auszuwerten und zu visualisieren.
Das Tutorial verwendet hier zwei Darstellungsmöglichkeiten:

Nach Ausführung des Profilings öffnen sich zwei Fenster, in welchem die genannten Diagramme erscheinen und sich während der Programmlaufzeit aktiv aufbauen. Die Invocations werden hier zweimal gefangen, jeweils bei "entry" und "exit" und da es sich lediglich um eine kleine Simulation handelt, werden in diesem Beispiel alle Methoden jeweils nur einmal aufgerufen:

method_invoc1
method_exec_time1

Für einen weiteren praktischen Test wird das "Profiling Chart Probe"-Profil in ein Java-Projekt übernommen, in welchem mit unterschiedlichen Sortieralgorithmen nacheinander ein Array aus Integer-Zahlen sortiert wird. Der Monitor wird auf "Probe Insertion" gestellt und die "Profiling Chart Probe" aktiviert. Folgende Filter werden konfiguriert, so dass hier die überflüssige main-Methode nicht berücksichtigt wird:

CLASSMETHOD NAMERULE
de.fhwiesbaden.*mainEXCLUDE
de.fhwiesbaden.**INCLUDE
**EXCLUDE

Bei Ausführung der Probe kommt es allerdings zu einer Exception, so dass der Quellcode in "ProfilingChartProbe.probe" im Fragment "exit" wie folgt angepasst werden muss:

In Zeile 144 der anhand des Probe-Profils automatisch erstellten .java-Datei lag ein Problem beim Parsen des Double-Wertes der Execution-Time in ein bestimmt definiertes Dezimalformat vor. Die Zeile wurde wie folgt geändert:

Original: Object[] includeMethodArgs = new Object[] {new Double(Double.parseDouble(df.format(executionTime))), new String(methodName)};

Geändert: Object[] includeMethodArgs = new Object[] {executionTime, new String(methodName)};


Code zum "entry"-Fragment:

 
/* Make sure our object is not NULL before continuing */
if (methodInvocationObject != null)
{
	try
	{		
		/* Get the number of times this method has been executed before */
		Object[] getCountMethodArgs = new Object[] {new String(methodName)};
		int previousValue = ((Integer)getCountMethod.invoke(methodInvocationObject, getCountMethodArgs)).intValue();
		previousValue++;
		
		/* Update method counts */
		Object[] updateMethodCountArgs = new Object[] {new String(methodName), new Integer(previousValue)};
		updateMethodCount.invoke(methodInvocationObject, updateMethodCountArgs);
				
		/* Graph the method only if it has been invoked more than 2500 times */
		if (previousValue >= 1) 
		{
			Object[] includeMethodArgs = new Object[] {new Integer(++previousValue), new String(methodName)};
			includeMethodBarChart.invoke(methodInvocationObject, includeMethodArgs);
		}

		/* Store the start time of the method */
		methodStartTime.put(methodName, new Long(new Date().getTime()));
		
	} catch (Exception e)
	{
		System.err.println("An exception occured while trying to execute the methods of MethodInvocationBarChart: " + e.getMessage());
		e.printStackTrace();
	}			
} 
 

Code zum "exit"-Fragment:

 
/* Get the start time of the method */
Long methodStartTimeObject = (Long)methodStartTime.get(methodName);
if (methodStartTimeObject == null)
	return;
	
long startTime = methodStartTimeObject.longValue();

/* Remove this entry from our hashtable. Makes things a little more optimum */
methodStartTime.remove(methodName);

/* Calculate the execution time of the method (in ms)*/
double executionTime = (double)((new Date().getTime()) - startTime) / (double)1000;

/* We're only interested if the execution time is > than 3 second */
if (executionTime >= 0.001)
{
	try
	{
		/* Graph the execution time of this method */
		Object[] includeMethodArgs = new Object[] {executionTime, new String(methodName)};
		includeMethodPieChart.invoke(methodExecutionObject, includeMethodArgs);		
	}
	catch (Exception e)
	{
		System.err.println("An exception occured while trying to execute the methods of methodInvocationObject");
		e.printStackTrace();
	}
}
 
Daraufhin lässt sich die Probe auch auf das Sortierprogramm ausführen und führt zu folgenden grafischen Ausgaben beim Sortieren von 50000 Zahlen (hier werden wiederrum jeweils zwei Invocations dargestellt, die durch "entry" und "exit", das Betreten und Verlassen der Methoden, begründet sind):
method_invoc2
method_exec_time2
Zurück zur TPTP-Hauptseite
Zurück zur Werkzeugübersicht