Freitag, 30. Dezember 2022

ein snap ausprobieren / testweise installieren

ein snap testen

Hinweis: das im folgenden beschriebene Vorgehen ist explizit mit Ubuntu 22.04 LTS durchgeführt worden. Da snapd, der Daemon, der für snaps zuständig ist, aber von Canonical für alle unterstützen Ubuntuversionen gleichermaßen gepflegt wird, sollte das Vorgehen auch für andere Ubuntuversion funktionieren. Ebenso sollte das Vorgehen für andere Linuxdistributionen funktionieren, auf denen snapd installiert ist.

snap, das Paketformat von Canonical erlaubt es, ein Programm auszuprobieren, ohne dass das snap komplett installiert werden mus.

Im Vergleich zu einer normalen Installation eines snaps über snap install unterscheidet sich dieses Verfahren in vier Punkten:

  1. Es werden keine Konfigurationsdateien im Homeverzeichnis des Nutzers unter ~/.config angelegt - es werden aber trotzdem Dateien unter ~/snap für das snap angelegt, das man testet.
  2. Das snap wird bei einem snap refresh nicht aktualisiert.
  3. Man könnte Dateien, die zum snap gehören, zur Laufzeit des snaps editieren und diese Änderung würden beim Start des Programms berücksichtigt. Was sich aber nicht ändern lässt ist das Confinement sowie die Connections eines snaps. 1.. Wenn man das Programm über die Kommandozeile startet, erhält man dort gegebenenfalls die Ausgaben des Programms wie Fehler- oder Warnmeldung. Dies kann bei der Fehlersuche hilfreich sein, wenn ein über ein snap installiertes Programm Probleme machen sollte.

Hinweis: Diese Verfahren ist dazu gedacht, Programme auszuprobieren, die noch nicht regulär installiert sind. Möchte man zwei verschiedene Versionen eines snap parallel nutzen sind Hinweis dazu im Blogartikel snaps parallel installieren zu finden.

Vorgehen

Im folgenden wird das Inkscape snap für das Vektorzeichenprogramm Inkscape als Beispiel genutzt. Die snap Version ist 10512. Für andere snaps sind einfach der Name und die Versionsnummer entsprechend anzupassen. Für alle folgenden Schritte gehe ich davon aus, dass man sich in seinem eigenen Homeverzeichnis ~/ befindet.

Die folgenden Befehle müssen alle im Terminal ausgeführt werden, teilweise sind dafür Root-Rechte notwendig.

Herunterladen und testweise einbinden

Zuerst lädt man das snap herunter, ohne es zu installieren, mit Hilfe des Befehls download:

$ snap download inkscape

Dabei werden zwei Dateien heruntergeladen: das snap an sich, in diesem Beispiel namens inkscape_10512.snap und die zugehörige Assertion-Datei (Verifizierungsdatei) inkscape_10512.assert, welche die kryptographischen Schlüssel und Validierungsdaten enthält, die bei einer Installation des snaps geprüft würden. "10512" ist hierbei die Versionsnummer zur Zeit des Downloads aktuelle, stabilen snaps. Der Befehl download kennt auch ein Option für Channels, d.h. man kann auch eine Beta- oder Testversion herunterladen - je nach dem was für das jeweilige snap bereit gestellt wird.

snaps in ein SquashFS Dateisystem verpackt, welches zuerst in ein Verzeichnis entpackt werden muss. Das notwendige Programm Namens unsquashfs ist bei Ubuntu standardmäßig installiert (wenn zuerst nein muss über die Paketverwaltung zuerst das Paket "squashfs-tools" installiert werden):

$ unsquashfs inkscape_10512.snap

Im Verzeichnis ist jetzt ein neues Unterverzeichnis namens squashfs-root angelegt worden, welches das entpackte snap enthält. Bei Interesse kann man durch das Verzeichnis und dessen Unterverzeichnisse navigieren, um zu sehen, wo welche Dateien liegen.

Zum Ausprobieren von Inkscape muss man den folgenden Befehl ausführen:

$ sudo snap try squashfs-root

Auch, wenn man sich im eigenen Homeverzeichnis befindet, sind Root-Rechte notwendig. Anschließend kann Inkscape regulär im Terminal, die GNOME-Shell bzw. Weg der jeweiligen Desktopumgebung den gestartet werden.

Das testweise laufende snap erscheint jetzt auch in der Liste des installierten snaps, auch wenn es nicht richtig installiert ist:

$ snap list

Name             Version                           Revision  Tracking    Herausgeber  Hinweise  
...  
inkscape         1.2.2-b0a8486541-2022-12-01-cust  x1        -           -            try  
...  

Die Revisionsnummer für snap zum Ausprobieren ist x1 und in der Spalte "Hinweis" ist zu sehen, dass das Inkscape snap im try-Modus ist.

Ein so eingebundenes snap wird auch bei einem Systemneustart wieder eingebunden, wie andere, regulär installierte snaps auch. Das deaktivieren / deinstallieren wird im folgenden Abschnitt beschrieben.

snap wieder entfernen

Das testweise installierte snap kann wie ein reguläres snap deinstalliert werden:

$ snap remove inkscape

Danach kann man das Verzeichnis ~/squashfs-root und das Verzeichnis inklusive Unterverzeichnissen ~/snap/inkscape löschen. Des Weiteren kann man die heruntergeladenen Dateien inkscape_10512.snap und inkscape_10512.assert löschen.

Was tun, wenn versehentlich auch ein produktiv genutztes snap ausprobiert wurde?

Hat man - versehentlich oder bewusst - ein snap testweise installiert, welches in einer anderen Version schon regulär installiert war (z.B. das Firefox snap), dann wird regulär installierte gegebenenfalls durch das testweise installierte ersetzt. Dies lässt sich aber einfach rückgängig machen, im folgenden am Beispiel des Firefox snaps gezeigt:

Zuerst prüft man, ob noch eine reguläre Version des snap installiert ist. Dies sollte normalerweise der Fall sein, da immer mindestens eine ältere Version eines snap noch vorhanden ist:

$ snap list firefox --all

...  
firefox  107.0.1-1  2154      latest/stable  mozilla✓     deaktiviert,try  
firefox  108.0b9-1  x1        latest/stable  -            try  
...  

Die Ausgabe zeigt, das es die testweise installierte Version x1 und eine weitere, reguläre Version 2154 auf dem System gibt. Mit den folgenden beiden Befehlen kehrt man zur regulären Version zurück und löscht das snap der Testversion:

$ sudo snap revert firefox $ sudo snap remove firefox --revision=x1

Für das vollständige Entfernen des testweise installierten Version löscht man noch die Dateien wie weiter oben im Abschnitt "snap wieder entfernen" beschrieben.

Dienstag, 27. Dezember 2022

snaps parallel installieren

snaps parallel installieren

Hinweis: das im folgenden beschriebene Vorgehen ist explizit mit Ubuntu 22.04 LTS durchgeführt worden. Da snapd, der Daemon, der für snaps zuständig ist, aber von Canonical für alle unterstützen Ubuntuversionen gleichermaßen gepflegt wird, sollte das Vorgehen auch für andere Ubuntuversion funktionieren. Ebenso sollte das Vorgehen für andere Linuxdistributionen funktionieren, auf denen snapd installiert ist.

snap, das Paketformat von Canonical erlaubt es, mehrere Versionen eines Programms parallel zu installieren. Die Voraussetzung ist dabei, dass die snaps aus verschiedenen Channels stammen. Verschiedene Channels können z.B. eine Extend Support Version eines Programms sein und der reguläre / aktuelle, stabile Release.

Verschiedene Channels sind aber in der Regel nicht die aktuelle, stabile Version ein Programms und die Betaversion, da diese bei vielen / den meisten snaps im selben Track sind und damit nicht parallel installierbar

Warum parallel installieren?

Ob man ein snap in mehreren Version parallel installieren möchte (oder muss), muss man letztenslich für sich selber entschieden. Wirklich nötig ist es - zumindest in meinen Augen - wohl eher selten. Interessant ist es vielleicht für diejenigen, die zu Testzwecken mehrere Versionen eines Programms benötigen, wie z.B. den auch im folgenden als Beispiel verwendeten Firefox in der jeweils aktuellen und ESR-Version.

Risiko einer Parallelinstallation

Das Risiko kann, je nach snap, sein, dass die eine Version des snaps Konfigurationsdateien des anderen snap überschreibt oder ändert, was zu Problemen führen könnte (aber nicht muss).

Vorgehen

Im folgenden wird als Beispiel das Firefox snap aus dem "stable/latest" (=das standardmäßig installiere) und dem "esr/latest" Track/Channel, so dass zwischen der jeweils aktuellsten und aktuellsten ESR (=Extended Support Release) Version gewechselt werden kann. Das Vorgehen ist auf andere snap und andere Channels übertragbar.

Der Wechsel erfolgt über Befehle, die im Terminal eingegeben werden müssen. Zum Wechsel zwischen zwei Versionen dient der Befehl

$ snap switch --channel=TRACK/CHANNEL NAME_DES_SNAPS

Nach dem Ausführen von switch muss immer anschließend noch ein

$ snap refresh

ausgeführt werden. Zum Wechsel auf den stabilen ESR-Track des Firefox führt man die Befehle

$ snap switch --channel=esr/stable firefox $ snap refresh

aus. Da die ESR-Version des Firefox noch nicht installiert ist, wird diese heruntergeladen und aktiviert. Gleichzeitig wird der latest/stable Firefox deaktiviert, aber nicht deinstalliert. Beim nächsten Start des Firefox nutzt man die ESR Version.

Um wieder zum latest/stable Track zurück zu wechseln führt man wieder die beiden Befehle

$ snap switch --channel=lastest/stable firefox $snap refresh

aus.

einen Channel wieder deinstallieren

Möchte man doch nur einen Channel, im folgenden latest/stable nutzen und die Programmversion des anderen deinstallieren, dann wechselt man zuerst in den zu deinstallierenden Channel

$ snap switch --channel=esr/stable firefox $ snap refresh

und deinstalliert dann den Firefox

$ snap remove firefox $ snap switch --channel=latest/stable firefox $ snap refresh

Anschließend muss der Firefox aus dem latest/stable Channel gegebenenfalls noch aktiviert werden. Steht in der Ausgabe von

$ snap list firefox --all

in der Spalte "Hinweise" der Eintrag disabled, dann führt man noch den Befehl

$ snap activate firefox $ snap refresh

aus.

Mittwoch, 8. Juni 2022

Python und Geschwindigkeit auf verschiedenen Intel und AMD CPUs - und einem Apple Bionic Chip

Vor ein paar Jahren gab es hier im Blog einen Post, der die Geschwindigkeit eines Pythonprogramms zum Number-Crunching (in Form eines Primzahlentests) beschriebt (Link zum Artikel).

Ich hatte jetzt kürzliche die Gelegenheit, die Ausführungsgeschwindigkeit auf vier verschiedenen Mobil CPUs verschiedener Hersteller und Generation zu vergleichen, nämlich:

Die Prozessoren sind also eine zum Zeitpunkt des Schreibens des Artikels eine ca. 7 Jahre alte CPU (der Core i5-5200U, erschienen 2015), ein Core i7 Prozessor der 10. Generation (erschienen zweite Jahreshälfte 2019), ein Core i7 Prozessor der 11. Generation (erschienen 2. Jahreshälfte 2021)  sowie die ebenfalls 2021 erschienene Ryzen 7 5700U CPU.

Außerdem habe ich noch einen Test auf einem iPad Air gemacht. Mehr dazu am Ende des Artikels.

Verglichen habe ich nur die Ausführungsgeschwindigkeit des Python-Programms ohne Optimierungen / Beschleunigungen, also ohne PyPy, Cython, JIT Compiler etc.

Als Betriebssystem diente für den Core i5-5200U und den AMD Ryzen 7 5700U Ubuntu 22.04 mit Python 3.10.4 aus den offiziellen Ubuntu Quelle und für die beiden Intel Core i7 Windows 11, ebenfalls mit Python 3.10.4 aus dem Windows App Store, also die Python-Version, die direkt von der PSF bereit gestellt wird.
Das ganze wurde immer bei ruhendem Desktop gemessen, d.h. außer dem Terminal, in dem das Python-Programm läuft, läuft kein weiteres Programm. Es wurde jedes Skript 3x ausgeführt, die weiter unten auf geführten Zeitangabe sind der Mittelwert der Ausführungszeiten.

Als erste habe ich die Ausführungsgeschwindigkeit mit nur einem Prozess gemessen, das Programm sieht wie folgt aus:

import math
from time import time

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419,
    777777722155555333,
    777777722155555335,
    9999999900000001,
    2327074306453592351,
    2327074306453592353]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    for number in PRIMES:
        prime = is_prime(number)
        print('{} is prime: {}'.format(number, prime))

if __name__ == '__main__':
    start = time()
    main()
    end = time()
    print(f'Time: {end - start}')

Die Ergebnisse sind wie folgt:

  • Core i5-5200U: 204 Sekunden
  • Core i7-10510U: 111 Sekunden
  • Core i7-1165G7: 68 Sekunden
  • Ryzen 7 5700U: 78 Sekunden

Wie zu erwarten war, sind die neueren CPUs deutlich schneller. Interessant ist auch die relative große Unterschied zwischen dem Core i7 10. Generation und 11. Generation, letzterer ist etwas 60% schneller. Hier hat Intel deutlich in Sachen Leistung nachgelegt, zumindest was die Performance von nur einem Kern angeht.
Zweite Beobachtung: im weiter oben verlinkten Blogpost wurde der gleiche Code ebenfalls auf dem gleichen Core i5-5200U ausgeführt, nur damals unter Python 3.6. Die Geschwindigkeit war damals quasi identisch mit der hier gemessenen. Auch wenn Python (bzw. genau genommen die Referenzimplementierung CPython) einige Verbesserungen in Sachen Geschwindigkeit bekommen hat, spielen diese zumindest für dieses Szenario keine Rolle, der Code ist auf der gleichen CPU bzw. dem gleichen Rechner wie damals quasi gleich schnell.

Im zweiten Test wurde das Programm modifiziert, so dass mit Hilfe des concurent.futures Moduls mehrere Prozesses zum Rechnen gestartet. Da die Core i5 5200U CPU und auch die neueren Core i7 CPUs "nur" vier Kerne haben, wurde als Prozessanzahl vier gewählt, damit im Idealfall jeder Prozess auf einem Kern läuft.

Der Code sieht wie folgt aus:

import math
from time import time
import concurrent.futures

WORKERS = 4

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419,
    777777722155555333,
    777777722155555335,
    9999999900000001,
    2327074306453592351,
    2327074306453592353]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with concurrent.futures.ProcessPoolExecutor(max_workers=WORKERS) as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))


if __name__ == '__main__':
    print(f'using {WORKERS} workers for calculation')
    start = time()
    main()
    end = time()
    print(f'Time: {end - start}')

Die Ergebnisse für den Multiprozessansatz sind:

  • Core i5-5200U: 111 Sekunden
  • Core i7-10510U: 89 Sekunden
  • Core i7-1165G7: 50 Sekunden
  • Ryzen 7 5700U: 51 Sekunden

Auch hier ist der Leistungsunterschied zwischen dem Core i7 10. und 11. Generation erheblich, der neuere ist ca. 80% schneller. Der Core i7-1168G7 und der Ryzen 7 5700U sind quasi gleich schnell.

Ein zusätzlicher Test mit dem Ryzen 7 und acht Workern brachte keine weitere Beschleunigung, das Ergebnis war quasi identisch mit dem mit vier Workern. Dies liegt im gegebenen Test aber ziemlich sicher daran, dass die ersten sechs Prüfungen relativ schnell abgeschlossen sind, d.h. man zieht für die restlichen fünf Zahlen keinen echten Nutzen aus mehr Kernen, weil nicht mehr so viele Prozesse laufen.

Festzuhalten bleibt aber auch: natürlich sind neuere Prozessoren schneller, aber bringen (bei weitem) nicht so viel wie der Einsatz von schnelleren Python-Implementierungen und JIT Compilern.
Alleine der simple Einsatz von PyPy statt CPython auf dem "alten" Core i5 Prozessor führt den Code doppelt so schnell aus wie die Core i7 CPU der 11. Generation oder der Ryzen 7 5700U.

Zusätzlich zu den diversen Intel und der AMD CPU habe ich den nicht-parallelen Code auf einem iPad Air 3. Generation, iOS 15.5 und Python 3.6.1 aus der Pythonista ausgeführt. Dieses iPad hat eine A12 Bionic CPU. Der parallelisierte Code funktioniert ja leider nicht unter iOS, weil, zumindest zum Zeitpunkt des Schreibens des Artikels, ein Prozess keine weiteren Prozesse starten darf.

Der A12 Bionic braucht für den obigen Code ca. 104 Sekunden - und ist damit ca. 10% schneller der getestet Intel Core i7 der 10. Generation. Schon ganz ordentlich für einen Prozessor, der ca. ein Jahr vor dem Intel Prozessor erschienen ist, wobei allerdings auch der Takt der leistungsstärkeren Kerne des A13 mit 2,,49 GHz (deutlich) höher ist als die 1,80 GHz Core i7-10510U.