Jump to content

[Java] Kleine Optimimierung Device.getResponseExpected()


Recommended Posts

Hallo Admins,

 

ich habe bei mir zwei Methoden der Device-Klasse wie folgt umgestellt:

public boolean getResponseExpected(byte functionId) {
    // IPConnection.unsignedByte creates values from 0..255 only
    byte value = responseExpected[iPConnection.unsignedByte(functionId)];
    if(value != RESPONSE_EXPECTED_FLAG_INVALID_FUNCTION_ID) {
        return value == RESPONSE_EXPECTED_FLAG_ALWAYS_TRUE || value == RESPONSE_EXPECTED_FLAG_TRUE;
    }

    throw new IllegalArgumentException("Invalid function ID " + functionId);
}

public void setResponseExpected(byte functionId, boolean responseExpected) {
    // IPConnection.unsignedByte creates values from 0..255 only
    int index = IPConnection.unsignedByte(functionId);
    byte value = this.responseExpected[index];
    if(value == RESPONSE_EXPECTED_FLAG_INVALID_FUNCTION_ID) {
throw new IllegalArgumentException("Invalid function ID " + functionId);
    }
    if(value == RESPONSE_EXPECTED_FLAG_ALWAYS_TRUE || value == RESPONSE_EXPECTED_FLAG_ALWAYS_FALSE) {
throw new IllegalArgumentException("Response Expected flag cannot be changed for function ID " + functionId);
    }

    if(responseExpected) {
this.responseExpected[index] = RESPONSE_EXPECTED_FLAG_TRUE;
    } else {
this.responseExpected[index] = RESPONSE_EXPECTED_FLAG_FALSE;
    }
}

 

Hintergrund:

  • IPConnection.unsignedByte() liefert korrekt nur 0..255 zurück (kein Range-Check notwendig)
  • der Range-Check in Java erfolgte auf Basis der functionId und nicht anhand des berechneten Index und nachdem schon einmal ins Array zugegriffen wurde => bringt leider eh nichts
  • IPConnection.unsignedByte() ist ein echter Funktionsaufruf, darum speichere ich den Wert zwischen, damit die Funktion nicht zu oft aufgerufen wird. Gerade bei der Ansteuerung von Servos erfolgt viel Kommunikation und die Funktion getResponseExpected wird zig-tausendfach aufgerufen.

 

In Summe bringt das ein paar % bei den Servoaufrufen. Auf CPU-schwächeren Systemen kann das hilfreich sein.

 

Vielleicht übernehmt Ihr die Anpassung ins API.

Link zu diesem Kommentar
Share on other sites

Du konntest dadurch messbare Geschwindigkeitsverbesserungen erzielen?

 

Ich finde deinen Code besser lesbar (habe den getter mit dem Original verglichen), insofern würde ich in jedem Fall dazu raten deine Änderung zu übernehmen. Allerdings kann ich mir nicht vorstellen, dass in einem IO-lastigen System wie TF solche Mikro-Optimierungen messbar helfen. Oder übersehe ich hier etwas?

 

Immerhin ist doch bei "viel" Servo Kommunikation insbesondere viel IO enthalten oder? Wenn ich bedenke, dass die Taktrate der Nachrichten zum Brick bei 1000 Hz liegt (1 ms), dann kann ich mir nicht vorstellen wie eine Optimierung im µs (oder gar ns?) Bereich Verbesserungen bringen kann.

Link zu diesem Kommentar
Share on other sites

Wie viele Aufrufe sind das jeweils insgesamt? (ich gehe davon aus, dass du sie in einer Schleife mehrfach gerufen hast)

 

Was ich meine:

Der bloße Aufruf der Funktion getResponseExpected() ist jetzt 15% schneller (weniger CPU-Zeit), insgesamt sind aber die ganzen TF-Funktionen eher IO-Bound und nicht CPU-Bound, das bedeutet, dass du zwar einige Takte auf der CPU sparst, aber die Kommunikation noch immer eine Millisekunde dauert. Ich überschlage das mal sehr grob:

vorher: 1 ms + 1 µs = 1001 µs
nachher: 1 ms + 0 µs = 1000 µs
------------------------------
Ersparnis: 1 µs (= 0.1%)

 

edit: Ich will übrigens gar nicht meckern, ich finde es gut, wenn sich viele Leute den Code anschauen und verbessern. Ist also nicht böse gemeint. Ich befürchte aber, dass es verschenkte Mühe ist, wenn deine Motivation darin besteht die Performance zu verbessern.

Link zu diesem Kommentar
Share on other sites

Das mit der Gesamt-Zeit ist völlig korrekt: das spart nur 0.x% der Gesamtzeit ein. Ich hatte 100.000 Aurufe.

 

edit: reale Performance-Verbesserung bringt das nicht - stimme ich zu.

 

Bei Tablets gilt aber: CPU-Verbrauch kostet Akku. Darum suche ich gerade nach Optimierungen. Der Garbage-Collektor hat bei mir auch viel zu tun, wegen den Byte-Buffern ...

 

edit: der Garbage-Collector bringt kleine Aussetzer rein und läuft bei mir schon alle 10 Sekunden.

 

Noch eine Anmerkung zur IO bei Servos:

Requests mit Response brauchen per WLAN bei mir ca. 5-6ms.

Servo-Requests ohne Response liegen aber weit unter 1ms, auch per WLAN (so meine Messung).

 

Real sende ich gut 100-120 Requests pro Sekunde, wenn ich mit je einem Finger in einem Kreuzfeld jeweils 2 Servos bewege (in Summe also 4 Servos quasi gleichzeitig).

Link zu diesem Kommentar
Share on other sites

Das mit dem GC ist ja echt bedenklich ^^

 

Müsste man glatt mal schauen, ob die Bindings in dieser Hinsicht auch sparsam mit den Ressourcen des Geräts umgehen.

Habe bisher nicht so sehr auf das Speicherverhalten geachtet (und wenn überhaupt nur die C#-Bindings reviewt), aber ich glaube das wäre nochmal einen Blick wert ^^

Link zu diesem Kommentar
Share on other sites

  • 2 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...