PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Cygwin, GCJ, Access einbinden



Blaubär
11-10-2004, 16:14
Hallo,

ich habe Daten in einer Access Datenbank und hole die bisher mit Java ab und das restliche Programm lief bisher auch in Java. Da das ganze doch langsam zeitrelevant wird, würde ich doch gerne was schnelleres haben. Ich habe teilweise mit JNI (über cygwin compiliert) rechenzeitintensive Schleifen ausgelagert.

Eigentlich waere es aber wohl eleganter alles mit GCJ zu kompilieren. Mittlerweile kann ich mit Cygwin und gcj auch exe-Dateien zu erstellen, solange kein Datenbankaufruf dabei ist. Deshalb die Frage:

Ist es ueberhaupt möglich, das java.sql.* - Paket mit einzubinden und wenn wie ?

Und wie schaut der Geschwindigkeitsvergleich zwischen C und mit GCJ kompilierten Java aus ?
Im Zweifel wuerde ich mir auch die Mühe machen, meine eher rudimentären C/C++ - Kenntnisse auszubauen.

Vielen Dank schon mal

Blaubär

peschmae
11-10-2004, 17:10
Gemäss Status-Website (http://www.kaffe.org/~stuart/japi/htmlout/h-jdk14-classpath.html) des Classpath-Projekts (was GCJ verwendet) ist das java.sql Zeugs zu 91.38% fertig.
Fehlen/nicht gut sein tun die Sachen (http://www.kaffe.org/~stuart/japi/htmlout/h-jdk14-classpath.html#pkg_java_sql)

Evtl. gibts da ein Problem.
Was für nen GCJ hast du? Ne aktuelle Version?

Ansonsten versuchst du eventuell besser einen der (kostenpflichtigen) anderen nativen Compiler von Java auf Windows:
z.B. http://www.excelsior-usa.com/jet.html

Gut geschriebener C-Code ist am Ende wohl meist schneller - auch schneller als nativ kompilierter Java-Code weil der ja in jedem Fall noch ne Garbage-Collection und Speicherüberwachung, etc am Laufen hat.
Ob das aber relevant ist - kommt auf die Anwendung an, aber meist ist das wohl egal.

MfG Peschmä

Lin728
11-10-2004, 20:43
- Nichts aus Zeitgründen per JNI auslagern! In JNI mit Java-Objecten zu arbeiten ist furchbar langsam.
- Native Compiler bringen keine großen Vorteile (GCJ ist langsamer als Java

-> schmeiss lieber einen profiler an und sieh nach, wo die ganze zeit verbraten wird. Sehr oft ist zu häufige Instanzierung der Grund, warum Anwnedungen lansam sind. String-Operationen sind ein gutes Beispiel.
Man erreicht generell durch Optimierung von Algorythmen einen viel besseren geschwindigkeitsgewinn als durch irgendwelche special Compilier.

Die Hotspot-engine ist wirklich sehr gut.

Blaubär
12-10-2004, 13:16
Hallo,

vielen Dank für die Antwort. Schaut so aus, als ob ich sql und gcj erst einmal nicht miteinander zum Sprechen bekomme. Die Daten liegen halt nur in einer Access-Datenbank vor. Ich verwende übrigens Cygwin GCj 3.3.3.
Eine Profiler (Testversion JProfiler) habe ich schon mal mitlaufen lassen und schon viel Zeit reingeholt.

Meine Erfahrung mit JNI war, dass es ein wenig Zeit reinholt, aber nicht so relevant ist. Ich brauche komplexe Zahlen und verwende in Java eine eigene Klasse, die zugegebenermaßen nicht optimal ist (was man schön im Profilersieht ;-)). In C geht das viel einfacher und übersichtlicher. Ich schiebe auch keine Objekt hin- und her sondern nur doubles. Vielleicht ist es deshalb schneller als reines Java.

Wenn ich den zweiten Beitrag richtig verstanden habe, kann ich mit einer nativen Compilierung mein Javaprogramm auf minimal ca. 70 % der normalen Zeit druecken. C sollte bis zu 10 und mehrfach schneller sein (weniger 10 % der Zeit), so dass sich eine native Compilierung dann nicht wirklich rentiert, oder ?

Tschuess
Blaubär

Lin728
12-10-2004, 15:13
Hallo nochmal!

Ja genau, durch native kompilierung wirds nicht viel weniger als 0,7 der Zeit brauchen, was die jetzige bytecode version braucht. Manchmal gibts ausnamen, aberGCJ ist sowieso eher langsamer als Hotspot-server jvm.
Eventuell dass du mit JET noch ein wenig raushohlen kannst...

Würd es dir viel ausmachen den code seiner rechenklasse hier zu posten, eventuell kann ich ja auch noch Probleme finden, wenn diese KLasse laut Profilier wirklich ein Flaschenhals ist.
Wenn dir das zu öffentlich ist, schicks mir halt als PN, ich sehs mir mal an.
Mir kommt das Statement bezüglich C und doubles und Objecte schieben nämlich ein wenig komisch vor ;-)

Java ist nicht wirklich selbst so langsam, es bietet dem programmierer nur viel mehr Komfortfeatures, welche man oft ganz unbewusst ausnützt.
In C hat man für alles was C braucht "gewisse Zeilen", wo man ganz genau weiß, dass die weh tun, drum vermeidet man Sie auch wenns geht.
In Java läuft das oft einfach mit ;-)

Blaubär
12-10-2004, 15:48
Alles kann ich nicht posten, ist schoen aufgeteilt auf mehr als 20 Klassen. Hier Ausschnitte aus zwei Klassen, bei denen ich schon weiss, dass es sehr suboptimal ist (sehr viele erzeugte Objekte im Profiler ;-)), Komplex in der Funktion noch mal anzulegen.
Das macht aber die Klasse, die Komplex benutzt übersichtlicher, bzw. funktioniert es mit C sehr gut und sehr viel übersichtlicher (u.a. funktioniert Punkt vor Strich ;-)).
Ich habe auch mal kurz probiert, das effizienter zu gestalten, aber nachdem mit JNI alles funktioniert hat, habe ich das nicht weiter verfolgt.

Klasse 1

public Komplex(double x, double y)
{
this.x = x;
this.y = y;
}

public Komplex add(Komplex z)
{
double x1 = z.getX();
double y1 = z.getY();
double xx = x + x1;
double yy = y + y1;
Komplex zz = new Komplex(xx, yy);
return zz;
}
usw. für die restlichen Funkionen

Klasse 2

public KubischCardanisch()
{
r = 0; s = 0; t = 0;
u = new Komplex();
v = new Komplex();
y1 = new Komplex();y2 = new Komplex();y3 = new Komplex();
D = new Komplex();
}
......
public void rechneRST(double r, double s, double t)
{
this.r = r;
this.s = s;
this.t = t;
double p, q;
// Bestimmung von p,q,D
p = (3.*s - r*r)/3;
q = (2.*r*r*r)/27 - r*s/3 + t;
D.setX(Math.pow(p/3, 3) + Math.pow(q/2, 2));

// Bestimmung von u,v
u1 = new Komplex(-q/2., 0).add(D.pow(0.5));
u = u1.pow(0.3333333);

uu = u.multiply(3, 0);
v = (new Komplex(-p, 0).divide(uu));

// Lösung der sog. reduzierten Gleichung
y1 = u.add(v);

//y2=(-(u+v)/2) + ((u-v)/2)*(3**(1./2.))*(0.0,1.0)
y21 = u.add(v).divide(-2,0);
y22 = (u.subtract(v)).divide(2,0).multiply(Math.sqrt(3), 0).multiply(0, 1);
y2 = y21.add(y22);

//y3=(-(u+v)/2)-((u-v)/2)*(3**(1./2.))*(0.0,1.0)
y31 = u.add(v).divide(-2,0);
y32 = u.subtract(v).divide(2,0).multiply(Math.sqrt(3), 0).multiply(0, 1);
y3 = y31.subtract(y32);

// Rücktransformation zum Berechnen der Lösungen x1,x2,x3
x1 = y1.subtract(r/3, 0);
x2 = y2.subtract(r/3, 0);
x3 = y3.subtract(r/3, 0);
}

In C schaut das dann so aus

#include <jni.h>
#include <stdio.h>
#include <complex.h>
#include <math.h>
#include "KubCardanisch.h"

.....

JNIEXPORT void JNICALL Java_KubCardanisch_rechne (JNIEnv *env, jobject obj, jdouble r, jdouble s, jdouble t)
{
double p,q;
double complex u,v;
double complex y1,y2,y3; // Lösung der reduzierten Gleichung
double complex x1,x2,x3; // Lösung der kubischen Gleichung
double complex D; // Diskriminante

// Bestimmung von p,q,D
p=((3.*s)-(r*r))/3. ;
q=(2.*pow(r, 3)/27.) - (r*s/3.) + t ;
D=powC((p/3.), 3) + powC((q/2.), 2);

// Bestimmung von u,v
u=powC((-q/2.+(powC(D, (1./2.)))), (1./3.));
v=-p/(3*u);

//Lösung der sog. reduzierten Gleichung
y1=u + v;
y2=(-(u+v)/2) + ((u-v)/2)*powC(3, (1./2.))*1.0i;
y3=(-(u+v)/2) - ((u-v)/2)*powC(3, (1./2.))*1.0i;

// Rücktransformation zum Berechnen der Lösungen x1,x2,x3
x1=y1-r/3.;
x2=y2-r/3.;
x3=y3-r/3.;

v1 = creal(x1);
v2 = creal(x2);
v3 = creal(x3);
}
JNIEXPORT jdouble JNICALL Java_KubCardanisch_getVolumen1 (JNIEnv *env, jobject obj)
{
return v1;
}
JNIEXPORT jdouble JNICALL Java_KubCardanisch_getVolumen2 (JNIEnv *env, jobject obj)
{
return v2;
}
JNIEXPORT jdouble JNICALL Java_KubCardanisch_getVolumen3 (JNIEnv *env, jobject obj)
{
return v3;
}

Lin728
12-10-2004, 20:45
Dein Beispiel ist wirklich schön objektorientiert, hmm, mal sehen.

Das problem ist ganz klar die objektorientierung, enorm viele neue Objekte und tonnenweise Methodenaufrufe.
Das Problem andererseits ist, dass man dertart mathematische Sachen garnicht oop macht, wenns wirklich um Performance geht.

4 Möglichkeiten:
1.) Als komplexe Zahl einfach ein double[2] verwenden - und wenn möglich immer das übergebene Array wiederverwenden. Auch arrays sind Objecte am Heap die angelegt und freigegeben werden müssen.
Deine Komplexen Klassen definiertst du mit statischen Methoden.

2.) Das wird noch extremer:
Gar keine Heap-Objekte verwenden! Eine Komplexe zahl besetht aus zwei Variablen var1_rea und var1_img.
Statische Methoden wie vorher, du ersparst dir sogar viele methoden, die du einfach händisch ausprogrammieren kannst.

3.) Alles so lassen wie es ist, nur bei addieren etc. KEINE neuen Objecte verwenden, sondern ein Object zu einem anderen Addieren, kein neues zurückgeben (was übrigends eh nicht im Sinne von OOP ist).
Wenn du mit einer berechnung fertig bist, verwende die Komplex-Objekte wieder, setze einfach die Werte neu.
Weg mit den getX() und getY() - Methoden, schön aber wenns hart auf hart geht langsam.

4.) Du definierst eine KLasse Komplex wo wirklich nur long real und long img drinne sind und verwendest diese im Sinne von Strukturen. Eine Klasse KomplexMath oder so rechnet dann mit diesen Komplex-Strukturen.
Komplex-Strukturen IMMER wiedererwenden - JEDES new in einer rechenintensiven Schleife ist eines zu viel!!
Der HotSpot-Server-JIT kann wirklich viel optimieren, aber bei "new" sind ihm die hände gebunden, da muss die JVM einfach ziemlich viel erledigen.

In C wäre das ganze wohl alleine durch die Tatsache einfacher, dass es Stack-Allocierung und Structs gibt und sogar ein wenig objektorientierter ;-)

Am besten du spielst dich noch ein wenig mit den Varianten oben - eventuell findest du die Lösung welche gute Performance bringt und trotzdem wartbar ist.

Lin728
12-10-2004, 20:59
Microbenchmarks sind zwar mit Vorsicht zu genießen, aber bitte:

http://kano.net/javabench/

Blaubär
14-10-2004, 11:37
Hallo,

ich denke ich werde erst einmal den Vorschlag 3) weiterverfolgen und - als Kompromiss zwischen Lesbarkeit und Geschwindigkeit jeweils ein zweite Methode basteln, die kein Objekt zurückgibt. Die werde ich dann hauptsächlich verwenden, außer ich will ein Zwischenergebnis dastehen haben, damit der Code noch lesbar bleibt.

Wenn das zu wenig bringt, dann werde ich mich wohl an Vorschlag 2) machen und das ohne komplexe Zahlen programmieren. Die Lösung einer kubischen Gleichung - soweit ich den Bronstein richtig verstanden habe - geht auch im Reelen, aber dann mit Fallunterscheidungen.

Vielen Dank noch mal für die Hilfe und die Diskussion an alle

Blaubär