Jump to content
View in the app

A better way to browse. Learn more.

Tinkerunity

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

[Java] Kleine Optimimierung Device.getResponseExpected()

Featured Replies

Geschrieben

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.

Geschrieben

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.

Geschrieben
  • Autor

Ein kleiner Test mit Aufrufen von getResponseExpected() in alter und neuer Variante hat bei mir

OLD: 26163us
NEW: 21645us

 

ausgegeben, also gut 15%.

Geschrieben

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.

Geschrieben
  • Autor

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).

Geschrieben

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 ^^

  • 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...

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.