OpenMP Jobs unter Linux auf eine bestimmte Anzahl von Prozessor-Cores/Threads begrenzen

Manchmal stößt man als Linux-Nutzer auf etwas exotische Themenstellungen. Über eine solche bin ich neulich bei der Vorbereitung eines beauftragten Pentest gestolpert. Für Vor-Ort-Tests schleppt man dann seine Laptops zum Kunden und möchte natürlich vorab wissen, wo die physikalischen Grenzen für die Durchführung des einen oder anderen Test liegen – und für welche Aufgaben man im Nachhinein auf Spezialsysteme zurückgreifen muss.

Viele Programme, die parallele Aufgaben- und Lastverteilung über mehrere Prozessorkerne hinweg unterstützen sollen, nutzen dafür die OpenMP API und lassen sich so gezielt für Multithreading kompilieren.

Siehe hierzu :
https://en.wikipedia.org/wiki/OpenMP
http://www.linux-mag.com/id/4609/

Ein klassisches Beispiel ist das Programm JtR zur Hashanalyse (um es mal freundlich auszudrücken). Dieses Tool ist auf eine hohe Performance des Systems angewiesen, auf der es läuft. Kann man plattformbedingt nicht die GPU für die kontinuierlich durchzuführenden Kryptierungsaufgaben einsetzen, so nutzt man zumindest die für OpenMP kompilierte Variante und mehrere CPU-Threads, um JtR schneller seine Arbeit erledigen zu lassen.

Das hat je nach Verschlüsselungstiefe der zu untersuchenden Hashes gilt natürlich seine Grenzen … Aus Sicht des Security-Beraters gilt aber: Erfolgreiche Hash-Dekodierungen vor Ort helfen enorm, zusammen mit dem Kundenbeauftragten für Sicherheit die Awareness der Angestellten für die Wahl hinreichend guter Passwörter zu schärfen – im Besonderen wenn das Haus-und Hof-Betriebsysteme zur Hasherzeugung nur begrenzte oder eben schnell ausführbare Kryptoalgorithmen verwenden.

Siehe für eine Diskussion der Hash-Algorithmen unter MS Windows etwa
http://security.stackexchange.com/questions/17672/windows-7-password-hash-security
und die dort vorhandenen Kommentare.

Wie bei multi-thread-basierten Programmen generell kann eine maximale Performance bei der Programmausführung ggf. auch Nachteile nach sich ziehen. Wer etwa mal größere PHP-Projekte unter Eclipse Juno bereinigen lassen musste, kann ein Lied davon singen – da gingen auch Workstations mit 16 CPU Threads für einige Zeit in die Knie – wenn hunderte Klassenbibliotheken parallel und auf allen CPU-Cores validiert und indiziert wurden. Ein paralleles Arbeiten etwa mit Libreoffice-Anwendungen wurde dann im fraglichen Zeitraum zur Qual. (Mit Eclipse Mars wurde die Politik der maximalen CPU-Nutzung Gott sei Dank geändert.)

Muss man nun – wie in meinem Fall im Rahmen eines Penetrationstests –

  • vor Ort beim Auftraggeber mit Systemen begrenzter Leistungsfähigkeit arbeiten,
  • eine von Haus aus ressourcenbelastende Virtualisierungsumgebung einsetzen
  • und kann man bestimmte Aufgaben nicht an Remote-Spezialsysteme deligieren,

so wird ein Übermaß an Ressourcenbereitstellung für die Performance eines Programmes wie JtR ggf. zum Verhängnis für andere parallel abzuwickelnde Aufgaben.

JtR in der OpenMP-Variante für Kali z.B. nutzt ohne weitere Parameter automatisch die maximale (!) Anzahl der zur Verfügung stehenden CPUs, die dann auch zu 100% ausgelastet werden. Das gleichzeitige Auslasten vieler Prozessor-Kerne kann schnell zum Engpass für weitere ressourcenintensive Aufgaben werden, die man gleichzeitig und u.U. auf weiteren Virtualisierung-Gastsystemen erledigen will oder muss.

Dies führte mich zur Frage: Wie steuert man eigentlich den Thread-Zugriff eines OpenMP-Programs unter Linux – genauer: Wie legt man die Anzahl der CPU-Threads fest, die das Programm nutzen soll?

Es gibt zwei sehr einfache Antworten:

Steuerung über die
Virtualisierungsumgebung:

Läuft das OpenMP-Programm auf einer virtuellen Maschine (KVM, VMware, Libcontainber, ..) so kann man natürlich die bereitgestellten CPU-Threads über die Grund-Einstellungen zum virtualisierten Gastsystem steuern.

Steuerung über die Shell (u.U. in der virtualisierten Umgebung):
Hier muss man einfach eine Umgebungsvariable für den zu startenden Prozess setzen und exportieren:

mytux:~# export OMP_NUM_THREADS=n

“n” steht für Anzahl der zu nutzenden Threads. Danach startet man den OpenMP-nutzenden Job.

Man muss es – wie so oft – halt nur wissen!

Will man gezielt alle verfügbaren Core für ein OpenMP-Programm einsetzen, so hilft:

export OMP_NUM_THREADS=`grep ‘processor’ /proc/cpuinfo | wc -l `

Viel Spaß bei der gezielten Ressourcenauslastung durch OpenMP-Programme – ob als beauftragter Pentester (natürlich immer [!] mit der expliziten schriftlichen Erlaubnis des Auftraggebers) oder aber auch bei der Entwicklung und dem Einsatz eigener Hochperformance-Programme unter C oder Fortran!

systemd Logging Protokolle – journalctl – Abfrage nach Services und Kommandos mit Autocompletion-Hilfe für Vergessliche

Als alter “syslog-ng” Nutzer tue ich mir immer wieder hart mit der Protokollierung durch “systemd”. Der Schlüssel-Befehl “journactl” ist mir natürlich präsent – aber welche Opionen muss ich dann wählen, um die Unzahl von Journal-Einträge nach solchen zu ganz bestimmten Services oder Kommandos zu filtern?

Den entscheidenden Tip für Dummies wie mich habe ich hier gefunden:
http://blog.delouw.ch/2013/07/24/why-journalctl-is-cool-and-syslog-will-survive-for-another-decade/
(Vielen Dank für den hilfreichen Blog-Artikel).

journactl hat eine Autocompletion-Funktionalität über die Tab-Taste:

Generelle Filter-Optionen erreicht man über

journalctl <TAB>[<TAB>]

Ggf. muss man die TAB-Taste 2-mal drücken.

mytux:~ # journalctl 
CODE_FILE=                   _KERNEL_DEVICE=
CODE_FUNC=                   _KERNEL_SUBSYSTEM=
CODE_LINE=                   _MACHINE_ID=
COREDUMP_EXE=                _PID=
ERRNO=                       _SELINUX_CONTEXT=
MESSAGE=                     _SOURCE_REALTIME_TIMESTAMP=
MESSAGE_ID=                  _SYSTEMD_CGROUP=
PRIORITY=                    _SYSTEMD_OWNER_UID=
SYSLOG_FACILITY=             _SYSTEMD_SESSION=
SYSLOG_IDENTIFIER=           _SYSTEMD_UNIT=
SYSLOG_PID=                  _TRANSPORT=
_AUDIT_LOGINUID=             _UDEV_DEVLINK=
_AUDIT_SESSION=              _UDEV_DEVNODE=
_BOOT_ID=                    _UDEV_SYSNAME=
_CMDLINE=                    _UID=
_COMM=                       __CURSOR=
_EXE=                        __MONOTONIC_TIMESTAMP=
_GID=                        __REALTIME_TIMESTAMP=
_HOSTNAME=                   

 
Das ist doch schon sehr hilfreich. Da die meisten System-Services direkt zu irgendwelchen “systemd UNITs” korrespondieren, kommt man hier schon ein gutes Stück weiter. Beispiel:

mytux:~ # journalctl _SYSTEMD_UNIT=sshd.service 
-- Logs begin at Fri 2014-12-19 17:40:02 CET, end at Sun 2015-09-27 19:02:35 CEST. --
......
-- Reboot --
Jan 24 10:49:37 mytux sshd-gen-keys-start[5942]: Checking for missing server keys in /etc/ssh
Jan 24 10:49:37 mytux sshd[5947]: Server listening on 0.0.0.0 port 22.
Jan 24 10:49:37 mytux sshd[5947]: Server listening on :: port 22.
Jan 24 10:50:03 mytux sshd[5971]: Accepted keyboard-interactive/pam for root from xxx.xxx.xxx.xxx port 33032 ssh2
Jan 24 10:50:03 mytux sshd[5971]: pam_unix(sshd:session): session opened for user root by (uid=0)
Jan 24 10:50:03 mytux sshd[6013]: Accepted keyboard-interactive/pam for root from xxx.xxx.xxx.xxx port 33033 ssh2
Jan 24 10:50:03 mytux sshd[6013]: pam_unix(sshd:session): session opened for user root by (uid=0)
Jan 24 12:10:20 mytux sshd[13201]: Accepted keyboard-interactive/pam for root from xxx.xxx.xxx.xxx port 33310 ssh2
.......

 
Oder:

mytux:~ # journalctl _SYSTEMD_UNIT=vmware.service 
-- Logs begin at Fri 2014-12-19 17:40:02 CET, end at Sun 2015-09-27 19:07:41 CEST. --
Jan 03 09:31:07 mytux vmware[1475]: Starting VMware services:
Jan 03 09:31:07 mytux vmware[1475]: [33B blob data]
Jan 03 09:31:07 mytux vmware[1475]: [49B blob data]
Jan 03 09:31:07 mytux vmware[1475]: [50B blob data]
Jan 03 09:31:07 mytux vmware[1475]: [30B blob data]
Jan 03 09:31:07 mytux vmnetBridge[1775]: Bridge process created.
Jan 03 09:31:07 mytux vmnetBridge[1775]: RTM_NEWLINK: name:enp8s0 index:2 flags:0x00011043
Jan 03 09:31:07 mytux vmnetBridge[1775]: Adding 
interface enp8s0 index:2
Jan 03 09:31:07 mytux vmnetBridge[1775]: Started bridge enp8s0 to virtual network 0.
.......

 
Erinnert man sich nicht mehr an laufende Services bzw. systemd-Units, so benutzt man die TAB-Taste erneut:

mytux:~ # journalctl  _SYSTEMD_UNIT=<TAB>[<TAB>]
Display all 196 possibilities? (y or n)

Das Ganze geht auch für Optionen:

journalctl  <TAB>[<TAB>]

Also:

mytux:~ # journalctl  -<TAB>[<TAB>]
--all             --system
--boot            --this-boot
--cursor          --unit
--directory       --until
--disk-usage      --update-catalog
--field           --user
--file            --user-unit
--follow          --verify
--full            --verify-key
--header          --version
--help            -D
--interval        -F
--lines           -a
--list-boots      -b
--list-catalog    -c
--local           -f
--merge           -h
--new-id128       -l
--no-pager        -m
--no-tail         -n
--output          -o
--priority        -p
--quiet           -q
--setup-keys      -u
--since           

 
Wie so oft führen bzgl. eines bestimmten Dienstes bzw. eines korrespondierenden Kommandos mehrere Wege zum Ziel:

mytux:~ # journalctl  _SYSTEMD_UNIT=sshd.service

oder

mytux:~ # journalctl  -u sshd

oder

mytux:~ # journalctl  –unit sshd

und

rux:~ # journalctl  _COMM=sshd

führen zu sehr ähnlichen Outputs. Der letzte Befehl zeigt am meisten an.

“_COMM” steht dabei für “Command” – das ermöglicht natürlich sehr vielfältige Filtermöglichkeiten – je nach Logging-Einstellungen.

Nun kombiniert man den Filter für eine Unit oder ein Komamndo noch mit einer Zeiteinschränkung über die Optionen “–since” und “–until” und jeweiligen Zeitstempeln im Format „2015-06-30 10:13:16“ – und schon fühlt man sich als Admin bzgl. der Analyse etwas besser. Z.B.:

mytux:~ # journalctl -u sshd –since “2015-06-30” –until “today”

Fazit: Durch die Autocompletion-Funktionalität wird einem der Gewöhnungsprozess an “journalctl” doch erheblich erleichtert. Man muss es halt nur wissen – und irgendwann sitzen die Kommando-Optionen auch bei mir.

Links:
https://wiki.archlinux.org/index.php/Systemd
http://0pointer.de/blog/projects/journalctl.html
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/s1-Using_the_Journal.html
https://www.digitalocean.com/community/tutorials/how-to-use-journalctl-to-view-and-manipulate-systemd-logs

Linux, Opensuse 13.2, Firefox: Flash bei Bedarf über Wrapper aktivieren

Ich bin wahrlich kein Freund von Flash. Aber es gibt einige (veraltete) Webseiten, auf denen man bestimmte sinnvolle Inhalte halt nur mit Flash ansehen kann. So hängen ja u.a. einige deutsche Fernsehsender der technischen Entwicklung hinterher. Und dann gibt es da in unserer Familie auch noch ein paar Enkel, die zwar einen Linux-Laptop nutzen, aber trotzdem irgendwelche Flash-Inhalte “unbedingt(!!Opa, unbedingt!!)” sehen “müssen”. Welche Optionen hat man dann?

Erstens kann man auf den “Chrome” oder vorzugsweise auf den “Chromium”-Browser ausweichen. Für beide gibt es ja bekanntermaßen das “Pepper-Flash”-Plugin von Google. “Pepper” steht dabei für eine neue Art von generellem Browser-Plugin-Interface (PPAPI), das aber z.Z. auf Chrome/Chromium begrenzt ist. Siehe hierzu u.a.
http://www.howtogeek.com/193876/using-firefox-on-linux-your-flash-player-is-old-and-outdated/
Dieses Plugin ist möglicherweise nicht sicherer, aber immerhin schneller als das originale Flash von Adobe.

Was aber tun Firefox-Anwender, nachdem Adobe Linux ja generell nicht mehr unterstützt und das mit den Linux-Distributionen noch erhältliche Plugin in der Version 11.2 uralt und mit Sicherheit unsicher ist?

Mozilla selbst unterstützt die Flash-Plugin-Technologie nicht mehr aktiv – und unter Linux schon gar nicht (s. u.a. http://www.linux-magazin.de/NEWS/Firefox-blockiert-Flash-Inhalte). Ich finde das völlig OK – aber was mache ich nun mit veralteten Webseiten oder den lieben Enkeln, die Flash unter FF “unbedingt” nutzen “müssen”?

Nun, ein paar nette Leute haben solche Situationen wohl vorhergesehen und eine Wrapper-SW – das sog. “Fresh Player Plugin” – für das Chrome/Chromium pepper-based Flash-Plugin entwickelt. Siehe etwa:
http://www.makeuseof.com/tag/how-to-get-chromes-latest-flash-player-to-work-in-firefox-on-linux/
http://www.webupd8.org/2014/05/fresh-player-plugin-pepper-flash.html
https://github.com/i-rinat/freshplayerplugin

Es war aber gar nicht so einfach herauszufinden, wie man eine Installation unter Opensuse 13.2 auf einfache Art über Pakete und ohne Kompilieren hinbekommt. Dann fand ich nach etwas Herumsuchen im Packman Repository http://ftp.gwdg.de/pub/linux/packman/suse/openSUSE_13.2/
das Paket “freshplayerplugin”.

Das habe ich mal testweise installiert, und damit war das Problem auch schon gelöst. Allerdings hatte ich auf dem betroffenen System bereits eine Chromium-Installation aus den SuSE-Standard-Repositories an Bord, die ich um das Paket “chromium-pepper-flash” – ebenfalls aus dem Packman-Repository – ergänzt hatte. Wer bislang weder Chrome noch Chromium auf seinem Linux-System zur Verfügung hat, kommt jetzt nicht darum herum, entweder Chrome komplett – oder aber zumindest das Paket “chromium-pepper-flash” zu installieren. (Vorzugsweise verzichtet man auf Chrome – und nutzt Chromium.)

Zum “freshplayerplugin” – also dem Wrapper für FF – gehört eine umfangreiche Konfigurationsdatei. Die steht nach der Paketinstallation unter “/etc/freshwrapper.conf”. Sie enthält eine Zeile, in der der Pfad zur eigentlichen Bibliothek für den Chrome- oder Chromium Pepper-Flash-Player “libpepflashplayer.so”. [Die “so”-Datei wird im Zuge der Installation von “chromium-pepper-flash” angelegt.]

Da ich Chrome, wegen der ständigen Ausforschung durch Google nicht benutze, habe ich bei
mir die Pfadangabe auf das Chromium-Verzeichnis verkürzt.

#pepperflash_path = “/opt/google/chrome/PepperFlash/libpepflashplayer.so:/usr/lib64/chromium/PepperFlash/libpepflashplayer.so”
pepperflash_path = “/usr/lib64/chromium/PepperFlash/libpepflashplayer.so”

Danach muss man im Firefox unter “Extras >> Add-Ons >> Plugins” das aktuelle (pepper-based) Shockwave Flash Plugin nur noch aktivieren.

pepper1

Bei mir haben der Wrapper und das pepper-based Flash auf den (wenigen) Flash-Seiten, die ich mir angesehen habe, problemlos funktioniert. Herzlichen Dank also – im Besonderen von den Enkeln – an die Entwickler des Wrappers!

Wer Wert auf Sicherheit legt, für den mag folgender Hinweis noch interessant sein:
Man kann Firefox (bei aktiviertem Flash Plugin) mit Hilfe von “firejail” auch in einer Art Sandbox-Umgebung laufen lassen. Sieh dazu einen ausführlichen Artikel im aktuellen Linuxuser-Magazin 10/2015.

MySQL – effiziente Prüfung von Tabellenspalten auf (ausschließlich) vorhandene Default-Einträge

Einige meiner Leser wissen, dass ich mich für PHP-basierte Simulationsrechnungen mit dem Thema des Uploads von CSV-Daten-Files für viele Tabellen befassen muss. Nun haben wir eine Situation, in der eine Tabelle zwar viele Spalten enthalten kann, aber für bestimmte Simulationen nicht alle Spalten zwingend mit Werten gefüllt werden müssen. Um die Upload-Zeiten gering zu halten, werden diese Spalten in den CSV-Dateien gar nicht übermittelt. Das durchzuführende LOAD DATA INFILE Statement wird entsprechend angepasst und versorgt die Spalten, für die das File keine Daten liefert, mit Default-Werten.

Nun erfordert jede unserer Simulationsrechnungen eine vorherige Prüfung von Konsistenzbedingungen. Dabei ist es u.a. wichtig, welche Spalten ausschließlich mit Default-Werten gefüllt wurden und welche nicht. Die Meinung eines beteiligten Entwicklers war, dass man diese Information – wenn nötig – unmittelbar aus dem tatsächlich gegebenen Tabellenzustand ermitteln sollte, um immer eine verlässliche Entscheidungsgrundlage zu haben.

Als Voraussetzung nehmen wir an, dass wir aus Platzgründen keine Indices für die einzelnen oder gekoppelten Daten-Spalten der zu untersuchenden Tabelle angelegt haben.

Abfrage über mehrere SQL-Statements für jede Spalte

Der erste naive Anlauf war dementsprechend, in mehreren SQL-Abfragen Spalte für Spalte auf die Anzahl der gesetzten Default-Werte zu prüfen und mit der Gesamtzahl der Tabellen-Records zu vergleichen. Das einzelne Select würde dann etwa so aussehen:

SQL-Typ1:
SELECT COUNT(*) FROM myTable WHERE colx=defaultValue;

Das Ganze pro Spalte für alle zu untersuchenden Tabellen. Ein solches Vorgehen erschien mir ineffizient – insbesondere wenn eine Tabelle viele zu untersuchende Spalten aufweist und man das Ganze für viele Tabellen machen muss. Der Grund:

Jede dieser Abfragen führt einen Full Table Scan durch, denn man wird in den seltensten Fällen einen Index über jede einzelne Spalte oder alle Spalten gelegt haben.

Wir reden in unserem Fall zudem über potentiell große Tabellen mit mehreren 10-Millionen Einträgen.

Ist die Abfrage in einem einzigen SQL-Statement effizienter?

Zunächst dachte ich deshalb darüber nach, ob man die Aufgabe nicht in einem einzigen Statement durchführen kann. Ergebnis:

SQL-Typ 2:
SELECT
SUM(IF(col1 = default_val_col1, 1,0)) as num_def_col1,
SUM(IF(col2 = default_val_col2, 1, 0)) as num_def_col2,
SUM(IF(col3 = default_val_col3, 1, 0)) as num_def_col3,


SUM(IF(coln = default_val_coln, 1, 0)) as num_def_coln
FROM myTable;

Das ist zwar schön und der Ansatz ist sicher für bestimmte andere Auswertungen auch von grundsätzlichem Interesse (s. etwa: http://www.randomsnippets.com/2008/10/05/how-to-count-values-with-mysql-queries/). So kann man ähnliche Statements z.B. einsetzen, wenn man herausfinden will, wie oft vorgegebene, unterschiedliche Werte in genau einer Spalte vorkommen.

Aber ist das in unserem Fall vom Zeitbedarf her wirklich effizienter als der erste Ansatz? Die Antwort lautet: Nur geringfügig.

Die folgenden zwei Abbildungen zeigen typische Werte für SQL-Typ 1 und SQL-Typ2 auf einem einfachen Testserver für eine Tabelle mit ca. 10 Millionen Einträgen und 6 untersuchten Wertespalten:

Messung für Statement vom SQL-Typ1 für eine Spalte

sqlff1

Messung für Statement vom SQL-Typ2 für 6 (!) Spalten

sqlff2

Wir kommen (nach Multiplikation mit der Anzahl der Spalten) auf etwa 6 sec für Typ1 und 5.3 sec Gesamtlaufzeit für Typ2. Der Unterschied ist also nicht weltbewegend. (Hinweis: Ein zusätzlich durchzuführendes Count(*) kostet praktisch keine Zeit; wir haben das hier deshalb weggelassen.)

Warum erhalten wir solch ein Ergebnis?
Nun die Anzahl der zu treffenden Entscheidungen ist praktisch identisch und gezählt wird in beiden Fällen. Demgegenüber tritt das mehrfache Durchlaufen der Tabelle bei Typ 1 zum systematischen Bereitstellen der Daten einer Zeile in den Hintergrund. Im besonderen, wenn die Tabelle schon im Cache vorliegen sollte.

Noch ineffizienter wird ein Ansatz, bei dem mit COUNT(Distinct) gearbeitet würde und bei den Spalten die nur einen Wert aufweisen, diesen Wert zusätzlich ermittelt würde :

Allein das Statement für unsere Testtabelle

SELECT COUNT( DISTINCT sssim ) AS dist_sssim, COUNT( DISTINCT mult ) AS dist_mult, COUNT( DISTINCT dobs ) AS dist_dobs, COUNT( DISTINCT sigmad ) AS dist_sigmad, COUNT( DISTINCT sigmalt ) AS dist_sigmalt, COUNT( DISTINCT fexp ) AS dist_fexp
FROM `alien_ss_comb_itm`

dauert hier 7.6 sec. Dies liegt daran, dass hier temporäre Datenstrukturen bzw. Tabellen erzeugt werden.

Die langsamste Abfrage-Alternative

Es gibt natürlich eine weitere Alternative zum Typ 1 – Statement:

SQL-Typ3:
SELECT colx as dist_colx, COUNT(colx) as num FROM myTable GROUP BY colx;

Die Anzahl der Treffer, der Ausgabewert “num” und der ggf. gefundene alleinige Wert können auch hier dafür verwendet werden, um festzustellen, ob die Spalte nur mit Default-Werten gefüllt ist.
Für dieses Statement dauert in unserer Testtabelle die Abfrage über eine einzige Spalte allerdings bereits 2.5 sec:

sqlff3

Auch hier ist das Anlegen von temporären Datenstrukturen und der erforderliche Einsatz von Filesort in der MySQL-DB die Ursache der schlechten Performance.

Zu kostspielig? Alternativen?

Offenbar ist so eine Prüfung für große Tabellen relativ kostspielig. Mehrere Sekunden, um festzustellen, welche Spalten mit regulären Daten gefüllt wurden? Geht gar nicht …

Zugegeben: Das hängt immer davon ab, in welchen Zusammenhang – also Art von Upload- oder Serverlauf – man eine solche Prüfung einbettet. Dauert ein Simulationslauf für große Tabellen 15 Minuten, so sind 5 sec egal. Auch bei Uploadzeiten von 50 sec kann man 10% Zuwachs verschmerzen. Auch zugegeben: Man ist von keiner weiteren Information außer dem aktuellen Tabellenzustand selbst abhängig.

Würde das Anlegen eines Index pro Spalte helfen?
Natürlich würde das SQL-Statements vom Typ 1 extrem beschleunigen! Aber kann man sich Indices pro Spalte denn bei großen Tabellen überhaupt leisten? Wohl eher nicht: Indices kosten u.U. und je nach Kardinalität enorm viel Platz und ihr Anlegen erhöht den Bedarf an CPU-Zeit im Rahmen eines Dateiimports beträchtlich. Wenn man also Indices über einzelne Daten-Spalten nicht noch für andere Zwecke benötigt, sollte man deshalb eher die Finger davon lassen.

Beschleunigung von erforderlichen Abfragen auf den Füllgrad von Spalten mit
Defaultwerten über eine Hilfstabelle

Muss man die vorgesehene Prüfung überhaupt über SQL-Abfragen auf den Spalten der zu untersuchenden Tabelle machen?

In unserem Fall, in dem es nur darum geht, ob in einer Spalte aussschließlich Default-Werte vorliegen, natürlich nicht! Der einzig sinnvolle Weg führt mal wieder über eine Hilfstabelle, die bereits auf Grund einer Analyse des Aufbaus der importierten CSV-Datei erstellt wird.

Im Fall der Verwendung von “LOAD DATA INFILE” genügt dabei ein Check der ggf. vorhandenen Header-Zeile mit Spaltenbezeichnungen und der ersten Datenzeile; ein solcher Check ist sowieso obligatorisch, um das “LOAD DATA INFILE” Statement um explizite Angaben zum Füllen der Spalten zu ergänzen, für die die CSV-Datei keine Daten liefert. Ein so ergänztes “LOAD DATA INFILE”-Statement ist viel schneller als das Füllen mit Defaultwerte der Bank selbst zu überlassen. Einen Check der Korrektheit der Struktur der übergebenen Daten benötigt man im übrigen sowieso.

Lösung: Auf Basis der CSV-Datei-Analyse füllt man nach einem erfolgreichen Laden der CSV-Daten in die Ziel-Tabelle zusätzlich eine kleine Hilfstabelle, in der für jede Tabelle und Spalte Werte eingetragen werden, die besagen, wie oft der Default-Wert vorliegt und ob er ausschließlich vorliegt.

Alle nachfolgenden Prüfungen greifen dann auf den Inhalt dieser Hilfstabelle zu. Das ist selbst bei einem zusätzlichen Vergleich von Zeitstempeln zwischen Hilfs-Tabelle und Original-Tabelle um Größenordnungen schneller als ein Statement vom Typ 2 – nicht nur bei großen Tabellen.

Sollte die Hilfstabelle aus irgendeinem Grunde mal nicht gefüllt sein, oder die Zeitstempel nicht passen, kann man ja in dem Programm, das die Belegung von Spalten mit Defaultwerten prüfen will, immer noch auf das Statement vom Typ 2 als Fallback zurückgreifen. Aber das ist maximal nur genau einmal erforderlich!

Genau so haben wir es dann in unserem Projekt auch gemacht!

Es liegt im übrigen auf der Hand, wie man mit ein wenig Parametrierung eine allgemeinere PHP-Funktion erstellt, die ermittelt, wie oft spaltenspezifische, vorgegebene Werte in einer importierten Datentabelle auftauchen. So ist die (dynamische) Erzeugung von SQL-Statements vom Typ 2 für Tabellenspalten ohne Index also für bestimmte Auswertungen ggf. doch von Nutzen.

Nvidia Treiber, KDE-Plasma-Desktop 4.14, Tearing-Effekt: Triple Buffering einschalten!

Meine Leser wissen, dass ich bzgl. des Linux-Desktops auf KDE setze. Den HW-technischen Unterbau liefern in meinen privaten Systemen, die ich meist selbst aufbaue, Nvidia-Grafikkarten. In der Regel verwende ich dafür den proprietären Treiber, dessen Modul ich über das Installationsskript von Nvidia kompilieren und installieren lasse. (Mit der unangenehmen Konsequenz eines “tainted” Kernel – aber das nur nebenbei).

Dieser Artikel betrifft ein Plasma-Problem, das ich auf Desktop-Systemen hatte. (Der Artikel bezieht sich nicht auf Laptop-Systeme mit Optimus-Technologie.) Seit geraumer Zeit (schätzungsweise seit KDE 4.12 bis heute unter KDE 4.14.9) plagte mich folgender, immer wiederkehrender Fehler:

Nach dem Starten des KDE Plasma Desktops mit aktivierten 3D-Effekten (OpenGL) – kam es bei der Bewegung von bestimmten Fenstern immer wieder zum sogenannten “Tearing”-Effekt. Besonders deutlich sichtbar wurde der für Fensterbegrenzungslinien von “konsole” oder Fenstern mit komplexeren GTK-Anwendungen. Dies erwies sich als unabhängig von der Voreinstellung der des OpenGL Composite Typs und des Qt-Grafiksystems (“native” oder “raster” Rendering)

Erstaunlicherweise verschwand dieser Effekt bei mir ebenso regelmäßig, wenn ich unter den KDE Systemeinstellungen auf dem Panel zu “Arbeitsflächen-Effekte” >> “Erweitert” eine der dortigen Einstellungen änderte und auf “Anwenden” drückte. Danach war für diese X-Sitzung Ruhe. Bei der Einstellungsänderung wurde offenbar etwas erkannt, was beim normalen KDE-Start nicht der Fall war). Aber solche manuellen Eingriffe bei jedem Start von KDE sind natürlich nervig.

Zufällig bin ich in anderem Zusammenhang vor ein paar Tagen über folgende Bug-Artikel gestolpert:
https://bugs.kde.org/show_bug.cgi?id=322060
https://bugs.kde.org/show_bug.cgi?id=330794
https://bugs.kde.org/show_bug.cgi?id=343184

Dadurch animiert habe ich nun mal “Triple Buffering” explizit in die “xorg.conf” eingetragen. Der Installer von Nvidia tut das nämlich nicht von sich aus. Er bewegte aber den einmal vorgenommenen händischen Eintrag bei der nächsten Treiber-Installation interessanterweise aus der “Device Section” in die “Screen Section”:

Auszug aus der /etc/X11/xorg.conf”:

Section "Screen"

    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
    Option         "Stereo" "0"
    Option         "nvidiaXineramaInfoOrder" "DFP-0"
    Option         "metamodes" "DVI-I-1: nvidia-auto-select +5120+0, HDMI-0: nvidia-auto-select +0+0, HDMI-1: nvidia-auto-select +2560+0"
    Option         "SLI" "Off"
    Option         "MultiGPU" "Off"
    Option         "BaseMosaic" "off"
    Option         "TripleBuffer" "true"
    SubSection     "Display"
        Depth       24
    EndSubSection
EndSection

 
Man erkennt hier, das ich Xinerama für 3 Schirme nutze. Der interessante Eintrag ist aber:

Option “TripleBuffer” “true”

Ich kann nur sagen:

Seitdem ist jegliches Tearing auf meinem 3-Schirme-Desktop verschwunden – ohne weitere Zusatzmaßnahmen und egal, was ich unter “Arbeitsflächen-Effekte” >> “Erweitert” für Einstellungen zum Punkt “Einzelbild-Zerreißen (Tearing) verhindern (Vsync)” einstelle. Auch ein spezieller Export der Umgebungsvariablen “__GL_YIELD” wie in einem der Bug-Reports beschrieben, erwies sich unter KDE 4.14 als überflüssig – diese Umgebungsvariable ist bei mir gar nicht gesetzt.

r
So einfach – man muss es halt nur wissen! Mein Dank an alle, die sich um diesen Bug in seinen verschiedenen Ausprägungen gekümmert haben! Ein schönes Beispiel dafür, dass der Open Source Prozess auch im Zusammenspiel mit Closed Source Komponenten funktioniert – auch wenn es manchmal etwas dauert.