# Performance, C vs. Fortran

**URL:** <https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461>\
**Category:** Uncategorized\
**Created:** [June 26, 2021, 7:32pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461 "2021-06-26T19:32:44Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![runningcrocodile](https://avatars.discourse-cdn.com/v4/letter/r/ac91a4/32.png) [@runningcrocodile](https://fortran-lang.discourse.group/u/runningcrocodile)\
**Post date:** [June 26, 2021, 7:32pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/1 "2021-06-26T19:32:44Z")

</div>

I recently found some old code I had used to solve the Poisson equation with a somewhat naive double loop relaxation method on a 2d grid. The C code is as follows:

```auto
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

void swap(double a[101][101], double b[101][101], int n)
{
  double swp[101][101];
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      swp[i][j] = a[i][j];
      a[i][j] = b[i][j];
      b[i][j] = swp[i][j];
    }
  }
}
double mmax(double phi[101][101], double phip[101][101], int n)
{
  double max = 0.0;
  double diff = 0.0;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      diff = abs(phi[i][j]-phip[i][j]);
      if (diff > max)
        max = diff;
    }
  }
  return max;
}
double rho(double x, double y)
{
  double s1 = 0.6;
  double e1 = 0.8;
	double s2 = 0.2;
	double e2 = 0.4;

	if (x > s1 && x < e1 && y > s1 && y < e1) {
		return 1.0;
	} else if (x > s2 && x < e2 && y > s2 && y < e2 ) {
		return -1.0;
	} else {
		return 0.0;
	}
}
void run(double toler, double a)
{
  double epsilon0 = 8.85e-12;
  double phi[101][101];
  double phip[101][101];
  memset(phip, 0, sizeof(phip[0][0])*101*101);
  memset(phi, 0, sizeof(phi[0][0])*101*101);

  double delta = 1.0;

  while (delta > toler) {
    for (int i=1; i < 100; i++) {
      for (int j=1; j < 100; j++) {
        phip[i][j] = (phi[i+1][j] + phi[i-1][j] +
                      phi[i][j+1] + phi[i][j-1])/4 +
                      pow(a,2.0)/(4.0 * epsilon0)*rho(i * a, j * a);
      }
    }
    delta = mmax(phi, phip, 101);
    swap(phi, phip, 101);

  }

}

int main(int argc, char *argv[])
{
  clock_t start = clock();
  run(1e-6, 0.01);
  clock_t end = clock();
  double total = ((double)(end - start)) / CLOCKS_PER_SEC;
  printf("Execution time: %f\n",total);
}

```

I decided to write it in Fortran to see how it does performance wise. And the Fortran code is as follows:

```auto
module rhofunc
implicit none
public
integer, parameter :: dp=kind(0.d0)
contains
    pure real(dp) function rho(x,y)
        real(dp), intent(in) :: x,y
        if (x > 0.6_dp .and. x < 0.8_dp .and. y > 0.6_dp .and. y<0.8) then
            rho = 1.0_dp
        else if (x> 0.2_dp .and. x<0.4_dp .and. y>0.2_dp .and. y<0.4_dp) then
            rho = -1.0_dp
        else
            rho = 0.0_dp
        end if
    end function

end module

program poisson
use rhofunc, only: rho
implicit none
integer, parameter :: dp=kind(0.d0), M=100
integer :: i,j
real(dp),parameter :: epsilon0=8.85e-12_dp, target=1e-6, a=0.01
real(dp) :: delta, start, end, phiprime(M,M), phi(M,M), temp(M,M), a2

delta = 1.0_dp

call cpu_time(start)

do while (delta > target )
    a2 = a**2.0_dp
    do i=2, M-1
        do j=2, M-1
            phiprime(i,j) = (phi(i+1,j) + phi(i-1,j) + phi(i,j+1) + phi(i,j-1))/4.0_dp &
            + a2/4.0_dp/epsilon0*rho(i*a,j*a)
        end do
    end do
    delta = maxval(abs(phiprime - phi))
    temp = phi
    phi = phiprime 
    phiprime = temp

end do
call cpu_time(end)
print *, end-start
end program

```

On my machine, the C code runs in 0.12 seconds, but the Fortran code takes 0.37 seconds. Is there a particular reason why the C code is faster here? (I’m able to somewhat improve C performance by doing some unholy pointer tricks when swapping to 0.09 seconds)

Both are single-file, so I simply used gcc/gfortran with the -Ofast optimization flag. Edit: I also ran both with WSL2 on Windows.

---

<div class="post-metadata">

**Author:** ![Beliavsky](https://avatars.discourse-cdn.com/v4/letter/b/ba8739/32.png) [@Beliavsky](https://fortran-lang.discourse.group/u/Beliavsky)\
**Post date:** [June 26, 2021, 7:55pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/2 "2021-06-26T19:55:38Z")

</div>

I got similar results. Maybe Fortran programs have a longer start-up time – could you increase the dimension of your problem to 1000 or 10000?

---

<div class="post-metadata">

**Author:** ![runningcrocodile](https://avatars.discourse-cdn.com/v4/letter/r/ac91a4/32.png) [@runningcrocodile](https://fortran-lang.discourse.group/u/runningcrocodile)\
**Post date:** [June 26, 2021, 8:17pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/4 "2021-06-26T20:17:42Z")

</div>

Something odd is going on, since if I increase the grid size to 250x250, the C version takes 0.6 seconds to run (about expected, since the increase in iterations is about 6x), whereas the fortran version now takes 30 seconds, a nearly 100x increase in time. This seems extremely odd to me. To test 1000x1000, one would have to allocate on heap for the C version.

---

<div class="post-metadata">

**Author:** ![Mason](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Mason](https://fortran-lang.discourse.group/u/Mason)\
**Post date:** [June 26, 2021, 8:21pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/5 "2021-06-26T20:21:58Z")

</div>

> [@runningcrocodile](#):
>
> ```auto
> do i=2, M-1
> do j=2, M-1
> phiprime(i,j) = (phi(i+1,j) + phi(i-1,j) + phi(i,j+1) + phi(i,j-1))/4.0_dp &
> + a2/4.0_dp/epsilon0*rho(i*a,j*a)
> end do
> end do
> 
> ```

Aren’t Fortran arrays column major order, but C arrays are row-major order? If so, this should be an inefficient iteration scheme, compared to C, right? Maybe the compiler takes care of this for you though

---

<div class="post-metadata">

**Author:** ![runningcrocodile](https://avatars.discourse-cdn.com/v4/letter/r/ac91a4/32.png) [@runningcrocodile](https://fortran-lang.discourse.group/u/runningcrocodile)\
**Post date:** [June 26, 2021, 8:25pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/6 "2021-06-26T20:25:18Z")

</div>

It seems the compiler took care of that anyway. Actually, swapping the loop variables around seems to make the code even slower, somehow. I’m pretty sure there must be something trivial I’m missing, because that also makes little sense.

Also, I noted that the Fortran code goes through something like 15x more iterations than the C code, and I don’t see why that happens either. Even accounting for that, though, C is considerably faster per iteration.

I wonder what I’m missing here.

---

<div class="post-metadata">

**Author:** ![septc](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/septc/32/77_2.png) [@septc](https://fortran-lang.discourse.group/u/septc)\
**Post date:** [June 26, 2021, 8:36pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/7 "2021-06-26T20:36:58Z")

</div>

Isn’t `phi(:,:)` in the Fortran code not initialized to zero before entering the main loop?  
Also, it may be useful to check the number of iterations used in the C and Fortran codes (which should be the same or similar if the two calculations are essentially “equivalent”…)

---

<div class="post-metadata">

**Author:** ![runningcrocodile](https://avatars.discourse-cdn.com/v4/letter/r/ac91a4/32.png) [@runningcrocodile](https://fortran-lang.discourse.group/u/runningcrocodile)\
**Post date:** [June 26, 2021, 8:40pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/8 "2021-06-26T20:40:40Z")

</div>

Yeah, I fixed the initialization, but it didn’t change anything. I also ninja edited just as you were about to reply that the Fortran code does many more loops than the C code, but I can’t figure out why. I imagine that it will be something rather stupid in the end. Also, even taking in to account the number of iterations, the C code seems to be faster per iteration.

---

<div class="post-metadata">

**Author:** ![implicitall](https://avatars.discourse-cdn.com/v4/letter/i/9fc29f/32.png) [@implicitall](https://fortran-lang.discourse.group/u/implicitall)\
**Post date:** [June 26, 2021, 10:45pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/9 "2021-06-26T22:45:40Z")

</div>

A difference I see is that abs() in C is returning an int. Would it be possible to rewrite the code using array slicing? That is once you verify it is getting correct results.

---

<div class="post-metadata">

**Author:** ![implicitall](https://avatars.discourse-cdn.com/v4/letter/i/9fc29f/32.png) [@implicitall](https://fortran-lang.discourse.group/u/implicitall)\
**Post date:** [June 26, 2021, 11:33pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/10 "2021-06-26T23:33:41Z")

</div>

i can’t check the results, but some code like this.

```auto
real(dp) :: rho_mat(M,M)

```

```auto
do i=2, M-1
    do j=2, M-1
        rho_mat(i,j) = rho(i*a,j*a)
    enddo
enddo

```

```auto
do while (delta > target )
    a2 = a**2.0_dp
    phiprime(2:M-1,2:M-1) = (phi(3:M,2:M-1) + phi(1:M-2,2:M-1) + phi(2:M-1,3:M) + phi(2:M-1,1:M-2))/4.0_dp &
            + a2/4.0_dp/epsilon0*rho_mat(2:M-1,2:M-1)
    delta = maxval(abs(phiprime - phi))
    print *, delta
    temp = phi
    phi = phiprime 
    phiprime = temp
enddo

```

See lower post for an example that is easier to read.

---

<div class="post-metadata">

**Author:** ![septc](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/septc/32/77_2.png) [@septc](https://fortran-lang.discourse.group/u/septc)\
**Post date:** [June 26, 2021, 11:41pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/11 "2021-06-26T23:41:14Z")

</div>

> A difference I see is that abs() in C is returning an int.

Oh… 🙂 After fixing this (plus some more modifications like declaring arrays as `phi(0:M)` with M=100), I got the same number of iterations. Interestingly, gfortran seems to give much slower speed with `-Ofast` than `-O3` for this code, for some reason…

(Also, `epsilon0 = 8.85e-12` and `a = 0.01` may possibly give some numerical issues, because of `a**2 / epsilon0` and `rho()` = a step-like function)? If I change `epsilon0` to, say, 8.85e-8, -O3 and -Ofast gave the same number of iterations.)

---

<div class="post-metadata">

**Author:** ![nncarlson](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/nncarlson/32/1175_2.png) [@nncarlson](https://fortran-lang.discourse.group/u/nncarlson)\
**Post date:** [June 26, 2021, 11:43pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/12 "2021-06-26T23:43:21Z")

</div>

C short-circuits evaluation of the logical expressions in `rho` but Fortran does not (and there a lot of terms to evaluate). I wonder if that might be a source of _some_ of the performance difference.

---

<div class="post-metadata">

**Author:** ![implicitall](https://avatars.discourse-cdn.com/v4/letter/i/9fc29f/32.png) [@implicitall](https://fortran-lang.discourse.group/u/implicitall)\
**Post date:** [June 26, 2021, 11:45pm UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/13 "2021-06-26T23:45:57Z")

</div>

Here’s what I eventually ended up with. Maybe you can see what you think. It has close to the same number of iterations by using the new suggested epsilon and putting fabs in the C code.

```auto
module rhofunc
implicit none
public
integer, parameter :: dp = kind(0.d0)
contains
pure real(dp) function rho(x, y)
   real(dp), intent(in) :: x, y
   if(x > 0.6_dp .and. x < 0.8_dp .and. y > 0.6_dp .and. y < 0.8) then
      rho = 1.0_dp
   else if(x > 0.2_dp .and. x < 0.4_dp .and. y > 0.2_dp .and. y < 0.4_dp) then
      rho = -1.0_dp
   else
      rho = 0.0_dp
   endif
end function

end module

program poisson
use rhofunc, only: rho
implicit none
integer, parameter :: dp = kind(0.d0), M = 100
integer :: i, j
real(dp), parameter :: epsilon0 = 3.85e-8_dp, target = 1e-6, a = 0.01
real(dp) :: delta, start, end, phiprime(0:M+1, 0:M+1), phi(0:M+1, 0:M+1), a2
integer :: iters
real(dp) :: rho_mat(M, M)

iters = 0
phi = 0.0_dp

delta = 1.0_dp

call cpu_time(start)

do i = 1, M
   do j = 1, M
      rho_mat(i, j) = rho(i*a, j*a)
   enddo
enddo

a2 = a**2.0_dp

do while(.true.)
   phiprime(1:M, 1:M) = (phi(2:M+1, 1:M) + phi(0:M-1, 1:M) + phi(1:M, 2:M+1) + phi(1:M, 0:M-1))/4.0_dp &
                        + a2/4.0_dp/epsilon0*rho_mat
   delta = maxval(abs(phiprime - phi))
   iters = iters + 1
   if(delta > target) then
      phi = phiprime
   else
      exit
   endif
enddo

call cpu_time(end)
print *, iters
print *, end - start
end program

```

---

<div class="post-metadata">

**Author:** ![han190](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/han190/32/7158_2.png) [@han190](https://fortran-lang.discourse.group/u/han190)\
**Post date:** [June 27, 2021, 2:48am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/14 "2021-06-27T02:48:06Z")

</div>

A minor fix to your answer :), in the line:

```auto
phiprime(1:M, 1:M) = (phi(2:M+1, 1:M) + phi(0:M-1, 1:M) + phi(1:M, 2:M+1) + phi(1:M, 0:M-1))/4.0_dp &
                        + a2/4.0_dp/epsilon0*rho_mat

```

you will have exculde the “center part” as well since the original post says

```auto
(phi(i+1,j) + phi(i-1,j) + phi(i,j+1) + phi(i,j-1))/4.0_dp + ...

```

that means `phi(i, j)` is not included.

---

<div class="post-metadata">

**Author:** ![implicitall](https://avatars.discourse-cdn.com/v4/letter/i/9fc29f/32.png) [@implicitall](https://fortran-lang.discourse.group/u/implicitall)\
**Post date:** [June 27, 2021, 2:53am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/15 "2021-06-27T02:53:05Z")

</div>

I was thinking that would be

```auto
phi(1:M, 1:M)

```

Is that not right?

---

<div class="post-metadata">

**Author:** ![han190](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/han190/32/7158_2.png) [@han190](https://fortran-lang.discourse.group/u/han190)\
**Post date:** [June 27, 2021, 4:53am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/16 "2021-06-27T04:53:02Z")

</div>

You’re right, I thought the array starts at 1, but it’s `phi(0:M + 1)`…

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [June 27, 2021, 5:01am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/17 "2021-06-27T05:01:25Z")

</div>

How does this version compare against C?

---

<div class="post-metadata">

**Author:** ![implicitall](https://avatars.discourse-cdn.com/v4/letter/i/9fc29f/32.png) [@implicitall](https://fortran-lang.discourse.group/u/implicitall)\
**Post date:** [June 27, 2021, 5:31am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/18 "2021-06-27T05:31:52Z")

</div>

Assuming it’s correct, though it doesn’t have the exact same number of iterations, the Fortran version is faster than the C version on my laptop with very simple settings.

gcc -O3 poisson.c -lm && ./a.out  
Iterations:, 15515  
Execution Time: 0.358088

gfortran -O3 poisson.f90 && ./a.out  
Iterations: 15889  
Execution Time: 0.22557400000000000

---

<div class="post-metadata">

**Author:** ![runningcrocodile](https://avatars.discourse-cdn.com/v4/letter/r/ac91a4/32.png) [@runningcrocodile](https://fortran-lang.discourse.group/u/runningcrocodile)\
**Post date:** [June 27, 2021, 6:01am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/19 "2021-06-27T06:01:38Z")

</div>

Interesting that it’s faster than C on your machine, it’s not on mine. I rewrote the C algorithm to be equivalent to the Fortran one, where the rho array is calculated outside of the loop, and with M=250 it runs in about 16 seconds, whereas @implicitall 's Fortran version takes over 30.

Also, I’m a bit embarassed for using abs instead of fabs in C 😃

---

<div class="post-metadata">

**Author:** ![implicitall](https://avatars.discourse-cdn.com/v4/letter/i/9fc29f/32.png) [@implicitall](https://fortran-lang.discourse.group/u/implicitall)\
**Post date:** [June 27, 2021, 6:04am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/20 "2021-06-27T06:04:10Z")

</div>

I only used the original C code with fabs and different epsilon. Feel free to post the program changes and number of iterations.

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [June 27, 2021, 6:25am UTC](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461/21 "2021-06-27T06:25:32Z")

</div>

Another candidate for our [GitHub - fortran-lang/benchmarks: Fortran benchmarks](https://github.com/fortran-lang/benchmarks/) repository. If anyone is interested in taking the lead on it, please let me know.

[Next page](https://fortran-lang.discourse.group/t/performance-c-vs-fortran/1461.md?page=2)
