Forum: Compiler & IDEs NIC (aus dem langen C vs C++ Thread)


von Stefan S. (Gast)


Lesenswert?

Gut, das Projekt kannte ich noch nicht. Für Deinen Primzahlen-Benchmark 
ist dein Compiler ja echt fix. Wenn Du Lua nicht kanntest, dann wohl Nim 
auch nicht. Ich habe mal den Python Code angepaßt. Aber tatsächlich ist 
er für dieses Beispiel nicht so extrem viel schneller.
1
proc main =
2
  const limit = 100000
3
  var letztePrimzahl: int
4
  for zahl in 2 .. limit:
5
    var primzahl = true
6
    for zaehler in 2 .. zahl div 2:
7
      if zahl mod zaehler == 0:
8
        primzahl = false
9
        break
10
    if primzahl:
11
      letztePrimzahl = zahl
12
  echo "Die hoechste ermittelte Primzahl ist ", $letztePrimzahl
13
14
when isMainModule:
15
  main()
16
17
18
$ time python2 p.py
19
Die hoechste ermittelte Primzahl ist 99991
20
21
real  0m25.958s
22
user  0m25.949s
23
sys  0m0.008s
24
25
$ nim c -d:release p.nim
26
time ./p
27
Die hoechste ermittelte Primzahl ist 99991
28
29
real  0m1.829s
30
user  0m1.828s
31
sys  0m0.000s

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan S. schrieb:
> Wenn Du Lua nicht kanntest, dann wohl Nim auch nicht.

Stimmt, kannte ich bisher auch nicht.

> Ich habe mal den Python Code
> angepaßt. Aber tatsächlich ist er für dieses Beispiel nicht so extrem
> viel schneller

Ich habe den Code bewusst 1:1 in jede der anderen Sprachen übersetzt, um 
irgendwelche sprachabhängigen Optimierungen zu vermeiden.

> $ nim c -d:release p.nim
> time ./p
> Die hoechste ermittelte Primzahl ist 99991
>
> real  0m1.829s
> user  0m1.828s
> sys  0m0.000s

Das ist allerdings wirklich flott. Wie ich eben mal schnell nachgelesen 
habe, erzeugt nim u.a. C-Output, der wieder durch den C-Compiler gejagt 
wird. Damit ist die hohe Ausführungsgeschwindigkeit erklärbar.

An dem C-Code-Erzeuger für NIC arbeite ich noch, jedoch liegt bei mir 
die höhere Priorität beim Interpreter. Die Compile-Execute-Test-Zyklen 
sind durch das immer wieder notwendige Flashen des µCs ziemlich lang. 
Mit NIC will ich nicht nur Zeit auf dem µC sparen, sondern auch 
wertvolle Zeit des Programmierers. ;-)

Mit der Beta-Version von NIC wird auch eine erste Version des 
C-Code-Erzeugers (habe noch keinen richtigen Namen dafür) fertig sein, 
vermutlich im Juli. Ich erhoffe mir eine 10- bis 100-fache 
Ausführungsgeschwindigkeit. Dann stelle ich das komplette Projekt unter 
"Projekte & Code" vor.

Auf jeden Fall Danke für Deine Hinweise auf Lua und Nim. Ich schaue mir 
beides näher an. Man kann dabei nur lernen ;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Stefan S. schrieb:
>> Wenn Du Lua nicht kanntest, dann wohl Nim auch nicht.
>
> Stimmt, kannte ich bisher auch nicht.
>
>> Ich habe mal den Python Code
>> angepaßt. Aber tatsächlich ist er für dieses Beispiel nicht so extrem
>> viel schneller
>
> Ich habe den Code bewusst 1:1 in jede der anderen Sprachen übersetzt, um
> irgendwelche sprachabhängigen Optimierungen zu vermeiden.
>
>> $ nim c -d:release p.nim
>> time ./p
>> Die hoechste ermittelte Primzahl ist 99991
>>
>> real  0m1.829s
>> user  0m1.828s
>> sys  0m0.000s
>
> Das ist allerdings wirklich flott. Wie ich eben mal schnell nachgelesen
> habe, erzeugt nim u.a. C-Output, der wieder durch den C-Compiler gejagt
> wird. Damit ist die hohe Ausführungsgeschwindigkeit erklärbar.
>
> An dem C-Code-Erzeuger für NIC arbeite ich noch, jedoch liegt bei mir
> die höhere Priorität beim Interpreter. Die Compile-Execute-Test-Zyklen
> sind durch das immer wieder notwendige Flashen des µCs ziemlich lang.
> Mit NIC will ich nicht nur Zeit auf dem µC sparen, sondern auch
> wertvolle Zeit des Programmierers. ;-)
>
> Mit der Beta-Version von NIC wird auch eine erste Version des
> C-Code-Erzeugers (habe noch keinen richtigen Namen dafür) fertig sein,
> vermutlich im Juli. Ich erhoffe mir eine 10- bis 100-fache
> Ausführungsgeschwindigkeit. Dann stelle ich das komplette Projekt unter
> "Projekte & Code" vor.
>
> Auf jeden Fall Danke für Deine Hinweise auf Lua und Nim. Ich schaue mir
> beides näher an. Man kann dabei nur lernen ;-)

Mein Codegenerator braucht zwar recht lang, bis der Code erzeugt ist 
(mehr als 6 Minuten auf einem i7 @ 2GHz), dafür ist die 
Ablaufgeschwindigt super:
1
$ time make 
2
/usr/bin/g++ -g -std=c++1z -Wall -Wextra -fPIC   -c -o test05.o test05.cc
3
g++   test05.o   -o test05
4
5
real    6m15,234s
6
user    6m31,005s
7
sys     0m7,164s
8
9
$ time ./test05
10
MP: 99991
11
real    0m0,000s
12
user    0m0,000s
13
sys     0m0,000s

Übrigens auch für ARM und AVR und auch auf AVR braucht der Code nur ein 
paar Bytes und läuft dementsprechend unschlagbar schnell!

Die space-for-speed Variante erzeugt den Code in
1
/usr/bin/g++ -g -std=c++1z -Wall -Wextra -fPIC   -c -o test05.o test05.cc
2
g++   test05.o   -o test05
3
4
real    0m9,225s
5
user    0m10,110s
6
sys     0m0,122s

Die Ausführungszeit ist exakt diesselbe!

Der Codegenerator ist eine "eDSL" in C++.

Hier der Source-Code für beide Varianten:
1
#include <cstdint>
2
#include <array>
3
#include <iostream>
4
5
constexpr size_t maxPrime(size_t maximum) {
6
    size_t mp = 0;
7
    for(size_t v = 2; v <= maximum; ++v) {
8
        bool vIsPrime = true;
9
        for(size_t d = 2; d < v/2; ++d) {
10
            if ((v % d) == 0) {
11
                vIsPrime = false;
12
                break;
13
            }
14
        }
15
        if (vIsPrime) {
16
            mp = v;
17
        }
18
    }
19
    return mp;
20
}
21
22
template<size_t Maximum>
23
constexpr size_t maxPrime2() {
24
    std::array<bool, Maximum> test{};
25
    for(size_t i = 2; i < Maximum / 2; ++i) {
26
        for(size_t f = 2; f < Maximum / 2; ++f) {
27
            size_t np = i * f;
28
            if (np < Maximum) {
29
                test[np] = true;
30
            }
31
            else {
32
                break;
33
            }
34
        }
35
    }
36
    for(size_t m = Maximum - 1; m >= 2; --m) {
37
        if (!test[m]) {
38
            return m;
39
        }
40
    }
41
    return 0;
42
}
43
44
int main() {
45
//    constexpr auto mp = maxPrime(100000);   
46
    constexpr auto mp = maxPrime2<100000>();   
47
    std::cout << "MP: " << mp << '\0';    
48
}

Ok, den Scherz konnte ich mir echt nicht verkneifen ...

von Nop (Gast)


Lesenswert?

Frank M. schrieb:

> Das ist allerdings wirklich flott. Wie ich eben mal schnell nachgelesen
> habe, erzeugt nim u.a. C-Output, der wieder durch den C-Compiler gejagt
> wird. Damit ist die hohe Ausführungsgeschwindigkeit erklärbar.

Sowas in der Art kann ja auch Matlab. So hat man die enorme 
Funktionsvielfalt, zumal man im Realtime-Workshop sich ja auch graphisch 
was zusammenklicken kann.

Die Geschwindigkeit ist immer noch gut. Nicht so gut wie bei manuellem 
C-Code vielleicht, aber den zu entwickeln würde viel zu lange dauern.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Mein Codegenerator braucht zwar recht lang, bis der Code erzeugt ist
> (mehr als 6 Minuten auf einem i7 @ 2GHz), dafür ist die
> Ablaufgeschwindigt super:

Ich seh jetzt nicht was das mit dem Thema zu tun hat.

Und wenn man in einem ernsthaften Projekt sowas braucht, wird man 
ziemlich sicher zu aute-generiertem Code greifen.  Die C++ Tricks haben 
zwar den Vorteil, dass die Generierung einfacher ist, aber einen 
Compiler als Skripting-Engine zu verwenden ist wohl so ziemlich das 
ineffizienteste was ich mir vorstellen kann.  Die Ergebnisse sind zwar 
ok, aber bis man dahin kommt macht es einfach nur AUA.  Wenn du in der 
Entwicklungsphase jedes mal 6 Min warten musst, wirst du alsbald zu 
einem anderen Paradigma greifen :-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Ich habe den Code bewusst 1:1 in jede der anderen Sprachen übersetzt, um
> irgendwelche sprachabhängigen Optimierungen zu vermeiden.

Dennoch muss man ziemlich aufpassen, dass Tests nicht trivialisieren und 
wirklich in etwa das testen, was man auch anvisisert.

> Die Compile-Execute-Test-Zyklen sind durch das immer wieder
> notwendige Flashen des µCs ziemlich lang.

huh? Sowas entwickelt man doch ersma mit nem Simulator, der einem diesen 
ganzen Zirkus und Overhead erspart.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
>>
>
> Dennoch muss man ziemlich aufpassen, dass Tests nicht trivialisieren und
> wirklich in etwa das testen, was man auch anvisisert.

Ja, natürlich hast Du recht. Vornehmlich geht es mir auch darum, eine 
einfache Programmiersprache für 32-Bit-µCs anzubieten. Wie man immer 
wieder aus einzelnen Forumsbeiträgen herausliest, scheuen viele 
AVR-Programmierer den Umstieg auf z.B. den STM32 wegen der steigenden 
Komplexität. Die Leute, die hier bisher in Bascom programmiert haben, 
sind da ganz aufgeschmissen.

Es stimmt ja auch: Man muss beim STM32, um eine LED blinken zu lassen, 
normalerweise eine ganze Latte von Portinitialisierungen vornehmen, 
bevor die LED überhaupt einen Mucks tut. Wenn man auf Delays verzichten 
will, kommen auch noch Timer-Initialisierungen hinzu. Hinderlich hierbei 
ist zudem, dass der C-Code für STM32F10x und STM32F4xx allein schon bei 
der Port-Initialisierung verschieden aussieht.

Als NIC-Programm sieht das Blinken einer LED einfach so aus:
1
function void blink ()
2
    gpio.toggle (GPIOA, 5)
3
endfunction
4
5
function void main ()
6
    gpio.init (GPIOA, 5, OUTPUT)
7
    alarm.set (500, function.blink)                 // blink() alle 500msec automatisch aufrufen lassen
8
9
    loop
10
            // ...                                  // Hier koennen komplett andere Aufgaben erledigt werden
11
    endloop
12
endfunction

Die LED blinkt dann im 1Hz-Rhythmus. Das erledigt die Runtime-Bibliothek 
im Hintergrund. Die Hauptschleife ("loop") ist hier noch komplett leer, 
da das Blinken dann timergesteuert erfolgt. Die Syntax dabei ist so 
simpel, dass jeder Programmieranfänger das sofort versteht.

Der Schwerpunkt liegt also eher bei der Einfachheit der Sprache. Wenn 
der Interpreter nebenbei auch noch flott läuft, bin ich schon zufrieden. 
Das Sieve-Programm gibt mir dabei erstmal einen Anhaltspunkt - mehr 
nicht.

>> Die Compile-Execute-Test-Zyklen sind durch das immer wieder
>> notwendige Flashen des µCs ziemlich lang.
>
> huh? Sowas entwickelt man doch ersma mit nem Simulator, der einem diesen
> ganzen Zirkus und Overhead erspart.

Naja, wenn ich einen Packen WS2812-Streifen aus China bekomme, die 
plötzlich Pausen von 280µs statt 50µs (wie im Datenblatt steht) zwischen 
den Datenpaketen benötigen, weiß ich nicht, wie ich dieses Fehlverhalten 
in einem Simulator reproduzieren könnte ;-)

: Bearbeitet durch Moderator
von Wilhelm M. (wimalopaan)


Lesenswert?

Johann L. schrieb:
> Wilhelm M. schrieb:
>> Mein Codegenerator braucht zwar recht lang, bis der Code erzeugt ist
>> (mehr als 6 Minuten auf einem i7 @ 2GHz), dafür ist die
>> Ablaufgeschwindigt super:
>
> Ich seh jetzt nicht was das mit dem Thema zu tun hat.

Das ganze war doch als Scherz markiert!

Motiviert war es durch dieses Aussage von Frank M. in dem anderen Thread
Beitrag "Welche Programmiersprache auf µC"

Frank M. schrieb:
> Die hohe Ausführungsgeschwindigkeit wird dadurch erreicht, dass der Host
> das NIC-Script vorcompiliert und dann auf den µC einen
> maschinenunabhängigen Objekt-Code hochlädt. Dabei werden dann auch
> direkt einige Optimierungen vorgenommen: Zum Beispiel werden konstante
> Ausdrücke in Expressions direkt zur Compilezeit ausgerechnet.

Denn in meinem Beispiel findet ja auch eine (Vor-)Kompilierung statt und 
zur Compilezeit konstante Ausdrücke werden berechnet!
Was das NIC ja in diesem Fall wohl eben nicht macht, sondern zur 
Laufzeit ...

Und ich sags nochmal: das war scherzhaft ...

von Dr. Sommer (Gast)


Lesenswert?

Frank M. schrieb:
> Es stimmt ja auch: Man muss beim STM32, um eine LED blinken zu lassen,
> normalerweise eine ganze Latte von Portinitialisierungen vornehmen,
Und deswegen braucht man gleich eine neue Sprache? Kann man so etwas 
nicht auch in vernünftige™ API's in C++ oder C kapseln? (Die API's von 
ST selber mit HAL/SPL zähl ich mal nicht als vernünftig). Mit der 
Arduino Umgebung für STM32 sollte das ja auch nicht mehr so schwierig 
sein, und das ist ja auch C++.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> Und deswegen braucht man gleich eine neue Sprache?

Nein, man braucht keine neue Sprache. Für Dich ist sie schon gar nicht 
gedacht.

Merke: Ich will hier keinem was aufdrängen. Wer es nutzen will, kann es 
nutzen, wer nicht, der nicht. Ich mache das aus Spaß. Und den kannst Du 
weißgott nicht in Frage stellen ;-)

Ich verstehe auch nicht, warum die Leute immer direkt mit Kritik und 
Fragen nach dem "Warum" angeschossen kommen, wenn irgendjemand etwas 
einfaches zusammenbaut und dann auch noch verschenken will.

> Kann man so etwas nicht auch in vernünftige™ API's in C++ oder C
> kapseln?

Klar kann "man" das. Mach doch. Wenn ein Anfänger oder 
Bascom-Programmierer das dann auch noch anwenden kann, umso besser. 
Vielleicht kannst Du Dir auch vorstellen, dass die 
NIC-Laufzeitbibliothek, die ja in C geschrieben ist, bereits dem 
NIC-Interpreter eine API zur Verfügung stellt. Diese kann man natürlich 
auch in C direkt aufrufen, ohne den Interpreter zu bemühen. Ob sie aber 
"vernünftig" ist, sei mal dahingestellt. Hier geht es darum, einem 
Programm eine API zu bieten und keinem Programmierer. Daher sieht sie 
ein wenig langweilig aus ;-)

P.S.
Solche Fragen nach dem "Warum" hörte ich schon damals, als ich das 
fli4l-Projekt ins Leben rief: "Router? Wofür? Ich steck mein DSL-Modem 
ins LAN-Interface und bin drin.". Klar war er drin, so drin, dass jeder 
direkt von außen auf seinen PC zugreifen konnte. Und die Frau und Kinder 
mussten warten, bis der Papa mit dem Surfen fertig war. Früher war das 
parallele Surfen aus einem Haushalt über mehrere PCs von der Telekom 
verboten. Heutzutage bekommt man die Internet-Router an jeder Ecke 
nachgeschmissen und die ganze Familie kann gleichzeitig surfen. Warum 
wohl?

: Bearbeitet durch Moderator
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.