top | item 38381295

(no title)

smacke | 2 years ago

Fortran can be faster than C because it has a more restrictive memory model (compiler can make more optimizations when it knows nothing else is aliasing some memory)

discuss

order

bee_rider|2 years ago

Fortran can’t be faster than C; you can write inline assembly kernels in C, you can add keywords to promise no aliasing, etc etc.

Fortran just has better syntax and defaults than C for this stuff. A devoted, expert C tuner with unlimited time on their hands can do anything. A grad student with like a year of experience can write a Fortran code that is almost as good, and finish their thesis. Or, a numerics expert can write a numerical code for their experiments and be reasonably sure that they are operating within a good approximation of the actual capabilities of their machine (if you are an expert on numerical computing and C+assembly, you can write a library like BLIS or gotoBLAS and become famous, but you have to be better than everybody else in two pretty hard fields).

IMO this is important to point out because somebody can bring a microbenchmark toy problem to show C beating Fortran easily. As long as they spend way more effort on the problem than it deserves.

smacke|2 years ago

I don't think anything here is in conflict with the statement that Fortran can be faster than C in some cases, but yes you're right that technically that should be qualified as naive Fortran can be faster than naive C

zokier|2 years ago

There is big difference here between portable ISO C vs C with compiler extensions and platform specifics.

hnlmorg|2 years ago

You can inline assembly in a lot of languages. However I’d argue that doing so is thus no longer writing code in that host language.

To put it another way, your comment is a little like saying Bash is just as fast as C because you can write shell scripts that inline assembled executables.

klez|2 years ago

Is there no way to apply such optimizations to C code as long as the developer adopts certain standards in writing code?

jerf|2 years ago

In principle yes, in practice, no. This is one of those places where our developer intuition fails us, and I fully include mine. It feels like it ought to be feasible, even now, but in practice it turns out that there are just so many ways to screw up that optimization without realizing it, with responsibility for it scattered between compilation units (which is to say it isn't even necessarily clearly one things fault, these can arise in interactions), and once it creeps in just a little bit it tends to spread so quickly, that in practice it is not practical to try to exclude the problems. You can't help but write some tiny crack it sneaks into.

This is part of why I'm in favor of things like Rust moving borrow checking into the langauge. In principle you can statically analyze all of that in C++ with a good static analyzer, in practice, it's a constant process of sticking fingers in broken dikes[1] and fighting the ocean. Sometimes you just need a stronger wall, not more fingers.

[1]: https://writingexplained.org/idiom-dictionary/finger-in-the-...

trealira|2 years ago

The main issue is that C doesn't have a way to pass arrays of any size to functions while preserving their type (the size is part of an array's type in C); by convention, one generally passes a pointer to its first element and a separate length parameter. A compiler cannot know that any two pointers do not point to the same location. Hence, it's harder to vectorize code like this, because each store to result[i] may affect arr1[i] or arr2[i]; in other words, the pointers might alias. In C89:

  /* They're all the same length */
  void add(float *result, float *arr1, float *arr2, size_t len)
  {
      size_t i;

      for (i = 0; i < len; ++i)
          result[i] = arr1[i] + arr2[i];
  }
The solution is supposed to be the "restrict" keyword, which informs the compiler that other pointers do not alias this one. It was added in C99. You declare a pointer that doesn't alias like this:

  float *restrict float_ptr;
If a restrict pointer is aliased by another pointer, the behavior is undefined.

https://en.wikipedia.org/wiki/Restrict

It's hard to judge the extent to which this helps. Apparently, when Rust annotated all its mutable references and Box<T> types with the LLVM equivalent of the "restrict" annotation, they exposed a lot of bugs in LLVM's implementation of it, because most C code doesn't use "restrict" pointers as extensively as Rust code uses mutable references and Boxes.

ReleaseCandidat|2 years ago

Theoretically with `restrict`, but that doesn't really help. But the biggest advantage of Fortran is it's support for multidimensional arrays, slices,...