Amazon.de Widgets
Skip to content
17.Januar 2011 / Patrick

Linux High Performance Cluster mit Oscar

closeDieser Beitrag wurde vor über 3 Monaten veröffentlicht. Die darin beschriebenen Informationen sind mit Vorsicht zu geniessen, da sie bereits veraltet oder nicht mehr gültig sein könnten. Solltest du von Neuerungen oder Verbesserungen wissen, so freue ich mich über einen klärenden Kommentar.

Mir wurde die interessante, aber relativ anspruchsvolle Aufgabe gestellt, einen Linux High Performance Cluter (Linux HPC) aufzubauen. Weder eine genaue Software, noch ein Betriebssystem war dabei vorgegeben.

Zur Verfügung stehen mir dazu 7 Sun Fire x4000 mit je 7GB RAM und je 2 DualCore-CPUs.

Nun aber habe ich selbst noch nie einen eigenen Cluster erstellt und im Internet waren auf den ersten Blick keine wirklichen Anleitungen verfügbar.
Also habe ich mich mal an den ersten Hinweis von RedHat geklammert. Diese liefern eine schöne Dokumentation mit Schritt-für-Schritt Anleitung. Jedoch scheiterte schlussendlich alles an der Tatsache, dass die Maschine offiziell im RedHat Netzwerk registriert werden muss.
Also ging ich weiter zu Beowulf. Während ich mit der Mailling-Liste des Projektes schrieb, bin ich auf das HPC Framework Oscar gestossen, welches sehr einfach und unkompliziert aussieht, und zudem sehr einfach und übersichtlich dokumentiert wurde.

Da Oscar für Distribution wie Debian, Ubuntu oder Fedora nur bei sehr alten Version volle Kompatibilität versprechen kann, habe ich auf CentOS, die freie Kopie von RedHat zurückgegriffen.

Wer aber möchte, der kann auch auf die folgenden Distributionen zurückgreifen:

  • Ubuntu 8.04
  • Ubuntu 9.10
  • Fedora Core 9
  • Debian 4
  • Debian 5
  • CentOS 5
  • Suse 10
  • Redhat 5

Die gesamte Installation hat Struktur und ist sehr einfach gehalten.
Zu Beginn muss man die Paketquellen von Oscar für yum zufügen. Dazu legt man eine Datei CentOS-OSCAR.repo im Ordner /etc/yum.repo.d/ an mit folgendem Inhalt:

1
2
3
4
5
6
7
8
9
10
# CentOS-OSCAR.repo
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
#
[oscar]
name=CentOS-$releasever - OSCAR
baseurl=http://bison.csm.ornl.gov/repos/rhel-5-i386
gpgcheck=0

Da meine Architektur auf 32-Bit basiert, habe ich die Endung x86_64 mit i386 unter dem Punkt baseurl ersetzt.

Danach muss ein Update ausgeführt werden, um die aktuellsten Pakete zu erhalten! Anschliessend kann Oscar installiert werden:

1
2
yum upgrade
yum install oscar

Nachdem die benötigten Pakete installiert sind, muss man Oscar mitteilen, welche Distribution man verwendet:

1
oscar-config --setup-distro centos-5-i386

Nun, bevor man weitergeht, muss ein Workaround ausgeführt werden, um ein Fehler im Script zu beheben.
Ohne diesen erhält man immer den folgenden Fehler:

1
ERROR: Impossible to detect the format of the online repository

Die Ursache liegt darin, dass RedHat / CentOS ihr Repository umgestellt hat.
Dass einzelne Daten nicht doppelt im Mirror vorkommen, wurde bisher der Ordner einer alten Version, in diesem Fall 5.4, immer zum Ordner der neusten Version, hier 5.5, verlinkt. Da dies aber nun scheinbar nicht mehr der Fall ist, und Oscar immer noch im Ordner 5.4 sucht, welcher dummerweise leer ist, schlägt die gesamte Installation fehl!
Also muss in der Datei /etc/oscar/ die Datei supported_distros.txt angepasst werden. Es müssen alle 5.4 in der Datei durch 5.5 ersetzt werden.

Als Ergebnis erhält man sowas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# The syntax of this file is very simple:
# - the file is composed of blocks, representing different OSCAR release (for
#   instance unstable for trunk, 5.0 for OSCAR-5.0). The version number has to
#   match the version specified in the VERSION file.
# - for each supported distros for a specific OSCAR release, an entry has to 
#   exist in the associated block
# - each distro entry is as following:
#   DISTRO-ID default-distro-repo default-oscar-repo
#   where: DISTRO-ID is the distribution id using the OS_Detect syntax
#          default repository URLs have to follow the rapt/yume syntax with the
#          prefix oscar: if the repository is an OSCAR one, distro: if it is
#          a repo for the distro.
 
[unstable]
ubuntu-910-x86_64 = distro:http://us.archive.ubuntu.com/ubuntu/+karmic+main+universe+multiverse oscar:http://bison.csm.ornl.gov/repos/unstable/debian-5-x86_64/+etch+/ distro:http://us.archive.ubuntu.com/ubuntu/+karmic-updates+main+universe+multiverse
scientific_linux-5-i386 = distro:http://ftp.scientificlinux.org/linux/scientific/54/i386/ oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-i386
redhat-el-5-i386 = distro:file:/tftpboot/distro/redhat-el-5-i386 oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-i386
redhat-el-5-x86_64 = distro:file:/tftpboot/distro/redhat-el-5-x86_64 oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-x86_64
centos-5-x86_64 = distro:http://mirror.centos.org/centos/5.5/os/x86_64/ oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-x86_64 distro:http://mirror.centos.org/centos/5.5/extras/x86_64/
centos-5-i386 = distro:http://mirror.centos.org/centos/5.5/os/i386/ oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-i386 distro:http://mirror.centos.org/centos/5.5/extras/i386/
fedora-9-i386 = distro:http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Everything/i386/os/ oscar:http://bison.csm.ornl.gov/repos/unstable/fc-9-i386
fedora-9-x86_64 = distro:http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Everything/x86_64/os/ oscar:http://bison.csm.ornl.gov/repos/unstable/fc-9-x86_64
ubuntu-904-x86_64 = distro:http://us.archive.ubuntu.com/ubuntu/+jaunty+main+universe+multiverse oscar:http://bison.csm.ornl.gov/repos/unstable/debian-5-x86_64/+etch+/ distro:http://us.archive.ubuntu.com/ubuntu/+jaunty-updates+main+universe+multiverse
ubuntu-804-x86_64 = distro:http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-x86_64/+etch+/
ubuntu-804-i386 = distro:http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-i386/+etch+/
debian-4-x86_64 = distro:http://ftp.us.debian.org/debian/+etch+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-x86_64/+etch+/
debian-4-i386 = distro:http://ftp.us.debian.org/debian/+etch+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-i386/+etch+/
debian-5-x86_64 = distro:http://ftp.us.debian.org/debian/+lenny+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-5-x86_64/+lenny+/
debian-5-i386 = distro:http://ftp.us.debian.org/debian/+lenny+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-5-i386/+lenny+/
suse-10-i386 = distro:http://download.opensuse.org/distribution/10.3/repo/oss/suse/ oscar:http://bison.csm.ornl.gov/repos/unstable/suse-10-i386
 
[6.0.5]
scientific_linux-5-i386 = distro:http://ftp.scientificlinux.org/linux/scientific/54/i386/ oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-i386
redhat-el-5-i386 = distro:file:/tftpboot/distro/redhat-el-5-i386 oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-i386
redhat-el-5-x86_64 = distro:file:/tftpboot/distro/redhat-el-5-x86_64 oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-x86_64
centos-5-x86_64 = distro:http://mirror.centos.org/centos/5.5/os/x86_64/ oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-x86_64 distro:http://mirror.centos.org/centos/5.5/extras/x86_64/
centos-5-i386 = distro:http://mirror.centos.org/centos/5.5/os/i386/ oscar:http://bison.csm.ornl.gov/repos/unstable/rhel-5-i386 distro:http://mirror.centos.org/centos/5.5/extras/i386/
ubuntu-904-x86_64 = distro:http://us.archive.ubuntu.com/ubuntu/+jaunty+main+universe+multiverse oscar:http://bison.csm.ornl.gov/repos/unstable/debian-5-x86_64/+etch+/ distro:http://us.archive.ubuntu.com/ubuntu/+jaunty-updates+main+universe+multiverse
ubuntu-804-x86_64 = distro:http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-x86_64/+etch+/ distro:http://us.archive.ubuntu.com/ubuntu/+hardy-updates+main+universe+multiverse
ubuntu-804-i386 = distro:http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-i386/+etch+/ distro:http://us.archive.ubuntu.com/ubuntu/+hardy-updates+main+universe+multiverse
debian-4-x86_64 = distro:http://ftp.us.debian.org/debian/+etch+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-x86_64/+etch+/
debian-4-i386 = distro:http://ftp.us.debian.org/debian/+etch+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-4-i386/+etch+/
debian-5-x86_64 = distro:http://ftp.us.debian.org/debian/+lenny+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-5-x86_64/+lenny+/
debian-5-i386 = distro:http://ftp.us.debian.org/debian/+lenny+main oscar:http://bison.csm.ornl.gov/repos/unstable/debian-5-i386/+lenny+/
 
[6.0.4]
centos-5-x86_64 http://isoredirect.centos.org/centos/5.3/os/x86_64/ http://bison.csm.ornl.gov/repos/rhel-5-x86_64
centos-5-i386 http://isoredirect.centos.org/centos/5.3/os/i386/ http://bison.csm.ornl.gov/repos/rhel-5-i386
ubuntu-804-x86_64 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bison.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
ubuntu-804-i386 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bison.csm.ornl.gov/repos/debian-4-i386/+etch+/
debian-4-x86_64 http://ftp.us.debian.org/debian/+etch+main http://bison.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
debian-4-i386 http://ftp.us.debian.org/debian/+etch+main http://bison.csm.ornl.gov/repos/debian-4-i386/+etch+/
debian-5-x86_64 http://ftp.us.debian.org/debian/+etch+main http://bison.csm.ornl.gov/repos/debian-5-x86_64/+etch+/
ubuntu-904-x86_64 http://us.archive.ubuntu.com/ubuntu/+jaunty+main+universe+multiverse http://bison.csm.ornl.gov/repos/unstable/debian-5-x86_64/+etch+/
 
[6.0.3]
centos-5-x86_64 http://isoredirect.centos.org/centos/5.3/os/x86_64/ http://bison.csm.ornl.gov/repos/rhel-5-x86_64
centos-5-i386 http://isoredirect.centos.org/centos/5.3/os/i386/ http://bison.csm.ornl.gov/repos/rhel-5-i386
fedora-9-i386 http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Everything/i386/os/ http://bison.csm.ornl.gov/repos/fc-9-i386
ubuntu-804-x86_64 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bison.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
ubuntu-804-i386 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bison.csm.ornl.gov/repos/debian-4-i386/+etch+/
debian-4-x86_64 http://ftp.us.debian.org/debian/+etch+main http://bison.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
debian-4-i386 http://ftp.us.debian.org/debian/+etch+main http://bison.csm.ornl.gov/repos/debian-4-i386/+etch+/
suse-10-x86_64 http://ftp-stud.fht-esslingen.de/pub/Mirrors/ftp.suse.com/pub/suse/x86_64/update/10.0-OSS/ http://bison.csm.ornl.gov/repos/suse-10-x86_64
debian-5-x86_64 http://ftp.us.debian.org/debian/+etch+main http://bison.csm.ornl.gov/repos/debian-5-x86_64/+etch+/
 
[6.0.2]
centos-5-x86_64 http://isoredirect.centos.org/centos/5/os/x86_64/ http://bear.csm.ornl.gov/repos/rhel-5-x86_64
centos-5-i386 http://isoredirect.centos.org/centos/5/os/i386/ http://bear.csm.ornl.gov/repos/rhel-5-i386
ubuntu-8-x86_64 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bear.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
ubuntu-8-i386 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bear.csm.ornl.gov/repos/debian-4-i386/+etch+/
debian-4-x86_64 http://ftp.us.debian.org/debian/+etch+main http://bear.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
debian-4-i386 http://ftp.us.debian.org/debian/+etch+main http://bear.csm.ornl.gov/repos/debian-4-i386/+etch+/
 
[6.0.1]
centos-5-x86_64 http://isoredirect.centos.org/centos/5/os/x86_64/ http://bear.csm.ornl.gov/repos/rhel-5-x86_64
centos-5-i386 http://isoredirect.centos.org/centos/5/os/i386/ http://bear.csm.ornl.gov/repos/rhel-5-i386
redhat-el-5-x86_64 file:/tftpboot/distro/rhel-5-x86_64 file:/tftpboot/oscar/rhel-5-x86_64
redhat-el-5-i386 file:/tftpboot/distro/rhel-5-i386 file:/tftpboot/oscar/rhel-5-i386
ubuntu-8-x86_64 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bear.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
ubuntu-8-i386 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bear.csm.ornl.gov/repos/debian-4-i386/+etch+/
debian-4-x86_64 http://ftp.us.debian.org/debian/+etch+main http://bear.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
debian-4-i386 http://ftp.us.debian.org/debian/+etch+main http://bear.csm.ornl.gov/repos/debian-4-i386/+etch+/
 
[6.0]
ubuntu-8-x86_64 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bear.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
ubuntu-8-i386 http://us.archive.ubuntu.com/ubuntu/+hardy+main+universe+multiverse http://bear.csm.ornl.gov/repos/debian-4-i386/+etch+/
debian-4-x86_64 http://ftp.us.debian.org/debian/+etch+main http://bear.csm.ornl.gov/repos/debian-4-x86_64/+etch+/
debian-4-i386 http://ftp.us.debian.org/debian/+etch+main http://bear.csm.ornl.gov/repos/debian-4-i386/+etch+/
redhat-el-5-x86_64 file:/tftpboot/distro/rhel-5-x86_64 file:/tftpboot/oscar/rhel-5-x86_64
redhat-el-5-i386 file:/tftpboot/distro/rhel-5-i386 file:/tftpboot/oscar/rhel-5-i386
centos-5-x86_64 http://isoredirect.centos.org/centos/5/os/x86_64/ http://bear.csm.ornl.gov/repos/rhel-5-x86_64
centos-5-i386 http://isoredirect.centos.org/centos/5/os/i386/ http://bear.csm.ornl.gov/repos/rhel-5-i386

Ist auch das geschafft, so folgt der nächste Workaround.
Das Script versucht eine mehr oder weniger alte Version von MySQL-Server zu installieren, was dummerweise fehl schlägt, und somit die ganze Installation mitreisst!
Also muss man von Hand die neuste Version vorinstallieren und dann den bootstrap starten:

1
2
yum install mysql-server yum-utils
oscar-config --bootstrap

Dies dauert relativ lange und gibt viel Sinnloses und Unsiniges auf der Konsole aus ;) Ruhig Blut also und Däumchen drehen.
Wenn das Script endlich durchgelaufen ist, geht es weiter mit dem Systemtest:

1
system-sanity

Hier empfiehlt es sich sehr, alle Vorschläge zu verbessern!
Wurde auch das erledigt, so kommt der Wizard zum Zug:

1
oscar_wizard install

Dieser ist relativ einfach gehalten, und kann Schritt-für-Schritt durchgegangen werden.
Bei Step 1 können weitere Pakete ausgewählt werden, was für den Standard aber überflüssig ist. Danach können diese Konfiguriert und zum Schluss alles Installiert werden.
Weiter geht es dann unter Step 4 mit dem Image für die Nodes. Dies kann direkt von Oscar selbst zusammengebastelt und erstellt werden, was ich als relativ nützliche und coole Funktion empfunden habe.
Zuerst muss aber die Plattenverwendung angepasst werden, da der Standard bei mir nicht funktionieren wollte:

1
2
3
/dev/sda1        *    ext3  /          defaults bootable
/dev/shm         -    tmpfs /dev/shm   defaults
nfs_oscar:/home  -    nfs   /home      rw

Dann geht’s auch schon los! Jedoch dauert der Vorgang sehr sehr sehr lange. Auch ist es normal das zwischendurch Fehler auftreten. Solange das Script nicht abbricht kann der Ausdruck ERROR mit einer Warnung gleichgesetzt werden ;)
Unter Step 5 müssen dann alle Nodes und in Step 6 die passende MAC-Adressen dazu erfasst werden, damit die Clients später auch gleich selbst installiert werden können.
Wer dem System, wie ich, nicht so ganz traut, oder noch andere heikle Server im selben Netzwerk hat, der kann auch eine CD mit dem ISO erstellen und dadurch auf PXE verzichten.

Sind dann auch die Nodes installiert, so zeigt Oscar an, dass alles erfolgreich installiert wurde. Nun in Wirklichkeit folgt hier Workaround Nummer 3!
Die Nodes verrennen sich nämlich in einer Kernelpanik mit dem folgenden Error:

1
Kernel panic - not syncing: Attempted to kill init!

Glücklicherweise lässt sich der Fehler umgehen, indem man dem Kernel die folgende Option anfügt:

1
enforcing=0

Dazu muss man den Grup Loader unterbrechen und dann mit der Taste e zuerst den default_kernel bestätigen und danach noch den Kernel (/vmlin…), an welcher dann die vorher angesprochene Phrase gehängt wird.

Danach können die Nodes gebootet werden und laufen problemlos. Damit man aber nicht jedes mal diese Änderung manuell machen muss, kann der Eintrag auch in der /boot/grub/grub.conf ergänzt werden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
##################################################
# This file is generated by System Configurator. #
##################################################
# The number of seconds to wait before booting.
timeout 5 
# The default kernel image to boot.
default 0
# The splash image (this line will be empty if nothing was found)
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
 
# kernel0 (hd0,0)
title default_kernel_(hd0,0)
	root (hd0,0)
	kernel /boot/vmlinuz-2.6.18-194.el5 ro root=/dev/sda1 enforcing=0
	initrd /boot/initrd-2.6.18-194.el5.img

Nun ist der Cluster komplett und kann abgeschlossen werden.
Dabei versucht das Skript automatisch die von mir gewählte Sun Grid Engine zu installieren. Leider gibt es auch hier wieder eine Diskrepanz.
So gibt es ein Script im Ordner /opt/sge/utilbin/lx26-x86 mit dem Namen gethostbyname und gethostname.
Das zweite gibt den FQDN der Maschine aus, also Name und Domain. Das erste Skript versucht dann anhand dieser Information eine IP zu bekommen.
Dummerweise ist in der hosts Datei die Domain vergessen gegangen. Also muss die Datei /etc/hosts wiefolgt ergänzt werden:

1
2
3
4
5
6
7
8
9
10
11
[root@lcc103 ~]# cat /etc/hosts
127.0.0.1		localhost.localdomain localhost
::1		localhost6.localdomain6 localhost6
10.128.88.102 lcc102.encodingit.ch lcc102 oscar_server nfs_oscar pbs_oscar 
 
# These entries are managed by SIS, please don't modify them.
 
#  addresses
10.128.88.103        lcc103.encodingit.ch lcc103
10.128.88.104        lcc104.encodingit.ch lcc104
10.128.88.105        lcc105.encodingit.ch lcc105

Dies muss nun auf allen Nodes verteilt werden (am schnellsten via scp) und dann funktioniert auch das Abschliessen des Cluster-Setup.

Wie genau aber der Syntax des Clusters funktioniert, wie Jobs verteilt oder das Queueing System verwendet wird, kommt in einem späteren Beitrag – da muss ich zuerst noch Vorarbeit leisten und mich selbst einarbeiten!

Wer nun auch gerne noch andere Distributionen verwenden möchte, der findet in diesem Dokument Abhilfe.

  • http://twitoaster.com/country-ch/compr00t/ compr00t

    Linux High Performance Cluster mit Oscar http://blog.encodingit.ch/2011/01/linux-… @compr00t

  • Stefan

    http://debianclusters.org/index.php/Main_Page

    Einfacher Debiancluster mit Schritt für Schritt Anleitung. Der in unserer Uni ist auch so aufgebaut.

  • querdenker

    cluster schön und gut aber was willst du damit machen? :)
    lg

    • http://encodingit.ch Patrick

      Nicht für mich privat, für die Arbeit. Die haben schon ihre Verwendung dafür ;-)

      • querdenker

        würde mich interessieren sag schon :)

        • http://encodingit.ch Patrick

          Wenn ich dir das verrate, müsste ich dich umbringen ;)

  • Andreas

    Was meiner Meinung nach am wichtigsten ist: Läuft der Cluster und macht er, was er soll?

    Andreas

    • http://encodingit.ch Patrick

      Bis her schon. Aber wie bereits geschrieben, kämpfe ich noch mit der Bedienungsanleitung, weshalb das Usage-Tutorial noch nicht öffentlich ist. Kommt aber bald mit ausführlichen Tests.

      Aber ganz allgemein: Würde die Installation nicht wie beschrieben funktionieren, so hätte es der Artikel gar nicht bis in den Blog geschafft.