Ich schreibe eine kleine Bibliothek für spärliche Matrixberechnungen, um mir beizubringen, die objektorientierte Programmierung bestmöglich zu nutzen. Ich habe wirklich hart daran gearbeitet, ein schönes Objektmodell zu haben, bei dem die Teile (dünne Matrizen und die Graphen, die ihre Konnektivitätsstruktur beschreiben) sehr locker gekoppelt sind. Meiner Meinung nach ist der Code viel erweiterbarer und für ihn wartbarer.
Es ist jedoch auch etwas langsamer als wenn ich einen stumpfen Ansatz gewählt hätte. Um die Nachteile dieses Objektmodells zu testen, habe ich einen neuen Matrixtyp mit geringer Dichte geschrieben, bei dem die Kapselung des zugrunde liegenden Diagramms aufgehoben wurde, um festzustellen, wie viel schneller das ausgeführt werden würde.
Anfangs sah es ziemlich trostlos aus; Der Code, auf den ich einst stolz war, lief 60% langsamer als eine Version ohne elegantes Softwaredesign. Aber ich konnte ein paar Optimierungen auf niedriger Ebene vornehmen - eine Funktion inlinieren und eine Schleife ein wenig ändern -, ohne die API überhaupt zu ändern. Mit diesen Änderungen ist es nur noch 20% langsamer als die Konkurrenz.
Was mich zu meiner Frage bringt: Wie viel Performanceverlust sollte ich in Kauf nehmen, wenn es bedeutet, dass ich ein schönes Objektmodell habe?
quelle
Antworten:
Nur sehr wenige wissenschaftliche Softwareentwickler verstehen gute Designprinzipien, daher entschuldige ich mich, wenn diese Antwort etwas langwierig ist. Aus Sicht der Softwareentwicklung ist es das Ziel des wissenschaftlichen Softwareentwicklers, eine Lösung zu entwerfen, die eine Reihe von Einschränkungen erfüllt, die häufig in Konflikt stehen .
Im Folgenden sind einige typische Beispiele für diese Einschränkungen aufgeführt, die möglicherweise auf den Entwurf Ihrer Bibliothek mit spärlicher Matrix angewendet werden:
Die Wissenschaftler konzentrieren sich zunehmend auf einige andere allgemeine Anforderungen aus dem Software-Engineering:
Möglicherweise benötigen Sie mehr oder weniger einer dieser Anforderungen. Wenn Sie versuchen, einen Gordon-Bell-Preis für Leistung zu gewinnen, sind auch Bruchteile eines Prozents relevant, und nur wenige der Juroren bewerten die Qualität Ihres Codes (solange Sie sie davon überzeugen können, ist es richtig). Wenn Sie versuchen, die Ausführung dieses Codes auf einer gemeinsam genutzten Ressource wie einem Cluster oder einem Supercomputer zu rechtfertigen, müssen Sie häufig Ansprüche bezüglich der Leistung Ihres Codes verteidigen, diese sind jedoch selten sehr streng. Wenn Sie versuchen, eine Veröffentlichung in einem Journal zu veröffentlichen, in der die Leistungssteigerungen Ihres Ansatzes beschrieben werden, müssen Sie zu Recht schneller als Ihre Konkurrenten sein, und 20% Leistung sind ein Kompromiss, den ich gerne für eine bessere Wartbarkeit und Wiederverwendbarkeit eingehen würde.
Wenn Sie auf Ihre Frage zurückkommen, sollte "gutes Design", das genügend Entwicklungszeit hat, niemals die Leistung beeinträchtigen. Wenn das Ziel darin besteht, Code so schnell wie möglich auszuführen, sollte der Code unter Berücksichtigung dieser Einschränkungen entworfen werden. Sie können Techniken wie Codegenerierung und Inline-Assemblierung verwenden oder hoch optimierte Bibliotheken verwenden, um Ihr Problem zu lösen.
Aber was ist, wenn Sie nicht genug Entwicklungszeit haben? Was ist gut genug? Nun, es kommt darauf an, und niemand wird in der Lage sein, Ihnen eine gute Antwort auf diese Frage zu geben, ohne mehr Kontext.
FWIW: Wenn Sie wirklich daran interessiert sind, Hochleistungs-Kernel mit spärlicher Matrix zu schreiben, sollten Sie sich mit einer optimierten PETSc-Installation vergleichen und mit ihrem Team zusammenarbeiten, wenn Sie sie schlagen. Sie würden gerne optimierte Kernel in die Bibliothek integrieren.
quelle
Es ist eine Frage, wofür du deine Zeit verbringst. Für die meisten von uns verbringen wir 3/4 der Zeit mit Programmieren und 1/4 der Zeit damit, auf Ergebnisse zu warten. (Ihre Zahlen können variieren, aber ich denke, die Zahl ist nicht völlig unbegründet.) Wenn Sie also ein Design haben, mit dem Sie doppelt so schnell programmieren können (3/4 einer Zeiteinheit statt 1,5 Zeiteinheiten), dann Sie can kann einen Leistungseinbruch von 300% verzeichnen (von 1/4 auf 1 Zeiteinheit) und Sie haben immer noch einen Vorsprung in Bezug auf die für die Lösung des Problems aufgewendete Echtzeit.
Auf der anderen Seite sehen Ihre Berechnungen bei Hochleistungsberechnungen möglicherweise anders aus, und Sie möchten möglicherweise mehr Zeit für die Optimierung Ihres Codes aufwenden.
Für mich scheinen 20% ein ziemlich guter Kompromiss zu sein, wenn Sie am Ende produktiver sind.
quelle
IMHO ist eine Strafe von bis zu 50% (aus welchem Grund auch immer) nicht so schlimm.
Tatsächlich habe ich einen Leistungsunterschied von 0-30% gesehen, der nur auf dem Typ des Compilers basiert. Dies gilt für die sparsame MatMult-Routine von PETSc für Matrizen, die sich aus FE-Diskretisierungen niedriger Ordnung ergeben.
quelle
Das Softwaredesign wird sich mit der Zeit nicht automatisch verbessern. Die Leistung wird. Sie erhalten die 20% mit Ihrer nächsten CPU zurück. Außerdem wird es durch ein gutes Softwaredesign einfacher, die Bibliothek in Zukunft zu erweitern oder zu verbessern.
quelle
Ein allgemeines Prinzip besteht darin, zuerst für ein gutes Design zu sorgen und dann die Leistung nur dann zu optimieren, wenn dies erforderlich ist . Anwendungsfälle, in denen eine Leistungssteigerung von 20% wirklich erforderlich ist, sind eher selten, wenn sie überhaupt auftreten.
quelle