28 Permanenter Speicher #
Dieses Kapitel enthält weitere Informationen zur Verwendung von SUSE Linux Enterprise mit nicht-flüchtigem Hauptspeicher, auch als permanenter Speicher bekannt, der aus einem oder mehreren NVDIMMs besteht.
28.1 Einführung #
Ein permanenter Speicher ist eine neue Art von Speicherung am Rechner. Er kombiniert annähernd so hohe Geschwindigkeiten wie bei dynamischen RAMs (DRAMs) mit der Byte-für-Byte-Adressierbarkeit des RAM und der Permanenz von Solid-State Disks (SSDs).
SUSE unterstützt aktuell die Verwendung eines permanenten Speichers mit SUSE Linux Enterprise Server auf Rechnern mit AMD64/Intel 64- und POWER-Architekturen.
Wie bei herkömmlichen RAMs wird der permanente Speicher direkt am Speichersteckplatz der Hauptplatine installiert. Damit wird er im selben physischen Formfaktor bereitgestellt wie RAM – als DIMMs. Man nennt sie NVDIMMs: Non-Volatile Dual Inline Memory Modules.
Im Unterschied zu RAM ist ein permanenter Speicher in vielerlei Hinsicht Flash-basierten SSDs ähnlich. Beide basieren auf unterschiedliche Weise auf dem Stromkreis von Festkörperspeichern, bieten aber unabhängig davon einen nicht-flüchtigen Speicher. Dies bedeutet, dass ihre Inhalte beibehalten werden, wenn das System heruntergefahren oder neu gestartet wird. Bei beiden Varianten geht das Schreiben von Daten langsamer von statten als das Lesen und beide unterstützen eine begrenzte Anzahl von Neuschreibungszyklen. Wie bei SSDs ist der Zugriff auf Sektorebene des permanenten Speichers möglich, sollte dies für eine bestimmte Anwendung erforderlich sein.
Die unterschiedlichen Modelle verwenden verschiedene Arten von elektronischen Speichermedien, wie Intel 3D XPoint oder eine Kombination aus NAND-Flash und DRAM. Neue Arten von nicht-flüchtigen RAMs werden derzeit entwickelt. Verschiedene Anbieter und Modelle von NVDIMMs bieten unterschiedliche Eigenschaften für Leistung und Langlebigkeit.
Da sich die entsprechenden Speichertechnologien noch in der frühen Entwicklungsphase befinden, ist bei der Hardware verschiedener Anbieter möglicherweise mit unterschiedlichen Einschränkungen zu rechnen. Daher sind die folgenden Aussagen als Verallgemeinerungen zu betrachten.
Ein permanenter Speicher ist bis zu zehn mal langsamer als DRAM, doch in etwa tausend mal schneller als Flash-Speicher. Im Gegensatz zum Vorgang des Auslöschens und Neuschreibens des gesamten Sektors beim Flash-Speicher kann der permanente Speicher auf Byte-zu-Byte-Basis neu geschrieben werden. Da die Neuschreibungszyklen begrenzt sind, können permanente Speicher schließlich Millionen von Neuschreibungen verarbeiten, verglichen mit Tausenden von Zyklen des Flash-Speichers.
Das hat zwei erhebliche Folgen:
Beim aktuellen Stand der Technik ist es nicht möglich, ein System nur mit permanentem Speicher auszuführen und dadurch einen gänzlich nicht-flüchtigen Hauptspeicher zu erzielen. Sie müssen einen herkömmlichen RAM mit NVDIMMs kombinieren. Das Betriebssystem und die Anwendungen werden am herkömmlichen RAM ausgeführt und NVDIMMs bieten eine sehr schnelle ergänzende Speichermöglichkeit.
Aufgrund der Leistungsmerkmale der permanenten Speicher von verschiedenen Anbietern müssen Programmierer möglicherweise die Hardwarespezifikationen der NVDIMMs an einem bestimmten Server berücksichtigen, einschließlich deren Anzahl und belegten Speichersteckplätze. Dies wirkt sich offensichtlich auf die Verwendung des Hypervisors aus sowie auf die Migration von Software zwischen verschiedenen Host-Rechnern usw.
Dieses neue Speicher-Untersystem ist in Version 6 des ACPI-Standards definiert. libnvdimm
unterstützt jedoch NVDIMMs, die den Standard noch nicht erfüllen, wodurch diese auf gleiche Weise verwendet werden können.
28.2 Begriffe #
- Region
Eine Region ist ein Block des permanenten Speichers, der in einen oder mehrere Namespaces unterteilt werden kann. Der Zugriff auf den permanenten Speicher einer Region ist erst nach dessen Zuordnung zu einem Namespace möglich.
- Namespace
Ein einzelner zusammenhängend adressierter Bereich eines nicht-flüchtigen Speichers, vergleichbar mit NVM Express SSD-Namespaces oder SCSI Logical Units (LUNs). Namespaces werden im
/dev
-Verzeichnis des Servers als separate Blockgeräte angezeigt. Abhängig von der erforderlichen Zugriffsmethode können Namespaces entweder Speicherplatz von verschiedenen NVDIMMs in größere Volumes zusammenfassen oder dessen Partitionierung in kleinere Volumes zulassen.- Modus
Jeder Namespace weist auch einen Modus auf, der definiert, welche NVDIMM-Funktionen für diesen Namespace aktiviert sind. Gleichgeordnete Namespaces der selben übergeordneten Region sind im Typ immer gleich, werden jedoch möglicherweise mit verschiedenen Modi konfiguriert. Namespace-Modi:
- devdax
Geräte-DAX-Modus. Erstellt eine Einzelzeichen-Gerätedatei (
/dev/daxX.Y
). Die Erstellung eines Dateisystems ist nicht erforderlich.- fsdax
Dateisystem-DAX-Modus. Standardmodus, falls kein anderer Modus angegeben wird. Erstellt ein Blockgerät (
/dev/pmemX [.Y]
), das DAX fürext4
oderXFS
unterstützt.- sector
Für veraltete Dateisysteme, die keine Checksumme für Metadaten erstellen. Geeignet für kleine Boot-Volumes. Kompatibel mit anderen Betriebssystemen.
- raw
Ein Speicherdatenträger ohne Kennung oder Metadaten. Keine Unterstützung von DAX. Kompatibel mit anderen Betriebssystemen.
NoteDer
raw
-Modus wird von SUSE nicht unterstützt. Es ist nicht möglich, Dateisysteme aufraw
-Namespaces einzuhängen.
- Typ
Jeder Namespace und jede Region weist einen Typ auf, der definiert, auf welche Weise auf den permanenten Speicher, der mit diesem Namespace oder dieser Region verknüpft ist, zugegriffen wird. Ein Namespace hat immer denselben Typ wie dessen übergeordnete Region. Zwei verschiedene Typen stehen zur Verfügung: Permanenter Speicher, der auf zwei verschiedene Arten konfiguriert werden kann, sowie der veraltete Block-Modus.
- Permanenter Speicher (PMEM)
Der PMEM-Speicher bietet Zugriff auf Byte-Ebene, genauso wie RAM. Mit PMEM kann ein einzelner Namespace mehrere überlappende NVDIMMs enthalten und alle können als Einzelgerät verwendet werden.
Ein PMEM-Namespace kann auf zwei Arten konfiguriert werden.
- PMEM mit DAX
Ein für den Direktzugriff (DAX) konfigurierter Namespace bedeutet, dass beim Zugreifen auf den Arbeitsspeicher der Seiten-Cache des Kernels umgangen und direkt auf das Medium zugegriffen wird. Die Software kann jedes Byte des Namespace separat lesen oder schreiben.
- PMEM mit BTT (Block Translation Table)
Wie bei einem herkömmlichen Festplattenlaufwerk wird auf einen für den Betrieb im BTT-Modus konfigurierten PMEM-Namespace Sektor für Sektor zugegriffen, im Unterschied zu dem eher RAM-ähnlichen Byte-adressierbaren Modell. Durch einen Übersetzungstabellen-Mechanismus werden die Zugriffe in Einheiten von Sektorgröße eingeteilt.
Der Vorteil von BTT liegt im Datenschutz: Das Speicher-Untersystem stellt sicher, dass jeder Sektor vollständig auf das zugrundeliegende Medium geschrieben wird und im Fall irgendeines Fehlers beim Schreiben dieser aufgelöst wird. Daher kann ein Sektor nicht teilweise geschrieben werden.
Der Zugriff auf BTT-Namespaces wird zudem vom Kernel im Cache gespeichert.
Der Nachteil ist, dass kein Direktzugriff auf BTT-Namespaces möglich ist.
- Block-Modus (BLK)
Beim Speichern im Block-Modus wird jeder NVDIMM als separates Gerät adressiert. Dieser Modus ist inzwischen veraltet und wird nicht mehr unterstützt.
Abgesehen von
devdax
-Namespaces müssen alle anderen Typen mit einem Dateisystem formatiert werden, genau wie bei einem herkömmlichen Laufwerk. SUSE Linux Enterprise Server unterstützt dafür die Dateisystemeext2
,ext4
undXFS
.- Direktzugriff (Direct Access, DAX)
Durch DAX kann ein permanenter Speicher direkt im Adressbereich eines Prozesses zugeordnet werden, beispielsweise über den Systemaufruf
mmap
.- Physikalische DIMM-Adresse (DPA)
Eine Speicheradresse als Offset in den Speicher eines einzelnen DIMMs, das heißt beginnend bei Null als niedrigstem adressierbaren Byte in diesem DIMM.
- Kennung
Im NVDIMM gespeicherte Metadaten wie beispielsweise Namespace-Definitionen. Der Zugriff ist über DSM möglich.
- Gerätespezifische Methode (Device-specific method, DSM)
ACPI-Methode für den Zugriff auf die Firmware eines NVDIMM.
28.3 Anwendungsfälle #
28.3.1 PMEM mit DAX #
Es ist wichtig zu wissen, dass diese Art von Speicherzugriff keine Transaktion ist. Im Fall eines Stromausfalls oder eines anderen Systemfehlers werden die Daten möglicherweise nicht vollständig in den Speicher geschrieben. Ein PMEM-Speicher ist nur für Anwendungen geeignet, die teilweise geschriebene Daten verarbeiten können.
28.3.1.1 Anwendungen, die von einem großen Byte-adressierbaren Speicher profitieren #
Wenn am Server eine Anwendung gehostet wird, die direkt einen großen Teil eines schnellen Speichers Byte für Byte verwendet, kann der Programmierer mit dem Systemaufruf mmap
Blöcke des permanenten Speichers direkt in den Adressbereich der Anwendung stellen, ohne auf zusätzlichen System-RAM zurückgreifen zu müssen.
28.3.1.2 Vermeiden des Kernel-Seiten-Cache #
Vermeiden Sie den Kernel-Seiten-Cache, wenn Sie den RAM für den Seiten-Cache aufsparen und ihn stattdessen anderen Anwendungen zuweisen möchten. Dieser könnte beispielsweise zum Speichern von VM-Images vorgesehen werden. Diese Images würden nicht in den Cache gestellt werden, was die Cache-Auslastung am Host reduzieren und mehr VMs pro Host zulassen würde.
28.3.2 PMEM mit BTT #
Diese Variante ist nützlich, wenn Sie den permanenten Speicher auf einigen NVDIMMs als einen Datenträger-ähnlichen Pool von sehr schnellen Speichern verwenden möchten. Wird beispielsweise das Dateisystemjournal auf PMEM mit BTT platziert, erhöht sich dadurch die Zuverlässigkeit der Dateisystemwiederherstellung nach Stromausfall oder sonstiger plötzlicher Unterbrechung (siehe Section 28.5.3, “Erstellen eines PMEM-Namespace mit BTT”).
Anwendungen halten diese Geräte für sehr schnelle SSDs, die wie jedes andere Speichergerät verwendet werden. LVM kann beispielsweise auf den permanenten Speicher aufgesetzt werden und funktioniert normal.
BTT hat den Vorteil, dass die Unteilbarkeit beim Schreiben in den Sektor gewährleistet ist. Somit bleiben sogar sehr anspruchsvolle und von Datenintegrität abhängige Anwendungen funktionsfähig. Die Erstellung von Fehlerberichten funktioniert über standardmäßige Kanäle zur Fehlerberichterstellung.
28.4 Tools zur Verwaltung von permanenten Speichern #
Zur Verwaltung eines permanenten Speichers muss das Paket ndctl
installiert werden. Dadurch wird auch das Paket libndctl
installiert. Es enthält einige Benutzerbereich-Bibliotheken zum Konfigurieren von NVDIMMs.
Diese Tools arbeiten mit der Bibliothek libnvdimm
, die drei Typen von NVDIMM unterstützt:
PMEM
BLK
PMEM und BLK gleichzeitig
Das ndctl
-Dienstprogramm enthält einige nützliche man
-Seiten, auf die mit dem folgenden Kommando zugegriffen wird:
tux >
ndctl help subcommand
Eine Liste der verfügbaren Unterkommandos erhalten Sie mit:
tux >
ndctl --list-cmds
Folgende Unterkommandos stehen zur Verfügung:
- version
Zeigt die aktuelle Version der NVDIMM-Unterstützungstools an.
- enable-namespace
Stellt den angegebenen Namespace zur Verfügung.
- disable-namespace
Verhindert die Verwendung des angegebenen Namespace.
- create-namespace
Erstellt einen neuen Namespace aus den angegebenen Speichergeräten.
- destroy-namespace
Entfernt den angegebenen Namespace.
- enable-region
Stellt die angegebene Region zur Verfügung.
- disable-region
Verhindert die Verwendung der angegebenen Region.
- zero-labels
Löscht die Metadaten von einem Gerät.
- read-labels
Ruft die Metadaten vom angegebenen Gerät ab.
- list
Zeigt verfügbare Geräte an.
- help
Zeigt Informationen zur Verwendung des Tools an.
28.5 Einrichten eines permanenten Speichers #
28.5.1 Anzeigen des verfügbaren NVDIMM-Speichers #
Mit dem Kommando ndctl
list
werden alle verfügbaren NVDIMMs in einem System aufgelistet.
Im folgenden Beispiel hat das System drei NVDIMMs, die sich in einem einzelnen, dreikanaligen überlappenden Set befinden.
root #
ndctl list --dimms
[ { "dev":"nmem2", "id":"8089-00-0000-12325476" }, { "dev":"nmem1", "id":"8089-00-0000-11325476" }, { "dev":"nmem0", "id":"8089-00-0000-10325476" } ]
Mit einem anderen Parameter listet ndctl
list
auch die verfügbaren Regionen auf.
Regionen erscheinen möglicherweise nicht in numerischer Reihenfolge.
Beachten Sie, dass zwar nur drei NVDIMMs vorhanden sind, doch vier Regionen angezeigt werden.
root #
ndctl list --regions
[ { "dev":"region1", "size":68182605824, "available_size":68182605824, "type":"blk" }, { "dev":"region3", "size":202937204736, "available_size":202937204736, "type":"pmem", "iset_id":5903239628671731251 }, { "dev":"region0", "size":68182605824, "available_size":68182605824, "type":"blk" }, { "dev":"region2", "size":68182605824, "available_size":68182605824, "type":"blk" } ]
Der Speicherplatz ist auf zwei verschiedene Arten verfügbar: entweder als drei separate 64 GB-Regionen vom Typ BLK oder als eine kombinierte 189 GB-Region vom Typ PMEM, die den gesamten Speicherplatz auf den drei überlappenden NVDIMMs als ein einziges Volume darstellt.
Beachten Sie, dass der angezeigte Wert für available_size
identisch ist mit dem Wert für size
. Dies bedeutet, dass noch kein Speicherplatz zugeordnet wurde.
28.5.2 Konfigurieren des Speichers als einzelnen PMEM-Namespace mit DAX #
Im ersten Beispiel konfigurieren wir unsere drei NVDIMMs in einem einzelnen PMEM-Namespace mit Direktzugriff (DAX).
Im ersten Schritt erstellen wir einen neuen Namespace.
root #
ndctl create-namespace --type=pmem --mode=fsdax --map=memory
{ "dev":"namespace3.0", "mode":"memory", "size":199764213760, "uuid":"dc8ebb84-c564-4248-9e8d-e18543c39b69", "blockdev":"pmem3" }
Dadurch wird ein Blockgerät /dev/pmem3
erstellt, das DAX unterstützt. Die 3
im Gerätenamen wird von der Nummer der übergeordneten Region übernommen, in diesem Fall region3
.
Die Option --map=memory
reserviert einen Teil des PMEM-Speicherplatzes auf den NVDIMMs für die Zuordnung interner Kernel-Datenstrukturen namens struct pages
. Dadurch kann der neue PMEM-Namespace mit Funktionen wie O_DIRECT I/O
und RDMA
verwendet werden.
Aufgrund der Reservierung eines Teils des permanenten Speichers für Kernel-Datenstrukturen hat der resultierende PMEM-Namespace eine geringere Kapazität als die übergeordnete PMEM-Region.
Als nächstes überprüfen wir, ob das neue Blockgerät für das Betriebssystem verfügbar ist:
root #
fdisk -l /dev/pmem3
Disk /dev/pmem3: 186 GiB, 199764213760 bytes, 390164480 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Bevor es verwendet werden kann, muss es wie jedes andere Gerät formatiert werden. In diesem Beispiel formatieren wir es mit XFS:
root #
mkfs.xfs /dev/pmem3
meta-data=/dev/pmem3 isize=256 agcount=4, agsize=12192640 blks = sectsz=4096 attr=2, projid32bit=1 = crc=0 finobt=0, sparse=0 data = bsize=4096 blocks=48770560, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal log bsize=4096 blocks=23813, version=2 = sectsz=4096 sunit=1 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0
Danach können wir das neue Laufwerk in ein Verzeichnis einhängen:
root #
mount -o dax /dev/pmem3 /mnt/pmem3
Dann überprüfen wir, ob wir nun über ein DAX-fähiges Gerät verfügen:
root #
mount | grep dax
/dev/pmem3 on /mnt/pmem3 type xfs (rw,relatime,attr2,dax,inode64,noquota)
Das Ergebnis ist ein PMEM-Namespace, der mit dem XFS-Dateisystem formatiert und mit DAX eingehängt ist.
mmap()
-Aufrufe von Dateien in diesem Dateisystem geben virtuelle Adressen zurück, die direkt dem permanenten Speicher auf unseren NVDIMMs zugeordnet werden. Der Seiten-Cache wird dabei voll umgangen.
fsync
- oder msync
-Aufrufe von Dateien in diesem Dateisystem stellen weiterhin sicher, dass geänderte Daten vollständig in die NVDIMMs geschrieben werden. Diese Aufrufe löschen die Zeilen des Prozessor-Cache, die mit Seiten verknüpft sind, die im Benutzerbereich über mmap
-Zuordnungen geändert wurden.
28.5.2.1 Entfernen eines Namespace #
Bevor wir einen anderen Volume-Typ erstellen, der den selben Speicher verwendet, müssen wir das PMEM-Volume aushängen und dann entfernen.
Hängen Sie es zunächst aus:
root #
umount /mnt/pmem3
Deaktivieren Sie dann den Namespace:
root #
ndctl disable-namespace namespace3.0
disabled 1 namespace
Löschen Sie es nun:
root #
ndctl destroy-namespace namespace3.0
destroyed 1 namespace
28.5.3 Erstellen eines PMEM-Namespace mit BTT #
BTT sorgt für Unteilbarkeit beim Schreiben in den Sektor, was es zu einer guten Wahl macht, wenn Datenschutz erforderlich ist, zum Beispiel für Ext4- und XFS-Journale. Bei Stromausfall sind die Journale geschützt und sollten wiederherstellbar sein. Die folgenden Beispiele zeigen, wie ein PMEM-Namespace mit BTT im Sektormodus erstellt und wie das Dateisystemjournal in diesem Namespace platziert wird.
root #
ndctl create-namespace --type=pmem --mode=sector
{ "dev":"namespace3.0", "mode":"sector", "uuid":"51ab652d-7f20-44ea-b51d-5670454f8b9b", "sector_size":4096, "blockdev":"pmem3s" }
Überprüfen Sie als nächstes, ob das Gerät vorhanden ist:
root #
fdisk -l /dev/pmem3s
Disk /dev/pmem3s: 188.8 GiB, 202738135040 bytes, 49496615 sectors Units: sectors of 1 * 4096 = 4096 bytes Sector size (logical/physical): 4096 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Wie der vorher konfigurierte DAX-fähige PMEM-Namespace verbraucht dieser BTT-fähige Namespace den gesamten verfügbaren Speicherplatz auf den NVDIMMs.
Das angehängte s
am Ende des Gerätenamens (/dev/pmem3s
) steht für sector
. Damit lassen sich Namespaces, die zur Verwendung von BTT konfiguriert wurden, leicht unterscheiden.
Das Volume wird wie im vorigen Beispiel formatiert und eingehängt.
Der hier gezeigte PMEM-Namespace kann DAX nicht verwenden. Stattdessen verwendet er BTT für die Unteilbarkeit beim Schreiben des Sektors. Bei jedem Schreiben des Sektors über den PMEM-Blocktreiber ordnet BTT einen neuen Sektor zu, um neue Daten zu empfangen. BTT aktualisiert ungeteilt die internen Zuordnungsstrukturen, nachdem alle neuen Daten vollständig geschrieben sind, sodass die neu geschriebenen Daten den Anwendungen zur Verfügung stehen. Wenn zu irgendeinem Zeitpunkt dieses Vorgangs der Strom ausfällt, sind alle geschriebenen Daten verloren und die Anwendung hat Zugriff auf die alten Daten, die noch intakt sind. Dadurch wird der Zustand der sogenannten „zerrissenen Sektoren“ verhindert.
Dieser BTT-fähige PMEM-Namespace wird wie ein Dateisystem formatiert und verwendet, genau wie jedes andere Standard-Blockgerät. Die Verwendung mit DAX ist nicht möglich. mmap
-Zuordnungen für Dateien auf diesem Blockgerät verwenden jedoch den Seiten-Cache.
28.5.4 Platzieren des Dateisystemjournals in PMEM/BTT #
Wird das Dateisystemjournal auf einem separaten Gerät platziert, muss es dieselbe Dateisystem-Blockgröße wie das Dateisystem verwenden. Sie beträgt höchstwahrscheinlich 4096 und Sie finden die Blockgröße mit diesem Kommando:
root #
blockdev --getbsz /dev/sda3
Im folgenden Beispiel wird ein neues Ext4-Journal auf einem separaten NVDIMM-Gerät erstellt und das Dateisystem auf einem SATA-Gerät. Dann wird das neue Dateisystem an das Journal angehängt:
root #
mke2fs -b 4096 -O journal_dev /dev/pmem3s
root #
mkfs.ext4 -J device=/dev/pmem3s /dev/sda3
Im folgenden Beispiel wird ein neues XFS-Dateisystem auf einem SATA-Laufwerk erstellt und das Journal auf einem separaten NVDIMM-Gerät:
root #
mkfs.xfs -l logdev=/dev/pmem3s /dev/sda3
Detaillierte Informationen zu den Optionen finden Sie in man 8 mkfs.ext4
und man 8 mkfs.ext4
.
28.6 Weiterführende Informationen #
Für weitere Informationen zu diesem Thema siehe die folgende Liste:
Enthält Anweisungen zum Konfigurieren von NVDIMM-Systemen, Informationen zu Tests sowie Links zu Spezifikationen für die Aktivierung von NVDIMMs. Diese Site wird im Zuge der NVDIMM-Unterstützung in Linux entwickelt.
Permanenter Speicher – Programmierung
Informationen zum Konfigurieren, Verwenden und Programmieren von Systemen mit nicht-flüchtigem Speicher unter Linux und anderen Betriebssystemen. Behandelt die NVM-Bibliothek (NVML), die nützliche APIs zum Programmieren mit permanentem Speicher im Benutzerbereich bereitstellt.
LIBNVDIMM: Nicht-flüchtige Geräte
Für Kernel-Entwickler gedacht und Teil des Dokumentationsordners im aktuellen Linux-Kernel-Baum. Es beschreibt die verschiedenen Kernel-Module, die an der NVDIMM-Aktivierung beteiligt sind, gibt einige technische Details zur Kernel-Implementierung und erläutert die
sysfs
-Schnittstelle zum Kernel, die vomndctl
-Tool verwendet wird.Dienstprogramm-Bibliothek zur Verwaltung des
libnvdimm
-Untersystems im Linux-Kernel. Enthält zudem Benutzerbereich-Bibliotheken sowie Einheitentests und eine Dokumentation.