Lapack: Prozessoranforderungen für LAPACK

Erstellt am 4. Juni 2021  ·  16Kommentare  ·  Quelle: Reference-LAPACK/lapack

Wir arbeiten an einer Übersetzung von LAPACK in .NET. Wir haben einen FORTRAN-Compiler geschrieben, der das gesamte LAPACK, einschließlich aller Tests, erfolgreich übersetzt. Bei echten Datentypen bestehen (fast) alle Tests. Bei komplexen Daten sehen wir immer noch einige Präzisionsprobleme.

Beispiel:
XEIGTSTZ < zec.in - schlägt fehl wegen Unterlauf in ZLAHQR.
Schritte zur Reproduktion: ZGET37 -> knt == 31, ZHSEQR -> ZLAHQR -> am Ende des zweiten QR-Schritts (ITS == 2) verursacht folgender Code einen Unterlauf (bei bestimmten Registern, siehe unten)

TEMP = H( I, I-1 )
    IF( DIMAG( TEMP ).NE.RZERO ) THEN
        RTEMP = ABS( TEMP)    ! <-- underflow on TEMP = (~1e-0173, ~1e-0173)
        IF (RTEMP .EQ. RZERO) RTEMP = CABS1(TEMP)
        H( I, I-1 ) = RTEMP
        TEMP = TEMP / RTEMP
        IF( I2.GT.I )

Unser Compiler zielt auf die .NET CLR ab. Sein JIT beschließt, SSE-Register für ABS(TEMP) zu verwenden, was zu einem Unterlauf bei der Zwischenberechnung der Größe führt. Ifort (als weiteres Beispiel) verwendet in dieser Situation Gleitkommaregister, daher keinen Unterlauf (wegen seiner größeren Länge: 80 Bit). Ich versuche, ein klares Bild davon zu bekommen, was von LAPACK zu erwarten ist, welche Genauigkeit / welchen Zahlenbereich es vom Compiler / Prozessor zur Laufzeit erfordert.

Sind alle Tests auf doppelte Genauigkeit so ausgelegt, dass sie mindestens 64-Bit-Register erfordern? Oder sind sie so konzipiert, dass sie für die heute verfügbaren populären FORTRAN-Compiler erfolgreich sind? (Im ersten Fall kann das oben genannte Problem (und ähnliche andere) Aufmerksamkeit erfordern. Soll ich ein Problem für sie einreichen?)

Ich habe nach einer Spezifikation gesucht, aber noch nicht gefunden. Jeder Link wäre auch dankbar. Danke im Voraus!

Question

Alle 16 Kommentare

Der Unterlauf selbst ist nicht das wahre Problem. Nach einem Unterlauf wechselt der Algorithmus zu CABS1, das weniger anfällig für Unterlauf ist. Das Problem, das entsteht, ist, dass TEMP nicht genau einheitlich ist, was zu einer Rundung in Z führt.

Eine mögliche Lösung besteht darin, mit CABS1 vorzuskalieren und dann mit ABS zu korrigieren (aufgrund der ersten Skalierung sollte ABS nicht mehr überlaufen). (Ich bekomme den Unterlauf auf meinem Computer nicht, also kann ich es nicht für Sie testen)

IF (RTEMP .EQ. RZERO) THEN
    RTEMP = CABS1(TEMP)
    H( I, I-1 ) = RTEMP
    TEMP = TEMP / RTEMP
    RTEMP = ABS( TEMP)
    H( I, I-1 ) = H( I, I-1 )*RTEMP
    TEMP = TEMP / RTEMP
END IF

Ich denke, die Tests sind definitiv darauf ausgelegt, für die Gruppe der gängigen FORTRAN-Compiler erfolgreich zu sein, weil sie einfach so ausgeführt werden. Unter-/Überlauf vorherzusagen ist unglaublich schwer. Zumindest in meinem Fall werden diese Subroutinen entworfen, indem man sie einfach gründlich testet (mit den gängigen Compilern) und jeden Über-/Unterlauf, den wir finden, korrigiert.

Dankeschön! Das ist sehr hilfreich.
Wir hatten versucht, uns mit CABS1 von einem Unterlauf zu erholen. Aber unser Versuch ging nicht weit genug. Dein Vorschlag scheint viel besser zu sein. Verwenden ...

*
*        Ensure that H(I,I-1) is real.
*
         TEMP = H( I, I-1 )
         IF( DIMAG( TEMP ).NE.RZERO ) THEN
            RTEMP = ABS( TEMP)
            IF (RTEMP .EQ. RZERO) THEN 
                RTEMP = CABS1(TEMP)
                H( I, I-1 ) = RTEMP
                TEMP = TEMP / RTEMP
                RTEMP = ABS( TEMP)
                H( I, I-1 ) = H( I, I-1 )*RTEMP
            ELSE 
                H( I, I-1 ) = RTEMP
            END IF
            TEMP = TEMP / RTEMP
            IF( I2.GT.I )
     $         CALL ZSCAL( I2-I, DCONJG( TEMP ), H( I, I+1 ), LDH )
            CALL ZSCAL( I-I1, TEMP, H( I1, I ), 1 )
            IF( WANTZ ) THEN
               CALL ZSCAL( NZ, TEMP, Z( ILOZ, I ), 1 )
            END IF
         END IF
*
  130 CONTINUE

... diese Iteration erfolgreich abgeschlossen wird (auch wenn SSE-Register für ABS() verwendet werden).

Ich denke, die Tests sind definitiv darauf ausgelegt, für die Gruppe der gängigen FORTRAN-Compiler erfolgreich zu sein, weil sie einfach so ausgeführt werden. Unter-/Überlauf vorherzusagen ist unglaublich schwer. Zumindest in meinem Fall werden diese Subroutinen entworfen, indem man sie einfach gründlich testet (mit den gängigen Compilern) und jeden Über-/Unterlauf, den wir finden, korrigiert.

Die Testsuite ist eine enorme Hilfe! Meine grobe Schätzung ist, dass weit weniger als 1% der Tests von diesem oder ähnlichen Überlaufproblemen betroffen sind (bei Verwendung unseres Compilers). Die Tests noch robuster gegen Unter-/Überlauf zu machen, könnte dazu beitragen, LAPACK auf mehr Plattformen zu bringen. Unser (fehlgeschlagener) Versuch oben ist nur ein Beispiel, das deutlich zeigt, dass wir auf unserer Seite kaum eine Lösung finden würden. Bevor ich mehrere verwandte Themen öffne, möchte ich eine Diskussion beginnen, ob Interesse an einer solchen Reise besteht oder nicht und was ein guter Ansatz wäre.

Danke für die Verbesserung @hokb und @thijssteel! Soll ich eine PR mit den Modifikationen schreiben oder bist du dazu bereit, @hokb?

Angesichts meiner begrenzten Erfahrung mit dem Projekt würde ich Ihre Bemühungen und die Möglichkeit zu schätzen wissen, Ihre PR als Richtlinie für Pot zu nehmen. zukünftige PRs von uns... (wenn das ok ist?)

Hallo @hokb ,

Ich habe nach einer Spezifikation gesucht, aber noch nicht gefunden. Jeder Link wäre auch dankbar. Danke im Voraus!

Ich bin mir nicht sicher, ob irgendwo etwas angegeben ist.

Unser Compiler zielt auf die .NET CLR ab. Sein JIT beschließt, SSE-Register für ABS(TEMP) zu verwenden, was zu einem Unterlauf bei der Zwischenberechnung der Größe führt. Ifort (als weiteres Beispiel) verwendet in dieser Situation Gleitkommaregister, daher keinen Unterlauf (wegen seiner größeren Länge: 80 Bit). Ich versuche, ein klares Bild davon zu bekommen, was von LAPACK zu erwarten ist, welche Genauigkeit / welchen Zahlenbereich es vom Compiler / Prozessor zur Laufzeit erfordert.

Fettgedruckte Aussage: Wenn alle Berechnungen mit IEEE 64-Bit-Arithmetik durchgeführt werden, sollte LAPACK funktionieren.

LAPACK erwartet nicht, dass das 80-Bit-Register jederzeit seine Berechnung unterstützt. Die Algorithmen sind auf 64-Bit-Arithmetik ausgelegt. Nun, wie von @thijssteel erwähnt , wird LAPACK mit verschiedenen Compilern/Architekturen getestet, und diese Compiler/Architekturen verwenden manchmal 80-Bit-Register, und wir denken vielleicht, dass unsere Algorithmen die ganze Zeit nur 64-Bit benötigen, aber das tun sie nicht, und sie erfordern tatsächlich ein 80-Bit.

Wir haben auf unserer Reise nichts systematisches unternommen, um diesen Problemen nachzugehen. Im Allgemeinen sind wir glücklich genug, wenn die Algorithmen die Testsuite bestehen, und wenn es etwas Hilfe vom 80-Bit-Register gibt, soll es so sein.

Sind alle Tests auf doppelte Genauigkeit so ausgelegt, dass sie mindestens 64-Bit-Register erfordern? Oder sind sie so konzipiert, dass sie für die heute verfügbaren populären FORTRAN-Compiler erfolgreich sind? (Im ersten Fall kann das oben genannte Problem (und ähnliche andere) Aufmerksamkeit erfordern. Soll ich ein Problem für sie einreichen?)

Meine grobe Schätzung ist, dass weit weniger als 1% der Tests von diesem oder ähnlichen Überlaufproblemen betroffen sind (bei Verwendung unseres Compilers).

Oh mein. 1%? Das ist eine erschreckend große Zahl.

Die Tests testen viel um den Unterlauf- und Überlaufbereich herum, so dass zu erwarten ist, dass die Tests dieses Problem viel wahrscheinlicher auslösen als der Code der Benutzer, aber immer noch.

Die Tests noch robuster gegen Unter-/Überlauf zu machen, könnte dazu beitragen, LAPACK auf mehr Plattformen zu bringen.

Die Portabilität auf mehr Plattformen ist in der Tat ein Interesse. Ein weiteres Interesse ist die erweiterte Genauigkeit mit Paketen wie GMP, bei denen die Genauigkeit, wie ich es verstehe, während der gesamten Berechnung festgelegt ist. (Also zum Beispiel sind Sie 256-Bit gedacht, und es gibt kein 300-Bit-Register, das Ihnen hilft.)

Unser (fehlgeschlagener) Versuch oben ist nur ein Beispiel, das deutlich zeigt, dass wir auf unserer Seite kaum eine Lösung finden würden. Bevor ich mehrere verwandte Themen öffne, möchte ich eine Diskussion beginnen, ob Interesse an einer solchen Reise besteht oder nicht und was ein guter Ansatz wäre.

Jawohl. Wir sind interessiert. Wir können jedoch nur so viel tun. Und wir haben viel auf unseren Tellern. Vielleicht nehmen wir dieses eine Thema nach dem anderen und sehen, wie weit wir gehen.

Auf jeden Fall ist es immer eine gute Idee, Issues auf dem GitHub zu posten. Es sensibilisiert für das Problem und hilft, Hilfe und Ideen zu sammeln, um die Probleme zu beheben.

Ich bin froh, dass wir diesen Weg gehen, aber ich würde empfehlen, es ruhig anzugehen.

Vielleicht sollten wir für gfortran zu Testzwecken mit den Flags -mfpmath=sse -msse2 kompilieren. Ich denke, dies erzwingt, dass alle Berechnungen mit 64-Bit-Arithmetik durchgeführt werden. Ich bin mir aber nicht sicher.

Angesichts meiner begrenzten Erfahrung mit dem Projekt würde ich Ihre Bemühungen und die Möglichkeit zu schätzen wissen, Ihre PR als Richtlinie für Pot zu nehmen. zukünftige PRs von uns... (wenn das ok ist?)

Sicher! Siehe #577.

@weslleyspereira Genial ! Ich überprüfe noch, ob dies auch für CLAHQR gilt. Werde mein Ergebnis so schnell wie möglich posten (morgen)

Hallo @langou !

Fettgedruckte Aussage: Wenn alle Berechnungen mit IEEE 64-Bit-Arithmetik durchgeführt werden, sollte LAPACK funktionieren.

Schön! Ich nehme an, mit "Arbeit" meinen wir: Wenn es mit Daten "in einem bestimmten Bereich" gefüttert wird, wird es aufgrund einer bestimmten Registergröße nicht überlaufen?

LAPACK erwartet nicht, dass das 80-Bit-Register jederzeit seine Berechnung unterstützt. Die Algorithmen sind auf 64-Bit-Arithmetik ausgelegt. Nun, wie von @thijssteel erwähnt , wird LAPACK mit verschiedenen Compilern/Architekturen getestet, und diese Compiler/Architekturen verwenden manchmal 80-Bit-Register, und wir denken vielleicht, dass unsere Algorithmen die ganze Zeit nur 64-Bit benötigen, aber das tun sie nicht, und sie erfordern tatsächlich ein 80-Bit.

Wir haben auf unserer Reise nichts systematisches unternommen, um diesen Problemen nachzugehen. Im Allgemeinen sind wir glücklich genug, wenn die Algorithmen die Testsuite bestehen, und wenn es etwas Hilfe vom 80-Bit-Register gibt, soll es so sein.

Klingt sehr vernünftig!

Meine grobe Schätzung ist, dass weit weniger als 1% der Tests von diesem oder ähnlichen Überlaufproblemen betroffen sind (bei Verwendung unseres Compilers).

Oh mein. 1%? Das ist eine erschreckend große Zahl.

Nun, wahrscheinlich ist es "weit weniger" als das ;)

Die Portabilität auf mehr Plattformen ist in der Tat ein Interesse. Ein weiteres Interesse ist die erweiterte Genauigkeit mit Paketen wie GMP, bei denen die Genauigkeit, wie ich es verstehe, während der gesamten Berechnung festgelegt ist. (Also zum Beispiel sind Sie 256-Bit gedacht, und es gibt kein 300-Bit-Register, das Ihnen hilft.)

Klingt interessant, aber dazu kann ich nichts sagen, da mir die Erfahrung mit solchen festen Präzisionsversuchen fehlt.

Jawohl. Wir sind interessiert. Wir können jedoch nur so viel tun. Und wir haben viel auf unseren Tellern. Vielleicht nehmen wir dieses eine Thema nach dem anderen und sehen, wie weit wir gehen.

Ich bin mir immer noch unsicher, was ein guter allgemeiner Ansatz wäre. Bloß mit mir, wenn mein Verständnis zu naiv ist. Aber hängt der Über-/Unterlauf nicht immer von beidem ab: Eingabedaten und Algorithmus? Anstatt den Code mit neuen Bedingungstests und neuem Code zum Wiederherstellen zu überfluten, könnten wir stattdessen den "erlaubten Bereich" für die Eingabedaten verringern? Ich habe jedoch nicht den notwendigen Einblick in den Aufwand, der für beide Ansätze erforderlich ist. Daher kann ich nicht beurteilen, was machbarer wäre.

Auf jeden Fall ist es immer eine gute Idee, Issues auf dem GitHub zu posten. Es sensibilisiert für das Problem und hilft, Hilfe und Ideen zu sammeln, um die Probleme zu beheben.

Gut. Wir werden Probleme nachreichen, während wir gehen. Ich verstehe, dass es eine Herausforderung sein wird, einen Fix zu finden, ohne einen Unterlauf reproduzieren zu können. Welche Informationen können wir also zur Verfügung stellen, um das Problem klarer zu machen? Hilft der Weg hinunter zum Betonunterlauf? Dh: Iterationszähler, aktuelle Werte von Locals zusammen mit Dateinamen usw. bereitstellen?

Ich bin froh, dass wir diesen Weg gehen, aber ich würde empfehlen, es ruhig anzugehen.

Das selbe hier! :)

Ein Ergebnis von #577 ist, dass LAPACK auf den FORTRAN-Compiler angewiesen ist, um eine einigermaßen robuste (Unter-/Überlauf) komplexe Division und ABS() zu implementieren. Ich frage mich, ob wir anfangen sollten, ein Dokument zu pflegen und solche und ähnliche Anforderungen zu sammeln? Sie sind gleichermaßen wichtig und nützlich für alle, die LAPACK mit anderen / neuen Compilern verwenden möchten, für Compiler-Builder und um Teile oder alle LAPACK-Algorithmen auf andere Sprachen zu übertragen?

Sicher! Es ist gut, wenn diese Informationen gut dokumentiert sind.

Zu Beginn habe ich einige Zeit damit verbracht, (vielleicht) alle Divisionen in den Dateien LAPACK/SRC/z*.f (KOMPLEX*16 Algorithmen) des Formulars zu verfolgen

 REAL / COMPLEX   or   COMPLEX / COMPLEX

Ich habe insgesamt 53 Dateien gefunden. Siehe die angehängte Datei: complexDivisionFound.code-search

  • Dafür habe ich den REGEX-Ausdruck im Visual Studio Code verwendet:

    \n .*/ ^0-9 (?!DBLE)(?!REAL)(?!MIN)(?!MAX)[^0-9]

Vielleicht sollten wir für gfortran zu Testzwecken mit den Flags -mfpmath=sse -msse2 kompilieren. Ich denke, dies erzwingt, dass alle Berechnungen mit 64-Bit-Arithmetik durchgeführt werden. Ich bin mir aber nicht sicher.

Ja, das sollte bei Verwendung von GCC der Fall sein, aber dieses Flag sollte auch standardmäßig auf x86-64 gesetzt sein. Der unten stehende Dokumentationsauszug gilt für GCC 11, aber viel ältere GCC-Versionen sollten das gleiche Verhalten zeigen. Verwenden der GNU Compiler Collection (GCC): 3.19.59 x86-Optionen

sse

Verwenden Sie skalare Gleitkommabefehle, die im SSE-Befehlssatz vorhanden sind. Dieser Befehlssatz wird von Pentium III und neueren Chips und in der AMD-Reihe von Athlon-4-, Athlon XP- und Athlon MP-Chips unterstützt. Die frühere Version des SSE-Befehlssatzes unterstützt nur Arithmetik mit einfacher Genauigkeit, daher werden die Arithmetik mit doppelter und erweiterter Genauigkeit immer noch mit 387 ausgeführt. Eine spätere Version, die nur in Pentium 4- und AMD x86-64-Chips vorhanden ist, unterstützt Arithmetik mit doppelter Genauigkeit auch.

Für den x86-32-Compiler müssen Sie die Schalter -march=cpu-type , -msse oder -msse2 , um SSE-Erweiterungen zu aktivieren und diese Option wirksam zu machen. Für den x86-64-Compiler sind diese Erweiterungen standardmäßig aktiviert.

Der resultierende Code sollte in den meisten Fällen erheblich schneller sein und die numerischen Instabilitätsprobleme des 387-Codes vermeiden, kann jedoch einen Teil des vorhandenen Codes beschädigen, der temporäre 80 Bits erwartet.

Dies ist die Standardauswahl für den x86-64-Compiler, Darwin x86-32-Ziele und die Standardauswahl für x86-32-Ziele mit dem SSE2-Befehlssatz, wenn -ffast-math aktiviert ist.

Beispiel:
XEIGTSTZ < zec.in - schlägt fehl wegen Unterlauf in ZLAHQR.
Schritte zur Reproduktion: ZGET37 -> knt == 31, ZHSEQR -> ZLAHQR -> am Ende des zweiten QR-Schritts (ITS == 2) verursacht folgender Code einen Unterlauf (bei bestimmten Registern, siehe unten)

TEMP = H( I, I-1 )
    IF( DIMAG( TEMP ).NE.RZERO ) THEN
        RTEMP = ABS( TEMP)    ! <-- underflow on TEMP = (~1e-0173, ~1e-0173)
        IF (RTEMP .EQ. RZERO) RTEMP = CABS1(TEMP)
        H( I, I-1 ) = RTEMP
        TEMP = TEMP / RTEMP
        IF( I2.GT.I )

Unser Compiler zielt auf die .NET CLR ab. Sein JIT beschließt, SSE-Register für ABS(TEMP) zu verwenden, was zu einem Unterlauf bei der Zwischenberechnung der Größe führt. Ifort (als weiteres Beispiel) verwendet in dieser Situation Gleitkommaregister, daher keinen Unterlauf (wegen seiner größeren Länge: 80 Bit). Ich versuche, ein klares Bild davon zu bekommen, was von LAPACK zu erwarten ist, welche Genauigkeit / welchen Zahlenbereich es vom Compiler / Prozessor zur Laufzeit erfordert.

Um es zusammenzufassen:

  • Sie haben eine halbe Million Zeilen Fortran77 in C# transpiliert.
  • Das Testen des transpilierten Codes schlägt fehl, wenn der .NET-Just-in-Time-Compiler verwendet wird.
  • Das Testen des Vanilla-LAPACK-Codes ist erfolgreich, wenn der Intel Fortran-Compiler (ifort) verwendet wird.
  • Der beobachtete Unterschied zwischen den beiden Fällen ist die Verwendung von 80-Bit-Zwischenprodukten durch ifort, die einen Unterlauf vermeidet.

Richtig?

Standardmäßig generiert GCC nur Code für 64-Bit-Float-Register auf x86-64 und auf meinen Computern bestehen normalerweise alle LAPACK-Tests außer einem oder zwei.

Besteht die Netlib LAPACK Testsuite beim Kompilieren mit GCC?

edit: gelöst https://github.com/Reference-LAPACK/lapack/pull/577#issuecomment -859496175

Vielleicht sollten wir für gfortran zu Testzwecken mit den Flags -mfpmath=sse -msse2 kompilieren. Ich denke, dies erzwingt, dass alle Berechnungen mit 64-Bit-Arithmetik durchgeführt werden. Ich bin mir aber nicht sicher.

Ich habe -mfpmath=sse -msse2 mit GCC 11 auf MacOS und Linux ausprobiert: https://github.com/weslleyspereira/lapack/actions/runs/966071530. Im Vergleich zum Workflow ohne diese Flags gab es keine zusätzlichen Fehler: https://github.com/Reference-LAPACK/lapack/actions/runs/945060330. Siehe #591

@hokb , könnten Sie die in https://github.com/Reference-LAPACK/lapack/issues/575#issuecomment -855880000 erwähnten Überlaufprobleme mit GCC mit SSE-Flags reproduzieren? Können Sie mir damit helfen?

@weslleyspereira Ich habe GCC noch nicht einmal ausprobiert. Alles, wofür ich Zugriff auf / ein laufendes Setup habe, ist ifort unter Windows. Es würde einige Tage dauern, bis ich GCC über cygwin zum Testen zum Laufen gebracht habe (besonders von meinem aktuellen Ferienhotelzimmer aus ... :| ) Lassen Sie mich jedoch wissen, ob ich diese Herausforderung annehmen soll!
Zumindest und laut https://godbolt.org/z/YYv5oPxe9 hat die Verwendung der Flags keinen Einfluss auf den von gfortran generierten Code. Aber das wird natürlich nur ein Testlauf zeigen...

Ich benutze kein Windows, aber ich habe es hier. Ich werde damit beginnen, LAPACK mit ifort auf meinem Ubuntu zu testen und zu sehen, was passiert. Genieße den Urlaub!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen