C++Guns – RoboBlog blogging the bot

08.07.2019

C++ Guns: std::ofstream better err msg

Filed under: Allgemein — Tags: — Thomas @ 20:07

Folgender Fetzen Code gibt eine gescheite Fehlermeldung für streams (wann fixen die endlich streams & exceptions?)

    auto fileName = std::string(getenv("HOME")) + "/config/clusterprocessaccounting.dat";
    std::ofstream f(fileName);
    if(not f) throw std::system_error(errno, std::system_category(), "failed to open " + fileName + " ");

terminate called after throwing an instance of 'std::system_error'
what(): failed to open /home/ite/config/clusterprocessaccounting.dat : No such file or directory

04.07.2019

C++ Guns: Fingerübung: can convert double to int?

Filed under: Allgemein — Tags: — Thomas @ 09:07

Wir bekommen öfter mal große integer Zahlen als double gespeichert in den Daten. Beim konvertieren nach Text (andere story) mit 6 signifikanten Ziffern und wissenschaftlicher Darstellung fallen Ziffern weg. Obwohl die wissenschaftliche Darstellung mit einem Exponent bei ganzen Zahlen nicht nötig wäre.

Fingerübung: Schreibe eine Funktion die true zurück gibt, wenn die übergebene double Zahl in ein 32bit signed integer, ohne Verluste, passt.

Da es UB ist, eine zu große double Zahl einem int zuzuweisen (mit constexpr überprüft), ist die Aufgabe nicht ganz so trivial.

constexpr int xxx = std::numeric_limits<int>::max()+1.0; // error: overflow in constant expression

Noch dazu kann ein Integer mehr negative Zahlen als positive Speichern (Die Null zähl mit). Und es gibt natürlich noch Inf und Nan.
Nach drei Versuchen sieht der Code nun wie folgt aus. constexpr Test inklusive.

#include <limits>
#include <cmath>

constexpr inline bool canConvertToInt(double d) {
  if(std::isnan(d) or std::isinf(d)) return false;
  if(d > 0) {
    return d <= std::numeric_limits<int>::max() and d-int(d)==0;
  } else {
    return d >= std::numeric_limits<int>::min() and d-int(d)==0;
  }
}

  static_assert(canConvertToInt(std::numeric_limits<int>::max()-1));
  static_assert(not canConvertToInt(std::numeric_limits<int>::max()-1 + 0.5));
  static_assert(canConvertToInt(std::numeric_limits<int>::max()));
  static_assert(not canConvertToInt(std::numeric_limits<int>::max()+0.5));

  static_assert(canConvertToInt(std::numeric_limits<int>::min()+1));
  static_assert(not canConvertToInt(std::numeric_limits<int>::min()+1-0.5));
  static_assert(canConvertToInt(std::numeric_limits<int>::min()));
  static_assert(not canConvertToInt(std::numeric_limits<int>::min()-0.5));

  static_assert(not canConvertToInt(std::numeric_limits<double>::infinity()));
  static_assert(not canConvertToInt(std::numeric_limits<double>::quiet_NaN()));
  static_assert(not canConvertToInt(std::numeric_limits<double>::signaling_NaN()));
  static_assert(not canConvertToInt(std::numeric_limits<double>::denorm_min()));

Der Praxistest kann beginnen.

22.06.2019

C++ Guns: 2019-06 pre-Cologne Paper - funny one

Filed under: Allgemein — Tags: — Thomas @ 08:06

P1770R0: On vectors, tensors, matrices, and hypermatrices - Wirklich jeder sollte diese kurze Präsentation einmal durchschauen. Ich habe den Eindruck, als hätte mindestens ein Mensch auf der Welt Ahnung von dem Thema.

P1764R0: ssize Should be Named count - Kurz und kompakt

P0631R7: Math Constants ENDLICH!

P1768R0: Contiguous Containers Should Contain .data() - Ja

P1751R0: Numeric Type Families - Ich weiss nicht ob ich integer will die Overhead mitbringen

P1717R0: Compile­time Metaprogramming in C++ - Zu lang zum lesen jetzt

P1708R0: Simple Statistical Functions - Sehr gut! Im Kontrast zu acpl

P1709R0: Graph Data Structures - Wow, viel Stuff. Das muss ich mal mit acpl::Graph vergleichen

P1682R0: std::to_underlying for enumerations - Siehe auch std::underlying_type

P1680R0: Implementing Contracts in GCC - Nice! Unbedingt zeitnah mal ausprobieren

P1672R0: “Axiom” is a False Friend - !

P1429R2: Contracts That Work

p1744r0: Avoiding Misuse of Contract-Checking - To read

p1743r0: Contracts, Undefined Behavior, and DefensiveProgramming - To read

P1645R0: constexpr for algorithms constexpr ftw

P0037R7: Fixed-Point Real Numbers

P0267R9: A Proposal to Add 2D GraphicsRendering and Display to C++

P1467R1: Extended floating-point types 16bit floats, ARM, GPU

P1331R1: Permitting trivial default initialization in constexpr contexts

P1301R3: [[nodiscard("should have a reason")]] - Warum nicht

P1280R2: Integer Width Literals

P1068R1: Vector API for random number generation

P1050R1: Fractional Numeric Type

P1030R2:std::filesystem::path_view

P1021R4: Filling holes in Class Template Argument Deduction

P0784R6: More constexpr containers

P0533R5: constexpr for and

Mehr...
2019-06 pre-Cologne mailing available (1 of 2)
2019-06 pre-Cologne mailing available (2 of 2)

09.06.2019

C++ Guns: std::filesystem und std::regex

Filed under: Allgemein — Tags: — Thomas @ 07:06

Heute mache ich die ersten Versuche mit std::filesystem und std::regex. Der GCC 8.1 ist installiert. Die Doku liegt bereit. Es kann los gehen.

std::filesystem

Ich möchte bestimmte "Müll" Dateien im Projekt Verzeichnis auflisten und ihren Speicherplatzverbrauch summieren. Die Handhabung von std::filesystem ist wirklich erstaunlich einfach. Klar strukturiert. Es funktioniert. Etwas, dass böse Zungen von std::chrono ja nicht behaupten.

Eine Schleife über alle Dateien in einem Verzeichnis geht echt fix:

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
for(auto& p: fs::recursive_directory_iterator("/", fs::directory_options::skip_permission_denied)) {
    if(p.is_regular_file()) {
        std::cout << p.path().filename() << " " << p.file_size() << '\n';
    }
}

Bis GCC 8 muss das Projekt noch explizit mit -lstdc++fs, ab GCC 9 dann nicht mehr.

Achtung: Beim GCC 8.1 und Netzlaufwerke hab ich festgestellt, dass is_regular_file() falsche Werte zurück gibt. Im Vergleich zu fs::is_regular_file(fs::status(p)), was das selbe macht. Ob das im GCC 9.1 auch so ist, muss ich noch prüfen.

Die Fehlerbehandlung ist auch nett gelöst. Man hat diesmal die Auswahl zwischen Exception und Error Code. Viele Funktionen kann ein error_eode Objekt übergeben werden (als Referenz nicht als Pointer woohoo!).

std::error_code ec;
for(auto& p: fs::recursive_directory_iterator("/", fs::directory_options::skip_permission_denied, ec)) {
if(e) {
    std::cout << e.message();

Oder mit Exception.

try {            
    if(fs::is_regular_file(fs::status(p))) {
    }
catch(fs::filesystem_error& err) {
    std::cerr << err.what() << "\n";
}

Als keiner Bonus hier meine std::filesystem::file_type ostream Funktion

std::ostream& operator<<(std::ostream& s, const std::filesystem::file_type type) {
    using std::filesystem::file_type;
    switch (type) {
    case file_type::none:      s << "none"; break;
    case file_type::not_found: s << "not_found"; break;
    case file_type::regular:   s << "regular"; break;
    case file_type::directory: s << "directory"; break;
    case file_type::symlink:   s << "symlink"; break;
    case file_type::block:     s << "block"; break;
    case file_type::character: s << "character"; break;
    case file_type::fifo:      s << "fifo"; break;
    case file_type::socket:    s << "socket"; break;
    case file_type::unknown:   s << "unknown"; break;
    }
    return s;
}

std::regex

Regex ist auch garnicht sooo schwer, wenn man es mal kann. Ich möchte alle Dateien dieser Form finden: dbg_0000 dbg_0001 u.s.w. Das passende Regex Objekt sieht dann so aus:

const std::regex dbg_regex("dbg_[[:digit:]]+");

for(auto& p: fs::recursive_directory_iterator("/", fs::directory_options::skip_permission_denied)) {
    if(p.is_regular_file()) {
       if(std::regex_match(p.path().filename().c_str(), dbg_regex)) {
           // found
       }
    }
}

Als Verbindung zwischen Dateiname und Regex dient C-String. Da es string_view hier (noch?) nicht gibt.

01.06.2019

C++Guns: RE: C++ Core Guidelines: std::array und std::vector sind die erste Wahl

Filed under: Allgemein — Tags: — Thomas @ 09:06

Ich finde es schade, dass der Artikel von Rainer Grimm bei heise.de C++ Core Guidelines: std::array und std::vector sind die erste Wahl so wenig Beachtung bekommt. Er wirft nicht nur ein paar interessante Fragen auf, sondern geht auf der Kernaussage von Performance ein: Don't think, use std::vector.

Natürlich hat sich der C++ Gründervater Bjarne Stroustrup schon seit Jahren (Jahrzehnten?) mit dem Thema beschäftigt. Es lohnt sich nachzulesen in Are lists evil?

Zuallererst: Benchmarks sind super schwer und keiner kann sie richtig machen. Daher werde ich im ersten Schritt
nur versuchen die Ergebnisse auf meinem Laptop nachzuvollziehen. Und im zweiten Schritt die Datenmenge oder die
Anzahl Zugriffe erhöhen, da eine Laufzeit von 0.07 Sekunden doch sehr gering ist. Da Linux ein Multiuser/Multithread
Betriebssystem ist, passiert allerlei Nebenbei. Und diese "Störungen" versuche ich durch eine längere Messzeit
zu auszublenden.

1) Reproduzieren
1.a) Erster Versuch
Beispiel Code runter laden, compilieren, starten, "Killed".

1.b)
Ich habe nicht genug RAM oder der RAM ist zugemüllt -_- Im Beispiel Code werden 100 Millionen Integer a 4 Byte
als Nutzdaten angegeben. Das ergibt ein Speicherverbrauch von _mindestens_ 400MB. std::vector und std::deque
funktionieren noch. Bei std::list steigt das Programm aus.
Der Grund ist einfach. Während std::vector einfach 400MB am Stück allokiert, passiert bei std::list schon mehr.
Ich wage zu behaupten, dass für jedes neu eingefügte Element einmal extra Speicher auf dem Heap allokiert wird.
Damit ist der Speicher Overhead natürlich gigantisch und das Programm steigt aus.

1.c)
Ein kurzer Blick in den Systemmonitor Zeigt, dass das Programm Firefox natürlich einige GB im RAM belegt. Also das Programm
beenden und schon zeigen sich 20 Instanzen von mysql die jeweils 170MB belegen. Wozu brauche ich eine Datenbank?
Wusste gar nicht, dass so etwas installiert ist. Also mysqld Server deinstallieren und beenden.

1.d) Zweiter Versuch
Immerhin läuft std::list jetzt durch, aber bei std::forward_list bricht das Programm mit der Fehlermeldung ab:
*** Error in `./a.out': free(): invalid pointer: 0x00000000464a1320 ***
Das weitere beenden von Programmen welche viel Speicher verbrauchen führe zu einem Absturz des Systems...

1.e) Dritter Versuch
Nach einem Neustart werden "nur" 832 von 7680MB als belegt angezeigt. Diesmal hat es funktioniert!

std::vector
time: 0.0352953930
res: 4999774274

std::deque
time: 0.0827120400
res: 4999774274

std::list
time: 0.2975692830
res: 4999774274

std::forward_list
time: 0.3002444010
res: 4999774274

Damit kann ich die Werte reproduzieren. std::vector ist wie zu erwarten am schnellsten. Und std::forward_list ist langsamer als std::list.

2) Längere Laufzeit
Die Datenmenge zu erhöhen würde kein Sinn machen. Also werde ich die Summe statt nur einmal, gleich 100 mal bilden.
Die zu erwartende Laufzeit liegt damit von 4 bis 30 Sekunden.
Um einen Vergleich anzustellen wie die Laufzeiten der Container sich relativ zu std::vector verhalten:

1.000 std::ector
0.427 std::deque
0.119 std::list
0.118 std::forward_list

std::vector
time: 3.4487668950
res: 499993166900

std::deque
time: 7.2533651530
res: 499993166900

std::list
time: 28.2407733910
res: 499993166900

std::forward_list
time: 30.5225665430
res: 499993166900

Hier die neuen relativen Werte:
1.000 std::vector
0.475 std::deque
0.122 std::list
0.113 std::forward_list

Also std::forward_list ist _wirklich_ langsamer als std::list. Es bleibt ein Rätsel.

10.05.2019

C++ Guns: play with threads and future

Filed under: Allgemein — Tags: — Thomas @ 13:05

Um schnell zu testen ob ein Rechner erreichbar ist, kann man ihn pingen. Der ping timeout dauert aber gern mal eine Sekunde. Wenn 10 Rechner nicht erreichbar sind, wartet man auch 10 Sekunden auf das Programm. Statt potentiell nur eine Sekunde. Die ping Anweisung kann man gut parallel ausführen. Zeit für std::async und std::future

Hier mein Beispiel, mit etwas Spielwiese:

#include <cstdlib>
#include <iostream>
#include <future>
#include <thread>
#include <string_view>

auto status(std::string_view host) {
  auto command = "ping -W 1 -c 1 " + std::string(host) + " >/dev/null 2>&1";
  return std::pair{std::system(command.c_str()), host};
}

auto red() {
  return "\033[32m";
}

auto green() {
  return "\033[31m";
}

auto reset() {
  return "\033[0m";
}

std::ostream& operator <<(std::ostream& s, const std::pair<int, std::string_view> p) {
  s << p.second << " ";
  if(p.first == 0) {
      s << red() << "UP " << reset();
    } else {
      s << green() << "down " << reset();
    }
  return s;
}

int main() {
    std::future f01 = std::async(std::launch::async, status, "rechner01");
    std::future f02 = std::async(std::launch::async, status, "rechner02");
    std::future f03 = std::async(std::launch::async, status, "rechner03");
    // ... 
    f01.wait();
    f02.wait();
    f03.wait();
    // ...
    std::cout << f01.get() << f02.get() << f03.get() << "\n";

}

C++ Guns: C++20 class types in non-type template parameters

Filed under: Allgemein — Tags: — Thomas @ 12:05

Mit C++20 und GCC9 wir können als Template Parameter nun auch einfach eigenen Typen angeben. Ohne uns mit Workarounds herumschlagen zu müssen.

Ein einfaches Beispiel sollte es verdeutlichen

struct MyType {
    int value;
};

template<MyType x>
auto func2() {
  return x.value;
} 

auto func3() {
    func2<MyType{1}>();
    constexpr MyType x{2};
    return func2<x>();
}

01.05.2019

ACCU 2019 Videos

Filed under: Allgemein — Tags: — Thomas @ 19:05

very nice! So Zeug hab ich bei meiner BA gebracht
Optimising a small real-world C++ application - Hubert Matthews [ACCU 2019]

This is a hands-on demonstration of optimising a small real-world application written in C++. It shows how measurement tools such as strace, perf tools, valgrind and cachegrind on Linux can be used to find the hotspots in an application. It also demonstrates some common pitfalls and how to avoid them by using different algorithms or libraries.

Contracts sind die Zukunft. Anschauen!
Programming with Contracts in C++20 - Björn Fahller [ACCU 2019]

Design by Contract is a technique to clearly express which parts of a program has which responsibilities. In the case of bugs, contracts can mercilessly point a finger at the part that violated the contract. Contracts are coming as a language feature in C++20. I will show how they can make your interfaces clearer with regards to use, but also point out pitfalls and oddities in how contracts are handled in C++. Writing good contracts can be difficult. I intend to give you guidance in how to think when formulating contracts, and how to design your interfaces such that good contracts can be written, because contracts have effects on interface design.

Genau meine Rede!
Better embedded library interfaces with modern C++ - Wouter Van Ooijen [ACCU 2019]

Traditionally, embedded applications are written in C. Using C++ is often frowned upon, because it is assumed to be less efficient. This talk shows how the interface of a typical embedded library can be made safer and more user-friendly, without being less efficient. Starting from a C-style interface modern C++ features are applied, like namespace, enum class, overloading, default argument values, std::byte, std::array, and templates.

Interessant
Audio in standard C++ - Timur Doumler [ACCU 2019]

Today, almost every computer, tablet and phone comes with audio input and output. Computer games and many other kinds of applications would be unthinkable without sound. Yet, the C++ language has no notion of it. Literature on audio in C++ is sparse. For even the simplest possible audio functionality, programmers need to deal with a confusing landscape of complex platform-specific APIs and proprietary 3rd party libraries. But audio in C++ doesn’t have to be hard!

Wow! Details von einem Profi
How C++20 Can Simplify std::tuple - Alisdair Meredith [ACCU 2019]

std::tuple has been the source of many presentations over the years, as the library specification glosses over a variety of implementation pitfalls, while successive standards increase the complexity. C++20 finally provides a number of features that, when combined, can yield a much simpler solution, saving developers of generic wrapper types from layers of expert-only code. This talk will show how applying the new Concepts language feature, in conjunction with new attributes and some extended syntax, enable the delivery of an optimized high performance implementation that is almost as simple as just declaring a class with a few data members. No metaclasses required!

Wichtig.
Implementing Physical Units Library for C++ - Mateusz Pusz [ACCU 2019]
Das ist nicht der erste Versuch eine unit library zu erstellen. Aber der erste den ich kenne der C++20 integiert. Aber keiner schafft es so richtig zu einem zufriedenstellenden Ergebnis.

This talk will present the current state of my work on designing and implementing Physical Units Library for C++. I will present all the challenges, design tradeoffs, and potential solutions to those problems. During the lecture, we will also see how new C++20 features help to make the library interface easier to use, maintain, and extend. Among others, we will see how we can benefit from class types provided as non-type template parameters, how new class template argument deduction rules simplify the interfaces, and a full power of using concepts to constrain template types.

Sehr interessanter Vortrag - auch wenn ich kein Wort verstanden habe
Allocator-Aware (AA) Software - John Lakos [ACCU 2019]
Man sollte sich vorher das hier ansehen: Local (Arena) Memory Allocators Part 1 - John Lakos - Meeting C++ 2017
und dann diesen Vortrag Local (Arena) Allocators Part II - John Lakos - Meeting C++ 2017

The performance benefits of supplying local allocators are well-known and substantial [Lakos, ACCU’17]. Still, the real-world costs associated with orchestrating the integration of allocators throughout a code base, including training, supporting tools, enlarged interfaces (and contracts), and a heightened potential for inadvertent misuse cannot be ignored. Despite substantial upfront costs, when one considers collateral benefits for clients – such as rapid prototyping of alternative allocation strategies – the case for investing in a fully allocator-aware (AA) software infrastructure (SI) becomes even more compelling. Yet there remain many “concerns” based on hearsay or specious conjecture that is either overstated or incorrect.

Etwas trocken, aber es lohnt sich das mal zu lernen
Regular Types and Why Do I Care ? - Victor Ciura [ACCU 2019]

“Regular” is not exactly a new concept (pun intended). If we reflect back on STL and its design principles, as best described by Alexander Stepanov in his 1998 “Fundamentals of Generic Programming” paper or his lecture on this topic, from 2002, we see that regular types naturally appear as necessary foundational concepts in programming. Why do we need to bother with such taxonomies ? Well, the STL now informally assumes such properties about the types it deals with and imposes such conceptual requirements for its data structures and algorithms to work properly. The new Concepts Lite proposal (hopefully part of C++20) is based on precisely defined foundational concepts such as Semiregular, Regular, EqualityComparable, DefaultConstructible, LessThanComparable (strict weak ordering), etc. Formal specification of concepts is an ongoing effort in the ISO C++ Committee and these STL library concepts requirements are being refined as part of Ranges TS proposal (experimental/ranges/concepts). Recent STL additions such as string_view, tuple, reference_wrapper, as well as new incoming types for C++20 like std::span raise new questions regarding values types, reference types and non-owning “borrow” types. Designing and implementing regular types is crucial in everyday programing, not just library design. Properly constraining types and function prototypes will result in intuitive usage; conversely, breaking subtle contracts for functions and algorithms will result in unexpected behavior for the caller. This talk will explore the relation between Regular types (and other concepts) and STL containers & algorithms with examples, common pitfalls and guidance.

Ganz nett wenn man Zeit hat
How to Teach C++ and Influence a Generation - Christopher Di Bella [ACCU 2019]

Learning to correctly use C++ is not difficult: teaching proper C++ usage is where the challenge lies, and at some point in your career, you’ll need to teach someone something about C++. You may not be a university lecturer or on-site trainer, but you could find yourself helping a colleague with their problem, presenting at a lunch-time session, or even at a conference! Perhaps you are someone who contributes to the company style guide or 'Intro to Our Repo' manual.

14.03.2019

C++ Guns: floating point bit round - p0476r2 Bit-casting object representations

Filed under: Allgemein — Tags: — Thomas @ 10:03

C++20

Low-level code often seeks to interpret objects of one type as another: keep the same bits, but obtain an object of a different type. Doing so correctly is error-prone: using reinterpret_cast or union runs afoul of type-aliasing rules yet these are the intuitive solutions developers mistakenly turn to.

Attuned developers use aligned_storage with memcpy, avoiding alignment pitfalls and allowing them to bit-cast non-default-constructible types.

This proposal uses appropriate concepts to prevent misuse. As the sample implementation demonstrates we could as well use static_assert or template SFINAE, but the timing of this library feature will likely coincide with concept’s standardization.

Furthermore, it is currently impossible to implement a constexpr bit-cast function, as memcpy itself isn’t constexpr. Marking the proposed function as constexpr doesn’t require or prevent memcpy from becoming constexpr, but requires compiler support. This leaves implementations free to use their own internal solution (e.g. LLVM has a bitcast opcode).

We should standardize this oft-used idiom, and avoid the pitfalls once and for all.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0476r2.html
https://github.com/jfbastien/bit_cast/

Solange wir noch kein C++20 haben um Bit Manipulationen an Gleitkommazahlen vorzunehmen, muss memcpy herhalten.

  double value;

  // float -> integer 
  std::uint64_t n;
  std::memcpy(&n, &value, sizeof(value)); // no aliasing violation

  // Bit Manipulation an Variable 'n'
  // ...

  // integer -> float
  std::memcpy(&value, &n, sizeof(n));

06.03.2019

Profiler read/write miss Gedanken

Filed under: Allgemein — Tags: — Thomas @ 16:03

Profiler read/write miss Gedanken

write miss: unterscheiden zwischen permanenten und temporäre Daten:
Permanente Daten: wohl unausweichlich, denn die neuen Daten MÜSSEN ja vom Chache in den Hauptspeicher geschrieben werden.
Temporäre Daten: eventuell vermeidbar, wenn man sie an einer späteren Stelle im Code erstellt. Wann immer Daten in den Cache geschrieben werden, fliegen andere Daten raus die eventuell gerade erst aufwendig geladen wurden.

read miss: Unterscheiden zwischen permanent und temporären Daten:
Permanente Daten: wohl unausweichlich. wenn man über einen Datensatz iteriert der größer als der Cache ist, MÜSSEN die Daten vom Hauptspeicher in den Cache geladen werden.
Temporäre Daten: eventuell vermeidbar. Selbe Argumentation wie bei write miss.

Eine temporäre/local scope Variable wird erstellt und in den Cache geschrieben. Dabei fallen eventuell wichtige Daten aus dem Cache. Nun passieren andere Berechnungen die auch in den Cache geschrieben werden. Dabei kann die temp. Variable in den Hauptspeicher ausgelagert werden. Später muss sie wieder vom Hauptspeicher wieder in den Cache geladen werden.

Cache misses auf temporäre Daten womöglich vermeidbar. Auf permanente Daten wohl unvermeidlich. Sso kann es vorkommen, dass das Laden der Daten mehr Zeit kostet als die eigentlichen arithmetischen Berechnungen damit. Profiler die nur Zeiten anzeigen, können nicht benutzt werden um zu Entscheiden ob etwas optimiert werden kann.
Die Addressberechnung und das Laden der Daten in den Cache ist teuer. Vorallem wenn die Daten nicht hintereinander im RAM liegen.
Wenn 10 Werte aus 10 Container geladen werden, sind 10 Cache Zeilen belegt. Da immer Cachezeilen-Byte viele Daten geladen werden (64byte??)
Wenn ein struct a 10 Member geladen wird, geschieht nur Speicherzugriff an einer Stelle im RAM und es wird auch nur eine (oder wenige) Cache Zeilen belegt.
Cache Zeilen sind wertvoll. es gibt nur wenige davon (CPU abhängig).
Ganz schlimm ist es, wenn in der nächsten Iteration an ganz anderer Stelle im Array zugegriffen wird. Dann sind alle geladenen Cachezeilen ungültig. Auch bei kontinuierlicher RAM Benutzung.
(Das ist DAS Problem bei Dreiecksnetzten)
Faustformel: arithmetische Operation +-*/ kostet 1-40. Main RAM read kostet 100-500

« Newer PostsOlder Posts »

Powered by WordPress