2017-01-13 3 views
1

Ich schreibe einen Code, der selten Objekte erstellt/entfernt (bis zu mehreren tausend), aber sehr häufig modifiziert sie im weichen IRQ-Kontext. Diese Objekte werden auch selten aus dem Aufgabenkontext gelesen (und wahrscheinlich auch nur selten geändert) (über procfs: Datei pro Objekt). Derzeit enthält mein Code globale pro-CPU-Datenblöcke, die jeweils von einem Spinlock geschützt werden. Ein solcher Block enthält eine Hash-Tabelle fester Größe für den Objektspeicher.Gibt es einen Linux-Header für Hashtable mit Spinlock-geschützten Buckets?

Offensichtlich ist das aktuelle Design nicht optimal, besonders bei sehr hohen Objektaktualisierungslasten: Das Lesen von Objekten aus procfs führt zu Datenverlusten bei der Aktualisierung von Soft IRQs. Ich muss das Synchronisationsschema neu schreiben, um globale Sperren loszuwerden. Die naheliegendste Wahl - einen Spinlock für jeden Hashtable-Bucket zu haben - sollte gut skalieren. Das Problem ist, dass ich wahrscheinlich meine eigene Hashtable-Implementierung verwenden muss oder zumindest mehrere Makros der obersten Ebene neu implementieren muss (diese wurden in linux/hashtable.h für Spinlock-geschützte Buckets nicht gefunden). Sollte ich auch auf eine RCU-fähige Hashtabelle schauen (ich habe jedoch noch kein solides Verständnis dieses Synchronisierungsansatzes)?

Antwort

3

Eimer mit Schlossschutz sind in der Kopfzeile linux/list_bl.h deklariert. Sie verwenden das niedrigste Bit des Kopfzeigers als Verriegelungsbit.

RCU-geschützten Zugriff auf den Eimer im Header mit anderen Hashtabelle Funktionen definiert linux/hashtable.h (sie haben _rcu Suffix).

Die Auswahl zwischen Schlössern und RCU liegt bei Ihnen. Beachten Sie, dass die RCU selbst nicht auflösen kann. Ändern Sie - Ändern Sie Konflikte. Und es hilft meistens für häufig gelesene Daten, die nicht Ihr Fall ist.


Da nur eine Sperrfunktion - hlist_bl_lock - für struct hlist_bl_head erklärt, und diese Funktion ist nicht bewusst für IRQs, sollten zusätzliche Aktionen ausgeführt werden, wenn Hash-Tabelle kann in irq oder unteren Hälften verwendet werden:

  • spin_lock_irqsave:

    local_irq_save(flags); 
    hlist_bl_lock(...); 
    
  • spin_unlock_irqrestore:

    hlist_bl_unlock(...); 
    local_irq_restore(flags); 
    
  • spin_lock_bh:

    local_bh_disable(); 
    hlist_bl_lock(...); 
    
  • spin_unlock_bh:

    hlist_bl_unlock(...); 
    local_bh_enable(); 
    
+0

Wie signifikante Leistungsverschlechterung ist, wenn Bit spinlocks mit den normal denjenigen zu vergleichen? Vielleicht sollte ich normale Spinlocks bevorzugen, da ich nicht zu viele Eimer brauche? – ababo

+0

Soweit ich verstehe, würden Sie die Leistung nicht verschlechtern. Im Gegensatz dazu können Sie die Leistung verbessern, da der Cache-Footprint * bei Access-Buckets reduziert ist. Die Verwendung eines einzelnen Bits für die Sperre würde einige * Sperr-Debugging-Funktionen * verlieren. Zumindest wäre * lock map * über Ihre Sperren nicht bewusst: Es benötigt zusätzliche Bytes im Sperrobjekt. Aber solange Sie das Sperren korrekt implementieren, sollte das Debuggen Ihrer Sperren Sie nicht stören. ** Als Zusammenfassung **: Bis Sie Locks auf sehr ungewöhnliche Weise verwenden, sind Bit Locks sowohl für die Performance als auch für die Lesbarkeit von Code eine gute Wahl. – Tsyvarev

+0

Ich hoffe, es ist sicher Bit Locks für den Austausch von Daten zwischen Soft-IRQs und Kernel-Threads zu verwenden (da es kein 'bit_spin_lock_bh' gibt)? – ababo