Beste Methode fürs Profiling

Status
Nicht offen für weitere Antworten.

Usul

Mitglied
Hallo,

gegeben eine Objekt einer Klasse ServiceManager. Diese Klasse kann auf verschiedenen JVMs verteilt sein und lädt dynamisch Dienste, welche in einem eigenen Thread laufen.


Frage: Wie kann man am Besten die DIENSTE (also die Threads) profilen? Natürlich hat man keine Möglichkeit, den Quellcode der Dienste selbst zu verändern. Gesucht ist die Ausführungszeit und der Speicherverbrauch.

Ausführungszeit: Das ist eigentlich kein Problem, da gibts ja mehrere gute Möglichkeiten.

Speicherverbrauch: Hier beginnt der Spass. Das Problem ist natürlich, dass Java von so etwas abstrahiert. Zu betrachten sind also sowohl Heapgröße, als auch die Stackgröße.

Folgende Möglichkeiten habe ich in Betracht gezogen:

MXBeans:
Eine schöne Java-API, die es einen erlaubt einige Infos über die JVM zu bekommen. Leider bekommt man es nicht hin, Speicherverbrauch FÜR THREADS herauszufinden (oder ich habs nicht in der API entdeckt).

JVMPI:
Wird nicht mehr unterstützt.

JVMTI:
Leider in C. Und ich habs mir noch nicht so genau angeschaut als dass ich weiss, wie viele Informationen ich bekomme. Vielleicht weiss ja jemand, ob ich damit auch Speicherverbrauch von Threads erfahren kann. Ich weiss dass es Events für die Objekterzeugung gibt (obwohl anscheinend nicht mehr für eigene Klassen). Die Frage ist, ob man erfahren kann wie viel Speicher das Objekt auf den Heap braucht und von welchem Thread es erzeugt wurde.

Bytecode-Instrumentierung:
Man kann die Java-Klassen ja beim Laden verändern (z.B. mit BCEL). Was man also erhält ist die Möglichkeit, die Klassen so zu verändern als ob man sie selbst schreiben würde. Hier kann man z.B. die Konstruktoren verändern und ein Thread.currentThread() einfügen. Leider geht das nicht für ALLE Klassen, nämlich nicht für die Java-eigenen Klassen. Somit erfährt man auch nicht alles. Und das Abschätzen der Größe der Klassen muss man wohl auch anhand der Felder der Klasse machen.

Weiss jemand mehr als ich? Wie machen es denn Profiling-Tools, oder können die auch nicht den Speicherverbrauch FÜR THREADS ermitteln?

Vielen Dank
 
Profilen tu ich immer mit einem anständigen Profiler. Exemplarisch sei hier www.yourkit.com genannt. Damit ist übrigens auch "remote profiling" im Netzwerk kein Problem.

Speicherverbrauch für Threads? Naja, geht man vom Main-Thread aus kann das jeder 0815 Profiler und auch "JConsole" (im JDK enthalten) anzeigen. Aber für einen speziellen Thread?! Das wäre mir neu. Es gibt eben nur einen Heap in dem alles liegt.

Profile lieber die ganze Anwendung und schau wo der meiste Speicher gebraucht wird. DA kannst du dann anfangen zu optimieren oder wie auch immer.

- Alex
 
maki hat gesagt.:
Speicherverbrauch für Threads?
Hört sich unsinnig an 😉


Die Threads sind Dienste. Und ich möchte ja die Dienste profilen. Ja, heutzutage muss eine Application nicht gleich die Anwendung sein, sondern kann nur das Framework für Anwendungen bilden, welche als eigene Threads laufen. Somit muss man dann den Speicherverbrauch auf diese Anwendungen (=Threads) runterbrechen können. Das ist der Sinn der Sache.
 
Thread != Dienst

Ein Thread führt Code aus, Speicher wird von Datenstrukturen belegt, auf dem Heap.
 
*zustimm*

Wobei das auslegungssache ist. Mit einem Thread kann ich eine Programmlogik, welche mir einen bestimmten Dienst zu verfügung stellt, von der anderen entkoppeln.

Allerdings ist es, AFAIK und offensichtlich auch soweit maki weiß, nicht möglich sagen zu können: Thread A belegt XYZ viel Speicher, davon Fallen ABC auf Klasse oder Membervariable D, ...etc

Speicher lässt sich in Java nicht explizit einem Thread zuordnen.
Du siehst nur, was (klasse, variable, ...) wieviel Speicher belegt. Die Zuordnung, aus welchem Thread das kommt, bleibt dir überlassen.

Schau dir einmal mal einen guten Java Profiler an und spiel damit rum. Du wirst sehen du kommst damit ans Ziel, auch ohne exakt zu wissen welcher Thread wieviel Speicher belegt.

- Alex
 
maki hat gesagt.:

Was ist denn ein Dienst? Es ist kein fest definierter Begriff, so wie Thread! In MEINEN Fall ist Thread=Dienst, da jeder Dienst (bei MIR) in einem eigenen Thread läuft. Für die Problemstellung ist diese Definition hilfreich. Somit kann man die Frage "wieviel Speicher benötigt der Dienst X" runterbrechen auf die sehr viel klarere Frage "wieviel Speicher benötigt Thread Y".

alex0801 hat gesagt.:
Schau dir einmal mal einen guten Java Profiler an und spiel damit rum. Du wirst sehen du kommst damit ans Ziel, auch ohne exakt zu wissen welcher Thread wieviel Speicher belegt.

Es ist mir schon bewusst, wie ich den GESAMTEN Heap-Speicherverbrauch bekomme. Trotzdem muss/möchte ich es für meinen speziellen Fall auf die Threads herunterbrechen können. Letztendlich geht es bei mir um eine automatisierte Bewertung der Dienste, in Hinblick auf die nicht-funktionalen Kriterien wie Zeit und Ressourcenverbrauch. Wie auch immer, das Problem ist und bleibt herauszufinden, welche Objekte auf den Heap liegen UND welcher Thread diese erzeugt hat.
 
Es ist kein fest definierter Begriff, so wie Thread!
Du verwechselst da etwas, Thread ist sehr wohl definiert.
Threads führen Code aus, ohne Threads -> kein laufendes Programm.

Wie ist es denn bei dir, gibt es pro request an deinen Dienst nur einen einzigen Thread? D.h., wenn mehrere Clients einen Dienst anfragen, kann nur ein einziger abgearbeitet werden?

Wenn es bei dir wirklich nur einen Thread pro Dienst gibt (=Singlethreaded) legt das natürlich den Trugschluss nahe, dass beides gleichwertig ist.
Abgesehen davon ist es eine schlechte Idee einen Dienst nur einen einzigen Thread zuzuordnen, Server schreibt man anders.

Wie dem auch sei, Eclipse TPTP kann auch zum Profiling verwendet werden.
 
>> Es ist mir schon bewusst, wie ich den GESAMTEN Heap-Speicherverbrauch bekomme. Trotzdem muss/möchte ich es für meinen speziellen Fall auf die Threads herunterbrechen können.

Und wir haben dir mehrfach versucht zu erklären dass dies nicht möglich ist, zumindest ist uns kein Java Profiler bekannt der sowas bewerkstelligt. Auch der fast 400EUR teure YourKit Java Profiler (www.yourkit.com) kann das AFAIK nicht.

>> Letztendlich geht es bei mir um eine automatisierte Bewertung der Dienste, in Hinblick auf die nicht-funktionalen Kriterien wie Zeit und Ressourcenverbrauch. Wie auch immer, das Problem ist und bleibt herauszufinden, welche Objekte auf den Heap liegen UND welcher Thread diese erzeugt hat.

Dann mach um himmels willen "wirkliche, echte Dienste" daraus, indem du sie in eigene Anwendungen auslagerst.

Innerhalb einer Anwendung mehrere "Dienst" anzubieten und diese dann noch profilen zu wollen... das wäre wie wenn ich MySQL und Apache zusammen mit PHP in eine einzige Executable stecke und dann im nachhinein Profilen möchte wieso und warum und wo mir so viel Speicher flöten geht. Auch hier müsste ich mir den Heap anschauen und selbst zuordnen, welche Klassen oder Variablen viel Speicher verbrauchen, und dann im Stack nachschauen wer (also welcher Thread) sie erzeugt hat.

Ein korrekter Profiler gibt dir alle notwendigen Informationen. Er sagt dir wieviel Zeit in welchem Thread bisher verbracht wurde und wieviel jede einzelne Variable und/oder Klasse im Heap an Speicher benötigt und wer sie letztendlich erzeugt hat oder benutzt, aber er sagt dir nicht "Thread A braucht XX MB vom Heap". Du musst die zusammenhänge selbst herstellen.

- Alex
 
Usul hat gesagt.:
... welche Objekte auf den Heap liegen UND welcher Thread diese erzeugt hat.
Die Information welcher Thread ein Objekt erzeugt hat existiert in Java nicht. Wuerde auch keinen Sinn machen, da der Lebnszyklus eines Objekts vollkommen unabhaengig vom erzeugenden Thread ist.
Deswegen kann auch kein Porfiler die Ressourcen (Speicher) die ein Objekt belegt eindeutig einem Thread zuordnen.
 
maki hat gesagt.:
Du verwechselst da etwas, Thread ist sehr wohl definiert.

Da hab ich mich schlecht ausgedrückt. Ich meinte: Dienst ist nicht eindeutig definiert, IM GEGENSATZ zu Thread (was eindeutig definiert ist, ja). Damit wollte ich klarmachen, dass es praktischer für die Problemstellung ist von Threads zu sprechen, anstatt von Diensten.

maki hat gesagt.:
Wenn es bei dir wirklich nur einen Thread pro Dienst gibt (=Singlethreaded) legt das natürlich den Trugschluss nahe, dass beides gleichwertig ist.
Abgesehen davon ist es eine schlechte Idee einen Dienst nur einen einzigen Thread zuzuordnen, Server schreibt man anders.

Ob das gut oder schlecht ist "nur" einen Thread pro Dienst zu haben, soll hier erstmal keine Rolle spielen. Denn WENN man den Speicherverbauch auf Threads bestimmen kann, DANN kann man auch den Speicherverbrauch für Dienste bestimmen, welche selbst wieder Threads erstellen.

Es ist doch klar, dass wenn ich eine Frage stelle, ich die Problemstellung auf das grundlegende Problem herunterbreche, damit die Frage verständlich wird. Sollte dieses Problem gelöst sein, dann lassen sich auch andere Probleme lösen.

So, ich hoffe diese Definitions-Diskussion ist somit abgeschlossen, weil sie trägt nichts zur Lösung bei 🙂 .

alex0801 hat gesagt.:
Und wir haben dir mehrfach versucht zu erklären dass dies nicht möglich ist, zumindest ist uns kein Java Profiler bekannt der sowas bewerkstelligt.

Dem habe ich doch gar nicht widersprochen? Das habe ich schon verstanden.

alex0801 hat gesagt.:
Dann mach um himmels willen "wirkliche, echte Dienste" daraus, indem du sie in eigene Anwendungen auslagerst.

Geht nicht, da ich auf dieses Framework keinen Zugriff habe.

alex0801 hat gesagt.:
Du musst die zusammenhänge selbst herstellen.
Darauf zielte ja auch meine Frage aus den ersten Posting ab. Ich hatte dazu ja schon mehrere Möglichkeiten erwähnt (wie etwa JVTMI oder Bytecode-Instrumentierung). Die Frage war, ob jemand, der damit Erfahrung hat, weiss wie weit ich mit diesen Möglichkeiten gehen kann.

kleiner_held hat gesagt.:
Die Information welcher Thread ein Objekt erzeugt hat existiert in Java nicht. Wuerde auch keinen Sinn machen, da der Lebnszyklus eines Objekts vollkommen unabhaengig vom erzeugenden Thread ist.
Deswegen kann auch kein Porfiler die Ressourcen (Speicher) die ein Objekt belegt eindeutig einem Thread zuordnen.

Wie gesagt, dass ist mir bewusst. Sonst hätte ich das Problem nicht.

Ich formuliere also meine Problemstellung (hoffentlich eindeutiger) um:
Wie kann man, OBWOHL es diese Zuordnung von Threads zu Objekten nicht in der JVM gibt, diese DENNOCH herstellen? Der Weg der Bytecode-Instrumentierung, den ich gerade gehe, hilft mir da ein Stück weit. Denn ich kann für (fast) jedes (nicht Java-native) Objekt (also dessen Klasse) ein Feld anlegen, was im (veränderten) Konstruktor auf Thread.currentThread() gesetzt wird. Ausserdem kann ich die finalize-Methode verändern (die ja vom GC-Thread aufgerufen wird) und weiss dann anhand des neuen Feldes, zu welchem Thread das Objekt gehörte. So kann ich schon perfekt den Lebenszyklus von Objekten nachvollziehen, inklusive Thread-Zuordnung. Doch leider halt nicht für Java-native Klassen, womit das noch semi-perfekt ist.
 
>> Wie kann man, OBWOHL es diese Zuordnung von Threads zu Objekten nicht in der JVM gibt, diese DENNOCH herstellen?

Zum letzten mal: Indem du einen guten Profiler nimmst und das was zwischen deinen Ohren sitzt benutzt. Automatisiert geht das nicht wirklich zuverlässig.
Welches Objekt welcher Klasse wann und wo von welcher anderen Klasse erzeugt wurde, und wieviel Speicher es frisst sagt dir ein guter Kompiler. Dann musst du nur selbst "erkennen", dann Klasse Ab und B zu Thread X gehören und Klasse C und D zu Thread Y. Dann die einzelnen Werte zusammenrechnen und schon hast du den Speicherverbrauch deines Threads (zumindest in etwa).

Zeit Zeitressourcen eines Threads gibt dir ein guter Profiler von Haus aus.

Aber mal davon abgesehen: Ich geb's auf. Irgendwie red ich hier mit ner Wand... (oder einem Inder.... die wollen nämlich auch immer mit dem Kopf durch die Wand aus Stahlbeton)
 
alex0801 hat gesagt.:
>> Wie kann man, OBWOHL es diese Zuordnung von Threads zu Objekten nicht in der JVM gibt, diese DENNOCH herstellen?

Zum letzten mal: Indem du einen guten Profiler nimmst und das was zwischen deinen Ohren sitzt benutzt. Automatisiert geht das nicht wirklich zuverlässig.
Welches Objekt welcher Klasse wann und wo von welcher anderen Klasse erzeugt wurde, und wieviel Speicher es frisst sagt dir ein guter Kompiler. Dann musst du nur selbst "erkennen", dann Klasse Ab und B zu Thread X gehören und Klasse C und D zu Thread Y. Dann die einzelnen Werte zusammenrechnen und schon hast du den Speicherverbrauch deines Threads (zumindest in etwa).

Zeit Zeitressourcen eines Threads gibt dir ein guter Profiler von Haus aus.

Aber mal davon abgesehen: Ich geb's auf. Irgendwie red ich hier mit ner Wand... (oder einem Inder.... die wollen nämlich auch immer mit dem Kopf durch die Wand aus Stahlbeton)

Es gibt eigentlich keinen Grund für Aggressionen. Wenn es dir lästig ist zu antworten, dann machs doch einfach nicht.

Die Problemstellung verlangt nun einmal Automatisierung. Daran kann ich nichts ändern. Wenn ich manuell EINEN Dienst/Applikation profilen sollte, dann würde ich das auch hinkriegen.

Dass das automatisiert nicht wirklich zuverlässig geht, merke ich. Trotzdem möchte ich sehen wie weit man gehen kann. Und vielleicht gibt es ja jemanden mit ner genialen Idee.
 
Agressionen? Hab ich was verpasst?

3 von 4 Antwortern in diesem Thread haben gesagt es geht nicht. Naja, die Hoffnung stirbt zuletzt, oder wie war das nochmal?!

- Alex
 
alex0801 hat gesagt.:
Agressionen? Hab ich was verpasst?

3 von 4 Antwortern in diesem Thread haben gesagt es geht nicht. Naja, die Hoffnung stirbt zuletzt, oder wie war das nochmal?!

- Alex

Und ich habe auch genauso oft gesagt, dass ich das verstanden habe. Leider sind die Restriktionen nunmal so wie sie sind und liegen ausserhalb meiner Einflussmoeglichkeiten.

Aber es geht nicht stimmt ja nicht so ganz. Mit dem Weg der Bytecode-Instrumentierung geht es zumindest etwas. Ausserdem habe ich gerade festgestellt, dass man sogar java.lang.Object instrumentieren kann (und auch andere Java-Systemklassen). Also komme ich schon in die richtige Richtung. Natürlich ist es dann am Ende auch noch eine Ermessensfrage, wie bei jedem Profiling-Problem, ob man für die gewünschten Informationen die Einbussen in Geschwindigkeit und (ggf.) Speicher in Kauf nimmt.

Also Fazit: Über Bytecode-Instrumentierung gehts, wenn auch nicht perfekt. Aber eine andere Möglichkeit sehe ich auch nicht. Und wie gesagt, an der Problemstellung kann ich leider nichts ändern.

Gast: Leider darf ich die Anwendung (oder die "Dienste") auch nicht ändern. 🙂
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben