Γλώσσα προγραμματισμού σημεία αναφοράς

Home

Αυτή η σελίδα περιέχει το ίδιο πρόγραμμα, που υλοποιείται με τον ίδιο τρόπο, C, Ada, FORTRAN, Lisp, FORTH, Java, Perl, R και Ruby και τρέχουν σε Pentium 300 mhz υπό τον “γούντι” Debian GNU/Linux, χρησιμοποιώντας αποκλειστικά τα εργαλεία που έρχονται με την διανομή Debian, εκτός από τη σύνταξη Java θα χρησιμοποιηθεί το jikes compiler από την IBM.

Αυτό είναι σχετικό για τις εφαρμογές που περιλαμβάνουν την εντατική υπολογισμούς για πολλούς χρήστες, όπως είναι οι προσομοιωτές με την ανοικτή πρόσβαση στο web (όπως warfarissimo και autovaca). Για τέτοιες εφαρμογές, απόδοση μεταφράζεται άμεσα σε κόστος: ο αριθμός των μηχανών που πρέπει να αγοράσει και να διατηρήσει, προκειμένου να εξυπηρετήσει ένα συγκεκριμένο αριθμό των χρηστών, ή να επιτύχει ένα απαιτούμενο χρόνο αντίδρασης είναι ευθέως ανάλογη προς το χρόνο υπολογισμού.

Το πρόγραμμα θα αξιολογηθεί υπολογίζει το ίδιο 100-όρος πολυωνύμου 500.000 φορές, χρησιμοποιώντας ακριβώς τον ίδιο αλγόριθμο. Σε όλα τα προγράμματα οι δείκτες των πολυώνυμο διατηρούνται σε ένα τοπικό float vector. Σε αυτό, το πρόγραμμα ελέγχει μόνο την ποιότητα του κώδικα που αποκτά πρόσβαση σε τοπικούς φορείς και να εκτελεί απλές αριθμητικές πράξεις σε βρόχους, και είναι δωρεάν από τις διαφορές στην τυπική βιβλιοθήκη, το λειτουργικό σύστημα κλήσεις και, πράγματι, η παρουσία προηγμένα χαρακτηριστικά της γλώσσας.

Υπάρχουν δύο εκδόσεις του προγράμματος: (1) όλοι οι υπολογισμοί γίνονται μέσα σε μια ενιαία λειτουργία του σώματος * (2) κάθε πολυώνυμο υπολογίζεται μέσω μιας κλήσης σε λειτουργία το διάνυσμα των 100 συντελεστών διατηρούνται σε στατικά διαστάσεις σειράς μέσα αυτή η λειτουργία ονομάζεται 500000 φορές.

Η ταχύτητα εκτέλεσης του η πρώτη έκδοση ήταν επίσης να διερευνηθεί μέσω της αναφοράς σε AMD 64×2.

Τα αποτελέσματα είναι τα παρακάτω (σε δευτερόλεπτα που απαιτείται για να εκτελέσετε την απλή εργασία που περιγράφεται παραπάνω). Κάντε κλικ στο σύνδεσμο με το όνομα της γλώσσας για να δείτε τις λεπτομέρειες (πρόγραμμα και πώς να μεταγλώττιση και εκτέλεση) για κάθε γλώσσα:

Γλώσσα ενιαίο σώμα (s) με την κλήση (s)
FORTRAN, g77 V2.95.4 2.73 2.73
Ada 95, gnat V3.13p 2.73 2.74
C, hand optimized **, gcc V2.95.4 2.73
Java, gcj V3.0 3.03 15.53
D, gcc V4.0.3+ 1)3.43 1)3.98
C, gcc V2.95.4 3.61 3.57
R translated to lisp χρησιμοποιώντας R2cl v0.1 και καταρτίζονται με cmucl 3.69
Lisp, CMU Common Lisp V3.0.8 18c+, build 3030 4.69 10.69
Java, jikes V1.15 (bytecompiled) 8.23 13.54
FORTH, hand optimized ** Gforth 0.6.1 1)18.21
FORTH,** Gforth 0.6.1 1)27.26
Python** +psyco (interpreted) 1)168.50
Perl, more optimized$ V5.6.1 (natively compiled) 209.20
Perl, more optimized$ V5.6.1 (interpreted) 258.64
Perl, hand optimized*** V5.6.1 (bytecompiled) 306.18
Perl* V5.6.1 (natively compiled) 367.23
Python** V2.1.2 (interpreted) 505.50
Perl* V5.6.1 (bytecompiled) 515.04
RUBY*** (interpreted) 1074.52
R V1.5.1 (interpreted) 5662.64

* Συνέβαλε με Matei Conovici
** Συνέβαλε με Mihai Manolescu
*** Συνέβαλε με zgrim
$ Συνέβαλε με Radu Greab
+ Συνέβαλε με Mihai Militaru

1) εκτιμώμενη

Ησυζήτηση. Η σημασία των δοκιμών αυτών στηρίζεται στο γεγονός ότι σε οποιαδήποτε γλώσσα, τις επιδόσεις διέπεται από το πόσο γρήγορα επιχειρήσεων, βρόχος, πρόσβαση στα στοιχεία ενός πίνακα, κλήσεις συναρτήσεων, κ. λπ., που εκτελούνται. Μηχανή-oriented languages (C, FORTRAN, Ada και, σε κάποιο βαθμό, Java) εκτελεί κατά μέσο όρο 100 φορές πιο γρήγορα από την ανθρώπινη έκφραση-oriented languages (Perl, R, Python, Ruby).

Προγραμματισμού 1 GHz Pentium [ταχύτερα, 1000$, 2002 PC] σε Perl είναι σαν τον προγραμματισμό των 10 MHz κάτι [overclocked, 50$, 1982 Z80-based ZX Spectrum] σε FORTRAN!

Αυτό δεν είναι μεγάλη έκπληξη, καθώς εξετάζουμε την κλασική trade-off μεταξύ της δύναμης της γλώσσας (επιτρέποντας στον προγραμματιστή να εκφράσω κάτι σε μια συμπαγή τρόπο) και της απόδοσης της εφαρμογής (το οποίο κλασικά ήταν που συνδέονται με τη γλώσσα να είναι κοντά στο μηχάνημα εκπροσώπηση).

Ωστόσο, η τεράστια εξαίρεση είναι CommonLisp. Lisp είναι η πιο ισχυρή γλώσσα, που αντιπροσωπεύουν την κλασική ακραία επιλογή για την εκφραστική δύναμη, αντί για την αποτελεσματική εφαρμογή της.

Η επιλογή αυτή φαίνεται να απέδωσαν. Δεδομένου αρκετά έκφραση δύναμης ήταν δυνατό να γράψει ένα compiler που ανταγωνίζεται με οποιαδήποτε μηχανή-oriented γλώσσα.

Συμπεράσματα (για μένα):

Προσάρτημα. Λεπτομέρειες του κάθε προγράμματος και πώς να το μεταγλωττίσετε και να το εκτελέσετε:

FORTRAN

tespol.f

program tespol
      dimension pol(100)
      real pol
      integer i,j,n
      real su,pu,mu
      real x

      n = 500000
      x = 0.2
      mu = 10.0
      pu = 0.0
      do i = 1,n
         do j=1,100
            mu = (mu + 2.0) / 2.0
            pol(j) = mu
         enddo
         su = 0.0
         do j=1,100
            su = x * su + pol(j)
         enddo
         pu = pu + su
      enddo
      write (*,*) pu
      end
Μεταγλώττιση και εκτέλεση με:
f77 tespol.f -O6 -o tespol
time ./tespol

tespol2.f

function dopoly(x)
      real x
      real su,mu
      integer j
      dimension pol(100)
      real pol

         do j=1,100
            mu = (mu + 2.0) / 2.0
            pol(j) = mu
         enddo
         su = 0.0
         do j=1,100
            su = x * su + pol(j)
         enddo

      dopoly = su
      end

      program tespol

      integer i
      real pu
      real x


      n = 500000
      x = 0.2
      mu = 10.0
      pu = 0.0
      do i = 1,n
         pu = pu + dopoly(x)
      enddo
      write (*,*) pu
      end
Μεταγλώττιση και εκτέλεση με:
f77 tespol2.f -O6 -o tespol2 time ./tespol2

Ada-95

tpol.adb

with Ada.Command_Line; use Ada.Command_Line;
with Ada.Text_Io; use Ada.Text_Io;

procedure Tpol is

   Pol: array(1..100) of Float;
   N: Integer:= Integer'Value(Argument(1));
   X: Float:= Float'Value(Argument(2));
   S: Float;
   Mu: Float:= 10.0;
   Pu: Float:= 0.0;

begin
   for I in 1..N loop
      for J in 1..100 loop
         Mu := (Mu + 2.0) / 2.0;
         Pol(J) := Mu;
      end loop;
      S := 0.0;
      for J in 1..100 loop
         S := X * S + Pol(J);
      end loop;
      Pu := Pu+S;
   end loop;
   Put_Line(Float'Image(Pu));
end Tpol;
Μεταγλώττιση και εκτέλεση με:
gnatmake -O6 tpol
time ./tpol 500000 0.2

tpol2.adb

with Ada.Command_Line; use Ada.Command_Line;
with Ada.Text_Io; use Ada.Text_Io;

procedure Tpol2 is

   N: Integer:= Integer'Value(Argument(1));
   X: Float:= Float'Value(Argument(2));
   Pu: Float:= 0.0;

   function Dopol(X: Float) return Float is

      Pol: array(1..100) of Float;
      S: Float;
      Mu: Float:= 10.0;

   begin
      for J in 1..100 loop
         Mu := (Mu + 2.0) / 2.0;
         Pol(J) := Mu;
      end loop;
      S := 0.0;
      for J in 1..100 loop
         S := X * S + Pol(J);
      end loop;
      return S;
   end Dopol;

begin
   for I in 1..N loop
      Pu := Pu+Dopol(X);
   end loop;
   Put_Line(Float'Image(Pu));
end Tpol2;

Μεταγλώττιση και εκτέλεση με:
gnatmake -O6 tpol2
time ./tpol2 500000 0.2


Java

public class tpoly {

    static public void main(String argv[]) {
     float mu = (float)10.0;
     float x,s;
     float pu = (float)0.0;
     int su, i, j, n;
     float pol[] = new float[100];

     n = 500000;
     x = (float)0.2;
     for(i=0; i<n; i++) {
       for (j=0; j<100; j++) {
         mu =  (mu + (float)2.0) / (float)2.0;
         pol[j] = mu;
       }
       s = (float)0.0;
       for (j=0; j<100; j++) {
         s = x*s + pol[j];
       }
       pu += s;
     }
     System.out.println(pu);
  }
}

Μεταγλώττιση και εκτέλεση με:
gcj-3.0 --main=tpoly --classpath=/usr/share/java/libgcj.jar -O2 -o tpoly tpoly.java
time ./tpoly
ή μεταγλώττιση σε δυφιολέξη κώδικα και να τρέξει με:
jikes -O tpoly.java
time java tpoly
public class tpoly2 {

    static float dopoly(float x) {
	float pol[] = new float[100];
	int j;
	float mu = (float)10.0;
	float s;

	for (j=0; j<100; j++) {
	    mu =  (mu + (float)2.0) / (float)2.0;
	    pol[j] = mu;
	}
	s = (float)0.0;
	for (j=0; j<100; j++) {
	    s = x*s + pol[j];
	}
	return s;

    }

    static public void main(String argv[]) {
     float x;
     float pu = (float)0.0;
     int i, n;

     n = 500000;
     x = (float)0.2;
     for(i=0; i<n; i++) {
       pu += dopoly(x);
     }
     System.out.println(pu);
  }
}
Μεταγλώττιση και εκτέλεση με:
gcj-3.0 --main=tpoly --classpath=/usr/share/java/libgcj.jar -O2 -o tpoly2 tpoly2.java
time ./tpoly2
ή μεταγλώττιση σε δυφιολέξη κώδικας και να τρέξει με:
jikes -O tpoly2.java
time java tpoly2

C

tepol.c

#include <stdio.h>
#include <stdlib.h>

main(short argc, char **argv) {
  float mu = 10.0;
  float x,s;
  float pu = 0.0;
  int su, i, j, n;
  float pol[100];

  n = atol(argv[1]);
  x = atof(argv[2]);
  for(i=0; i<n; i++) {
    for (j=0; j<100; j++) {
      pol[j] = mu = (mu + 2.0) / 2.0;
    }
    s = 0.0;
    for (j=0; j<100; j++) {
      s = x*s + pol[j];
    }
    pu += s;
  }
  printf("%f\n",pu);
}
Μεταγλώττιση και εκτέλεση με:
gcc -O6 tepol.c -o tepol
time ./tepol 500000 0.2

tepol2.c

#include <stdio.h>
#include <stdlib.h>

float dopoly(float x) {

  float mu = 10.0;
  float s;
  int j;
  float pol[100];

  for (j=0; j<100; j++) {
    pol[j] = mu = (mu + 2.0) / 2.0;
  }
  s = 0.0;
  for (j=0; j<100; j++) {
    s = x*s + pol[j];
  }
  return s;
}

main(short argc, char **argv) {
  float x;
  float pu = 0.0;
  int  i, n;

  n = atol(argv[1]);
  x = atof(argv[2]);
  for(i=0; i<n; i++) {
    pu += dopoly(x);
  }
  printf("%f\n",pu);
}
Μεταγλώττιση και εκτέλεση με:
gcc -O6 tepol2.c -o tepol2
time ./tepol2 500000 0.2
Χέρι βελτιστοποιημένη C

bench1.c (από Mihai Manolescu)

#include <stdio.h>
#include <stdlib.h>

main(short argc, char **argv) {
  float mu = 10.0;
  float x,s;
  float pu = 0.0;
  int su, i, j, n;
  float pol[100];
  register tm1;
  register int tp1;

  n = atol(argv[1]);
  x = atof(argv[2]);
  for(i=0; i<n; i++) {
    tp1=2;
    tm1=1/2.0;
    for (j=0; j<100; j++) {
      pol[j] = mu = (mu + tp1) * tm1;
    }
    s = 0.0;
    for (j=0; j<100; j++) {
      s = x*s + pol[j];
    }
    pu += s;
  }
  printf("%f\n",pu);
}

Common-Lisp

testpol.lisp

(defun eval-pol (n x)
  (declare (fixnum n) (single-float x))
  (let ((su 0.0) (mu 10.0) (pu 0.0)
	(pol (make-array 100 :element-type 'single-float)))
    (declare (single-float su) (single-float mu) (single-float pu))
    (dotimes (i n)
	     (declare (fixnum i))
	     (setf su 0.0)
	     (dotimes (j 100)
		      (declare (fixnum j))
		      (setf mu (the single-float (/ (+ mu 2.0) 2.0)))
		      (setf (aref pol j)
			    (the single-float mu)))
	     (dotimes (j 100)
		      (declare (fixnum j))
		      (setf su (the single-float
				    (+ (aref pol j) (the single-float (* su x))))))
	     (setf pu (the single-float (+ pu su)))
	     )
    (prin1 pu)
    ))

Έναρξη CMU Common lisp:
lisp
... στη συνέχεια, το φορτίο, τη μεταγλώττιση και εκτέλεση με:
(load "testpol.lisp")
(compile #'eval-pol)
(time (eval-pol 500000 0.2))

testpol2.lisp

(proclaim '(optimize))

(declaim (start-block dopoly eval-pol))

  (defun dopoly (x) 
    (declare (ftype (function (single-float) single-float) dopoly))
    (declare (single-float x))
    (let ((su 0.0) (mu 10.0)
	  (pol (make-array 100 :element-type 'single-float)))
      (declare (single-float su) (single-float mu))
      (dotimes (j 100)
	(declare (fixnum j))
	(setf mu (the single-float (/ (the single-float (+ mu 2.0)) 2.0)))
	(setf (aref pol j)
	      (the single-float mu)))
      (dotimes (j 100)
	(declare (fixnum j))
	(setf su (the single-float
		      (+ (aref pol j) (the single-float (* su x))))))
      su)
    )


(defun eval-pol (n x)
  (declare (fixnum n) (single-float x))
  (let ((pu 0.0))
    (declare (single-float pu))
    (dotimes (i n)
	     (declare (fixnum i))
	     (setf pu (the single-float (+ pu (the single-float (dopoly x)))))
	     )
    (prin1 pu)
    ))

(declaim (end-block))

Έναρξη CMU Common lisp:
lisp
... στη συνέχεια, το φορτίο, τη μεταγλώττιση και εκτέλεση με:
(load "testpol2.lisp")
(compile #'eval-pol)
(time (eval-pol 500000 0.2))

 

D tepol.d (από Mihai Militaru)

//tepol.d

import std.stdio;
import std.conv;

int main(char[][] args)
{
	float mu = 10.0;
	float x,s;
	float pu = 0.0;
	int su, i, j, n;
	float pol[100];

	n = toLong(args[1]);
	x = toFloat(args[2]);
	for(i=0; i<n; i++)
	{
		for (j=0; j<100; j++)
	{
		pol[j] = mu = (mu + 2.0) / 2.0;
	}
	s = 0.0;
	for (j=0; j%lt;100; j++)
	{
		s = x*s + pol[j];
	}
		pu += s;
	}
	writefln("%f\n",pu);
	return 0;
}

Μεταγλώττιση με:
gdmd -O -release -inline tepol.d

Εκτελέστε το με:
time ./tepol 500000 0.2

tepol2.d (από Mihai Militaru)

//tepol2.d

import std.stdio;
import std.conv;

float dopoly(float x)
{
	float mu = 10.0;
	float s;
	int j;
	float pol[100];

	for (j=0; j<100; j++)
	{
		pol[j] = mu = (mu + 2.0) / 2.0;
	}
	s = 0.0;
	for (j=0; j<100; j++)
	{
		s = x*s + pol[j];
	}
	return s;
}

int main(char[][] args)
{
	float x;
	float pu = 0.0;
	int  i, n;

	n = toLong(args[1]);
	x = toFloat(args[2]);
	for(i=0; i<n; i++)
	{
	pu += dopoly(x);
	}
	printf("%f\n",pu);
	return 0;
}
Μεταγλώττιση με:
gdmd -O -release -inline tepol2.d

Εκτελέστε το με:
time ./tepol2 500000 0.2

Python

tpytpol.py (από Mihai Manolescu)
n = 500000
x = 0.2

def t(x):
    mu = 10.0
    pu = 0.0
    pol =[0] * 100
    r = range(0,100)

    for i in range(0,n):
        for j in r:
            pol[j] = mu = (mu + 2.0) / 2.0
        su = 0.0
        for j in r:
            su = x * su + pol[j]
        pu = pu + su
    print pu

t(x)
Εκτελέστε το με:
time python tpytpol.py

Perl

tperlpol.pl (από τον Matei Conovici)

#! /usr/bin/perl


$n = $ARGV[0];
$x = $ARGV[1];

$mu = 10;
$pu = 0;

@pol = ();

for ($i = 0; $i < $n; $i++) {
	for ($j = 0; $j < 100; $j++) {
		$mu = ($mu + 2) / 2;
		
		$pol[$j] = $mu;
	}

	$s = 0;
	for ($j = 0; $j < 100; $j++) {
		$s = $x * $s + $pol[$j];
	}

	$pu += $s;
}

print "$pu\n";
Μεταγλώττιση και εκτέλεση με:
perlcc -O -o tperlpol tperlpol.pl
time ./tperlpol 500000 0.2
ή, για δυφιολέξη συλλογή:
perlcc -B -o tperlpol tperlpol.pl
time ./tperlpol 500000 0.2


Perl
(βελτιστοποιημένη)

pl.pl (by zgrim)

my($n,$x,$mu,$pu,@pol)=(500000,0.2,10,0,(0..99));
for(1..$n) {
    for (0..$#pol)  {   $pol[$_] = $mu = ( $mu + 2 ) * 0.5      } 
    $s = 0;
    for(0..$#pol)   {   $s = $x * $s + $pol[$_]                 } 
    $pu += $s
} 
print qq[$pu\n];
Μεταγλώττιση και εκτέλεση με:
perlcc -B -o pl pl.pl
time ./pl


Perl
(χέρι βελτιστοποιηθεί για μητρική σύνταξη)

perl3.pl από Radu Greab

#!/usr/bin/perl -w

use strict;

my $n = $ARGV[0];
my $x = $ARGV[1];

my $mu = 10;
my $pu = 0;

my @pol;

foreach (0 .. $n - 1) {
    foreach (0 .. 99) {
        $pol[$_] = $mu = ($mu + 2) / 2;
    }

    my $s = 0;
    foreach (0 .. 99) {
        $s = $x * $s + $pol[$_];
    }

    $pu += $s;
}

print "$pu\n";
Μεταγλώττιση και εκτέλεση με:
perlcc -O -o perl3 perl3.pl
time ./perl3


R (
ή S, Splus)

trpol2.R

trpol2 <- function(n,x) {
  mu <<- 10.0
  pu <<- 0.0
  pol <<- 1:100
  tp1 <<- 2.0
  tm1 <<- 1/2.0
  for (i in 1:n) {
    for (j in 1:100) {
      mu <<- (mu + tp1) * tm1
      pol[j] <<- mu
    }
    s <<- 0.0;
    for (j in 1:100) {
      s <<- x*s + pol[j];
    }
    pu <- s+pu;
  }
  print(pu)
}
Εκτελέστε το πρόγραμμα με:
time echo " source(\"trpol2.R\") ; trpol2(500000,0.2) ; q() " | R --no-save


Ruby (από zgrim)

pol.rb

n = 500000
x = 0.2
mu = 10
pu = 0
pol = []

n.times do
    0.upto(99) { |j| pol[j] = mu = (mu + 2) * 0.5 }
    s = 0
    0.upto(99) { |j| s = x * s + pol[j] }
    pu += s
end

print pu,"\n"
Εκτελέστε το πρόγραμμα με:
time ruby pol.rb

FORTH (από Mihai Manolescu)

bench.fs

--- bench.fs:

\ gforth source code for speed test
\                                                       mmihai, sept '04
\

100 floats allocate throw
constant farray

: init_farray
    0e0
    farray
    100 0 do
        dup fdup f!
        float+
    loop
    drop fdrop
;

: my_loop
    init_farray
    0e0                 \ x pu
    10e0                \ x pu mu

    0 do
        farray
        100 0 do
            2e0 f+ f2/
            dup fdup f!
            float+
        loop
        drop                    \ x pu mu
        frot frot               \ mu x pu
        fswap 0e0               \ mu pu x su
        farray
        100 0 do
            fover  f*
            dup f@ f+
            float+
        loop
        drop
        frot f+                 \ mu x pu
        frot                    \ x pu mu
    loop
    fdrop f. cr fdrop
;

0.2e0 500000 my_loop

Εκτελέστε το πρόγραμμα με:
time gforth-fast bench.fs -e bye

FORTH, χέρι βελτιστοποίηση (από Mihai Manolescu)

bench2.fs

\ gforth source code for speed test
\                                                       mmihai, sept '04
\

falign here 100 floats allot constant farray

: my_loop
    0e0                 \ x pu
    10e0                \ x pu mu

    0 do
        farray
        2e0 fswap
        100 0 do
            fover f+ fover f/
            dup fdup f!
            float+
        loop
        fnip
        drop                    \ x pu mu
        frot frot               \ mu x pu
        fswap 0e0               \ mu pu x su
        farray
        100 0 do
            dup
            fover  f*
            f@ f+
            float+
        loop
        drop
        frot f+                 \ mu x pu
        frot                    \ x pu mu
    loop
    fdrop f. cr fdrop
;

0.2e0 500000 my_loop

Εκτελέστε το πρόγραμμα με:
time gforth-fast bench2.fs -e bye

 

Αρχικά στο http://dan.corlan.net/bench.html