Forum: Mikrocontroller und Digitale Elektronik Codeoptimierung Redundante Module entfernen


von schobbe (Gast)


Lesenswert?

Hallo,

ich habe folgendes Problem ich muss eine etwa 18.000 Byte große 
Applikation so verändern, dass sie in einen 16K Controller reinpasst.

Einen Punkt zur Einsparung habe ich schon gefunden:
Es gibt 3 Module die doppelt vorhanden sind.

Derjenige der den Code erstellt hat, hatte die tolle Idee für 2 mehr 
oder weniger unabhängige Kanäle separate Steuerungs- und 
Überwachungsmodule zu erzeugen.

Im Code sieht das dann etwa so aus:

Steuerung1.c:
1
char Status1;
2
char Grenzwert1;

Steuerung2.c:
1
char Status2;
2
char Grenzwert2;

Diese Kanal-Codierung im Namen zieht sich durch die komplette 
Applikation.

Meine Idee ist nun jeweils das redundante Modul zu entfernen und für 
jede Variable ein Array anzulegen, dass im Moment 2 Elemente fassen 
kann...

Hat jemand schon Erfahrung mit sowas? Oder weiß auf was man hier 
besonders achten muss?

Wie gesagt muss man hier sehr stark in den Code eingreifen: in die 
zentralsten Schnittstellen des Systems. Schätzungsweise muss hier sehr 
viel geändert werden.. ausserdem sind die Module untereinander nicht gut 
gekapselt, was heißt das es extrem viele Schnittstellen gibt ...

Schon mal vielen Dank!!!

und ein schönes WE :-)

von 1234 (Gast)


Lesenswert?

Ha. Ja. Dann mach mal... wir koennen da glaub nicht helfen. Fuer 
wieviele 1000 stueck soll die arbeit denn gemacht werden ? Alternativ 
koennte man sich mal nach einem 32k Controller umschauen und sich die 
Arbeit sparen...

von Peter D. (peda)


Lesenswert?

Ohne den Quellcode und ohne CPU und Compiler zu kennen, ists schwer, 
Tips zu geben.

Schau ins Assemblerlisiting, wo der Compiler große Codemonster erzeugt 
und versuche dann sowas in Unterprogramme auszulagern, wenn es oft 
benötigt wird.


Peter

von Oliver (Gast)


Lesenswert?

>Hat jemand schon Erfahrung mit sowas?

Bestimmt.

>Oder weiß auf was man hier besonders achten muss?

Das das Programm hinterher das selbe macht wie vorher. Und das ist auch 
die Strategie - Programm alt und Programm neu Schritt für Schritt im 
Debugger vergleichen.

Oliver

von schobbe (Gast)


Lesenswert?

@1234:

Mir ging es hier eher um Konzepte wie man sowas am besten anpacken kann. 
Z.B. wie Peter geschrieben hat Teile in Unterfunktionen auslagern, aber 
sowas sind doch schon tiefergehende Eingriffe wo man unter Umständen das 
Timing kaputt machen kann..?

Der Code läuft bereits Serienmäßig auf einem 32k Controller. Aber aus 
Kostengründen soll er auf einen 16K Flash Controller runter.

Bisherige Codegröße (ohne Optimierungen, 2 Kanäle aktiv): ca. 18.000 
Byte
Codegröße (1 Kanalversion, 2 Kanal durch Compilerschalter deaktiviert): 
ca. 15.700 Byte.

@Peter Dannegger
CPU ist ein HCS08 (Freescale)
Compiler ist der Cosmic Compiler 68hc08

Ziel ist es nun die 2 Kanalversion auf etwa die Größe der 1 Kanalversion 
zu bringen OHNE die Funktion zu ändern. Also tatsächlich nur 
Optimierungen.

Für Kanal 1 und Kanal 2 gibt es jeweils 2 Überwachungsmodule und 1 
Steuerungsmodul.

Die Steuerungsmodule sind etwa funktional zu 90 % identisch (bis auf die 
Namensbezeichnung x1x... x2x..)

Für die übrigen 10 % muss ich dann wohl Sonderbehandlungen einbauen wie 
gesagt OHNE was an der Funktion zu ändern. Da muss man dann sehr 
akribisch und ordentlich vorgehen..

Vielleicht hat das ja jemand schon mal bei einem größeren Projekt machen 
müssen, also Re-factoring... und weiß was für Tricks es da gibt..

Natürlich muss ich immer genau wissen was ich da tue und nicht einfach 
blind "Find & Replace".. .das is mir auch klar.

Mein Ziel ist etwa so eine Schnittstelle:
1
//vorher:
2
Steuerung_1_Funktion ();
3
4
Steuerung_2_Funktion ();
5
6
// danach
7
Steuerung_Funktion(enum_kanal KANAL);

durch Sonderbehandlungen hole ich mir ja auch mehr Overhead wieder ins 
Boot und das will ich ja vermeiden...

An der Steuerung_1 sind etwa 5 weite Module inkludiert.

Diese haben in sich wieder jeweils separate Variablen für Kanal 1 und 
Kanal 2...

mein erster Schritt, habe ich mir gedacht, wäre also jetzt erstmal diese 
Low Module zu nehmen (wie Analogwert Erfassung) und hier auch jeweils 2 
Variablen ein Feld zu machen.. über das dann mit einem Index (Kanal 1 / 
Kanal 2) zugegriffen wird..

ist dieses modul fertig... kommen die übrigen 4 dran.. und wenn die 
fertig sind, packe ich das große Steuerungsmodul an.. und vereinheitlich 
hier alles, ohne große Sonderbehandlungen.. so weit möglich..

Falls eine aufritt habe ich mir das so überlegt:
1
if (KANAL == KANAL_1){
2
    // Sonderbehandlung 1a
3
}
4
else
5
{
6
  if (KANAL == KANAL_2){
7
    // Sonderbehandlung 1b
8
  }
9
}

usw.

Was haltet ihr von dem Vorgehen???

Vielen Dank!!

von Peter D. (peda)


Lesenswert?

schobbe wrote:
> Bisherige Codegröße (ohne Optimierungen

Du meinst damit hoffentlich nicht -O0.
Wenn ein Programm nicht mit -Os läuft, ist irgendwas faul (z.B. 
fehlendes volatile).


> Die Steuerungsmodule sind etwa funktional zu 90 % identisch (bis auf die
> Namensbezeichnung x1x... x2x..)

Dann sollte es möglich sein, die Variablen pro Kanal in ein Struct 
zusammenzufassen und dann der gemeinsamen Funktion nur den Pointer 
darauf zu übergeben.


Peter

P.S.:
Deine Größenangaben sind auch das Binary, d.h. nicht das Hex oder 
S-record?

von schobbe (Gast)


Lesenswert?

Peter wrote:


>Du meinst damit hoffentlich nicht -O0.
>Wenn ein Programm nicht mit -Os läuft, ist irgendwas faul (z.B.
>fehlendes volatile).

Nee, also volatile ist schon nötig, so viel optimiert der Compiler dann 
anscheinend schon :)

>Dann sollte es möglich sein, die Variablen pro Kanal in ein Struct
>zusammenzufassen und dann der gemeinsamen Funktion nur den Pointer
>darauf zu übergeben.

Wie meinst du das? Kannst du das ein bissel konkreter beschreiben? 
Welchen Vorteil hätte ein struct mit Pointer Übergabe gegenüber einer 
Array-Variante? Also jede bisherigen redundanten Variable durch ein 
Array mit 2 Elementen zu ersten?

>P.S.:
>Deine Größenangaben sind auch das Binary, d.h. nicht das Hex oder
>S-record?

Die Größenangaben stammen aus dem Mapfile. Also ich habe die genutzen 
Flash-Bereiche zusammen addiert. Dort wird ja auch aufgelistet, wieviel 
Flashspeicher jedes Modul benötigt.

Stefan

von schobbe (Gast)


Lesenswert?

Den Vorteil mit den structs und den Pointern gegenüber den Arrays hab 
ich immer noch nicht ganz verstanden.

Könntest du das ein bisschen genauer erklären?

Danke !

von Winfried (Gast)


Lesenswert?

Diese Struct-Sache geht in Richtung Objektorientierung: Daten stehen im 
Zentrum und Funktionen, die mit diesen Daten was machen. Und welches 
Objekt (struct) nun konkret manipuliert werden soll, sagt dir der 
Pointer auf das konkrete Objekt.

Sonderbehandlungen find ich immer Murks, dann lieber das herausfinden, 
was funktionell identisch ist und nur auf andere Daten/Objekte 
angewendet wird. Oder auch in Richtung abstrakte Klassen und 
Konkretisierungen schauen.

Auch wenn du normal C programmierst, kannst du sehr objektorientiert 
denken und vieles davon in diese Richtung umsetzen.

von Winfried (Gast)


Lesenswert?

Nochwas, du kannst auch ein Array anlegen, in denen du mehrer 
struct-Variablen ablegst. So sparst du dir aber die Sache, für jede 
Variable ein neues Array anlegen zu müssen, zumal ja logisch alle 
Variablen eigentlich eine Einheit bilden und so irgendwie 
zusammengehören.

von schobbe (Gast)


Lesenswert?

@Winfried

Also wenn ich dich jetzt richtig verstanden habe meinst du sowas:
1
// Steuerungsmodul
2
3
typedef struct{
4
  typA STRG_Variable_A;
5
  typB STRG_Variable_B;
6
  typC STRG_Variable_C;
7
}Strg_Variablen;
8
9
Strg_Variablen Steuerung1;
10
Strg_Variablen Steuerung2;
11
12
void exec_Steuerung (Strg_Variablen *strg){
13
   strg->STRG_Variable_A ++;
14
   // ...
15
}

Aber was ist daran jetzt der Vorteil gegenüber:
1
// Steuerungsmodul
2
3
#define KANAL_ANZAHL 2
4
5
typedef enum{
6
   KANAL_1,
7
   KANAL_2
8
}enum_Kanal;
9
  typA STRG_Variable_A[KANAL_ANZAHL];
10
  typB STRG_Variable_B[KANAL_ANZAHL];
11
  typC STRG_Variable_C[KANAL_ANZAHL];
12
13
void exec_Steuerung (enum_Kanal Kanal){
14
   STRG_Variable_A[Kanal] ++;
15
   // ...
16
}

>Nochwas, du kannst auch ein Array anlegen, in denen du mehrer
>struct-Variablen ablegst. So sparst du dir aber die Sache, für jede
>Variable ein neues Array anlegen zu müssen, zumal ja logisch alle
>Variablen eigentlich eine Einheit bilden und so irgendwie
>zusammengehören.

Ich sehe ein, dass deine Variante mit den structs übersichtlicher ist.
Aber mir geht es ja hier um Optimierung.. was erzeugt den schmäleren 
Code? Die Array Variante oder die mit den structs.

Reserviert ein struct nicht mehr Speicher wenn die Datentypen wegen dem 
alignment nicht genau in den Speicherbereich passen?

die Pointer schnittstelle braucht ja einen 32 Bit Pointer als 
Übergabeparameter und die enum Variante 8 - 16 Bit.

Wie gesagt muss ich den Code verkleinern. Aber die Übersichtlichkeit 
spielt natürlich auch ne Rolle.

Achso jetzt verstehe ich auch den Argument mit dem Pointer Array..
1
Strg_Variablen* STRG_ARRAY[KANAL_ANZAHL]
2
3
void exec_Steuerung (enum_Kanal Kanal){
4
   (STRG_ARRAY[Kanal]->STRG_Variable_A[Kanal]) ++;
5
   // ...
6
}
7
8
Es muss ja ein bestehender Code geändert werden.

>Sonderbehandlungen find ich immer Murks, dann lieber das herausfinden,
>was funktionell identisch ist und nur auf andere Daten/Objekte
>angewendet wird. Oder auch in Richtung abstrakte Klassen und
>Konkretisierungen schauen.

Wie gesagt es gibt hier 2 zu 90% identische Module.
An einer Stelle ist Steuerung 2 von Steuerung 1 abhängig. Sowas muss ja 
irgendwie behandelt werden. Im Moment sieht man das schön beim 
File-compare.. das z.b. ein If-Zweig unterschiedlich aussieht.

Gruss

von Peter D. (peda)


Lesenswert?

schobbe wrote:
>
1
> void exec_Steuerung (Strg_Variablen *strg){
2
>    strg->STRG_Variable_A ++;
3
>

Hier kann vom Pointer+Displacement der Wert geholt werden (LDD).

> Aber was ist daran jetzt der Vorteil gegenüber:
>
1
> void exec_Steuerung (enum_Kanal Kanal){
2
>    STRG_Variable_A[Kanal] ++;
3
>

Hier muß immer erst aus dem Index die Zieladresse berechnet werden 
(CLR,SUBI,SBCI,LD).


Peter

von Programmierer (Gast)


Lesenswert?

Wie soll jemand, der so elementare Frage hat, einen womöglich noch 
fremden Code, refaktorisieren und optinmieren? Das kann doch nur in die 
Hose gehen...

von schobbe (Gast)


Lesenswert?

>Hier kann vom Pointer+Displacement der Wert geholt werden (LDD).

Was bedeutet LDD?

> void exec_Steuerung (enum_Kanal Kanal){
>    STRG_Variable_A[Kanal] ++;
>

>Hier muß immer erst aus dem Index die Zieladresse berechnet werden
>(CLR,SUBI,SBCI,LD).

Heißt das, dass bei einem Feld Zugriff mehr Maschinenbefehle und damit 
auch mehr Binärcode erzeugt wird?

stefan

von Peter D. (peda)


Lesenswert?

schobbe wrote:
> Was bedeutet LDD?

Ich war in Gedanken beim AVR.
Obs beim HCS08 ähnlich ist, weiß ich nicht.


Peter

von schobbe (Gast)


Lesenswert?

Was war mit der Vermutung, dass es mehr Speicher benötigt, wenn ich 
alles in structs kapsle, als jede Variable in ein array zu packen.

ich werde mich mal erkundigen wie das ist, ob ein pointer zugriff 
weniger code overhead erzeugt als ein array zugriff

stefan

von Gruenschnabel (Gast)


Lesenswert?

>Der Code läuft bereits Serienmäßig auf einem 32k Controller. Aber aus
>Kostengründen soll er auf einen 16K Flash Controller runter.

Wieviel ist denn ein kleinerer Typ billiger? 2 Euro vielleicht? Und wie 
groß ist die Stückzahl/Jahr?

Wenn das Programm zuverlässig läuft, laß die Finger davon. Spätere 
Änderungen wegen neuer Fehler sind in der Regel teurer als die Ersparnis 
beim Einkauf. Gut, bei großen Stückzahlen wird das anders sein.

von Winfried (Gast)


Lesenswert?

Schau auch nicht nur auf Speicherplatz-Reduzierung. Die Lesbarkeit und 
gute Strukturierung ist auch wichtig. Im gesamten Produkt-Lebenszyklus 
muss man ja auch immer wieder mal was am Code machen und ein vermurkster 
Code ist entweder irgendwann gar nicht mehr wartbar oder sorgt für jede 
Menge Aufwand und Fehleranfälligkeit.

Wenn du 2 Module hast, die zu 90% identisch sind, dann kann man es so 
strukturieren, das alles komplett identische herausgelöst und gemeinsam 
genutzt wird und nur der Rest in jedem Modul separat programmiert wird.

Auch noch wichtig: Zu unterscheiden, was Ram und was Rom/Flash kostet 
und wo der Engpass ist. Du hattest ja oben geschrieben, dass ein struct 
evtl. mehr Speicherplatz braucht, aber das wäre ja Ram und ich hatte 
verstanden, du hast vor allem ein Rom/Flash-Problem.

von schobbe (Gast)


Lesenswert?

@Gruenschnabel

>Wieviel ist denn ein kleinerer Typ billiger? 2 Euro vielleicht? Und wie
>groß ist die Stückzahl/Jahr?

Mhm, um wie viel Euro der 16K Controller im Vergleich zum 32K Controller 
günstiger ist, kann ich gar nicht genau sagen. Aber da es hier 
Stückzahlen in der Größenordnung 10^5 bis 10^6 geht, kommt es beim 
Einkauf/Vertrieb auf jeden Cent an.

>Wenn das Programm zuverlässig läuft, laß die Finger davon. Spätere
>Änderungen wegen neuer Fehler sind in der Regel teurer als die Ersparnis
>beim Einkauf. Gut, bei großen Stückzahlen wird das anders sein.

Richtig, wie gesagt ist der Code sehr suboptimal also auch sehr schwer 
wartbar / erweiterbar. Von der Projektleitung wurde auch jede 
Softwareänderung abgelehnt, aber dieser Umstieg von 32K auf 16K ist ein 
wichtiger Schritt. Eben sowenig soll die Funktionalität angefasst 
werden. Deshalb ergeben sich daran auch viele Funktionstests 
(Regressionstests).

@Winfried

>Schau auch nicht nur auf Speicherplatz-Reduzierung. Die Lesbarkeit und
>gute Strukturierung ist auch wichtig. Im gesamten Produkt-Lebenszyklus
>muss man ja auch immer wieder mal was am Code machen und ein vermurkster
>Code ist entweder irgendwann gar nicht mehr wartbar oder sorgt für jede
>Menge Aufwand und Fehleranfälligkeit.

Hier ist das Kind leider schon in den Brunnen gefallen ...

>Wenn du 2 Module hast, die zu 90% identisch sind, dann kann man es so
>strukturieren, das alles komplett identische herausgelöst und gemeinsam
>genutzt wird und nur der Rest in jedem Modul separat programmiert wird.

Ich weiß was du meinst.
Du meinst wenn Modul A und Modul B sich in 90 % ähneln, dann die 90 % in 
eine Art Basis Klasse C auslagern und A und B davon "ableiten". Dieser 
sollen dann die restlichen 10 % unterschiedlichen Code erhalten.

Hier ist die Sache, aber nicht ganz so "einfach".

             Modul A <-> Modul B
Funktion 1   identisch
Funktion 2   identisch
Funktion 3   identisch
Funktion 4   90 % gleich - 10 % unterschiedlich

Nur ist Funktion 4 etwa 1000 Zeilen groß!

Wenn man sich Funktion 4 als Aktivitätsdiagramm vorstellt. Dann verzeigt 
sich bei ganz bestimmten Eingangsparametern A und B etwas anders.. bzw. 
A ist von B UNabhängig an dieser Stelle, aber B nicht von A. Also gibt 
es hier eine "halb-seitige" Abhängigkeit.

Hier etwas als Basisklasse zu definieren und A und B davon abzuleiten 
ist sehr schwierig, bzw. für mich gerade nicht vorstellbar. Wie gesagt 
ist Funktion eine gigantisch aufgeblähte State-Machine mit tausend 
Verschachtelungen ...

Man kann sich das wie ein Mikado-Spiel vorstellen :-)
Ein riesiger Haufen blauer und roter Stäbchen... und du bekommst die 
Aufgabe die roten und blauen auseinander zu ziehen und zwei neue Stapel 
zu bilden, nur müssen die blauen und roten Stäbchen dann wieder genau so 
liegen wie bei der Ausgangssituation....


>Auch noch wichtig: Zu unterscheiden, was Ram und was Rom/Flash kostet
>und wo der Engpass ist. Du hattest ja oben geschrieben, dass ein struct
>evtl. mehr Speicherplatz braucht, aber das wäre ja Ram und ich hatte
>verstanden, du hast vor allem ein Rom/Flash-Problem.

Hier muss ich dir Recht geben.
Das war ein Denkfehler von mir. Natürlich ist es egal ob ich die 
Datenstrukturen als struct oder Array aufbaue, schließlich wird der 
Speicher ja im RAM alokiert. Wenn ich nun den Vorteil betrachte den 
Peter genannt hat (Pointer Zugriff), dann müsste doch ein kleinerer Code 
enstehen, wenn ich die Redundanzauflösung mit Pointern betreibe und 
nicht mir Arrays !?

Vielen Dank!!

von Programmierer (Gast)


Lesenswert?

> Aber da es hier Stückzahlen in der Größenordnung 10^5 bis 10^6 geht,
> kommt es beim Einkauf/Vertrieb auf jeden Cent an.

Solche Stückzahlen und Du hast keinen Schimmer wie man so etwas macht?

von schobbe (Gast)


Lesenswert?

>Solche Stückzahlen und Du hast keinen Schimmer wie man so etwas macht?

Ich bin derjenige der das jetzt ausbaden darf, ja.

Wie gesagt habe ich ja schon einen Ansatz genannt, wie ich die 
Redundanzauflösung verwirklich würde. Jetzt geht es nur noch darum, was 
die beste Lösung ist.

Wenn ich die Applikation erstellt hätte, hätte ich von vornherein eine 
ganz andere Architektur gewählt. Aber nun ist es eben so und ich muss 
die Redundanz rauskriegen um in erster Linie Codegröße einzusparen.

von Gruenschnabel (Gast)


Lesenswert?

Vielleicht ist es doch einfacher/sicherer das Programm oder die 
kritischen Funktionen neu zu schreiben. Da die Programmabläufe wohl 
bekannt sind, kann man von Anfang an eine bessere Strukturierung 
vornehmen.
Bei der Stückzahl wäre der Aufwand gerechtfertigt. Wenn's zu schwierig 
werden sollte, sag Bescheid ... :-)

von schobbe (Gast)


Lesenswert?

>Vielleicht ist es doch einfacher/sicherer das Programm oder die
>kritischen Funktionen neu zu schreiben. Da die Programmabläufe wohl
>bekannt sind, kann man von Anfang an eine bessere Strukturierung
>vornehmen.
>Bei der Stückzahl wäre der Aufwand gerechtfertigt. Wenn's zu schwierig
>werden sollte, sag Bescheid ... :-)

Wenn es so einfach wäre würde ich dir Recht geben ... :-)

Aber hier gibt es 3 Faktoren:
- Termindruck
- Das Risiko durch eine komplette Neuentwicklung einen Fehler 
einzubauen, der durch die Modultests / Systemtests nicht erkannt wird.
(vermeindlicher "Qualitätsverlust")
- steigende Kosten

Hier wird ganz klar von der Projektleitung: "Never touch a running 
system" propagiert. Was ja auch irgendwo verständlich ist. Man stelle 
sich vor es wurden schon zig tausend Euro in die Entwicklung investiert 
und dann nochmal zig tausend Euro für Systemtests.

Wenn man nun vorschlägt, dass man alles neu entwickeln möchte sind die 
davon nicht wirklich begeistert.

Diese 3 Faktoren verursachen Kosten!
Ziel ist es jedoch Kosten einzusparen.

Man siehe dass das 2 sich widerstrebende Ziele sind :-)

von schobbe (Gast)


Lesenswert?

Wenn ich nun den Vorteil betrachte den
Peter genannt hat (Pointer Zugriff), dann müsste doch ein kleinerer Code
enstehen, wenn ich die Redundanzauflösung mit Pointern betreibe und
nicht mir Arrays !?

von Oliver (Gast)


Lesenswert?

>dann müsste doch ein kleinerer Code enstehen, wenn ich die Redundanzauflösung 
>mit Pointern betreibe und nicht mir Arrays !?

Du kümmerst dich um die falschen Dinge. Jetzt schon über die Optimierung 
im Bereich einzelner Bytes nachzudenken, ohne überhaupt einen Plan für 
das Ganze zu haben, ist Blödsinn.

Arrays und Pointer sind in C (und nicht nur dort) engstens verwand, und 
ergeben bei gleicher Funktionalität am Ende auch gleich großen Code. Was 
du vermeiden solltest, ist ein Array, in dem verschiedene Variablen 
drinstecken. So etwas ist am Ende nicht wartbar.
1
typedef struct
2
{
3
   char Status;
4
   char Grenzwert;
5
} datenstruct;
6
7
datenstruct Daten_Kanal_1;
8
datenstruct Daten_Kanal_2;
9
datenstruct Daten_Kanal_3;
10
11
...
12
//Aufruf
13
exec_steuerung(&Daten_Kanal_1);
14
exec_steuerung(&Daten_Kanal_2);
15
exec_steuerung(&Daten_Kanal_3);
16
17
void exec_steuerung(datenstruct *daten);
18
{
19
   char dummy = daten->Status;
20
}

So würde ich das, ausgehend von deinem Beispiel ganz oben, in etwa 
machen.

Oliver

von schobbe (Gast)


Lesenswert?

>Arrays und Pointer sind in C (und nicht nur dort) engstens verwand, und
>ergeben bei gleicher Funktionalität am Ende auch gleich großen Code. Was
>du vermeiden solltest, ist ein Array, in dem verschiedene Variablen
>drinstecken. So etwas ist am Ende nicht wartbar.

Mir ist auch klar, dass
1
data_types[Kanal_1].Grenzwert = 10;

äquivalent zu
1
data_types->Grenzwert = 10;

ist.

sofern Kanal_1 das 1. Element im Array ist.


An ein Array mit verschiedenen Variablen hatte ich auch nie gedacht.

An was ich dachte ist für JEDE REDUNDANTE Variable ein Array mit (in 
diesem Fall) 2 Elementen zu erzeugen.

Oder Alternativ FÜR ALLE REDUNDANTE Variablen einen struct anzulegen und 
dann zwei Variablen von diesem Typ zu definieren.

Ich glaube für meine Ansprüche und zum besten Refacotoring des Codes ist 
es

einen solchen Codeteil:
1
if (analogwert_1 > grenzwert_1)
2
{
3
   set_grenzwert_fehler_1();
4
}

so abzuändern (EXEMPLARISCH !!!)
1
if (analogwert_x[KANAL] > grenzwert_x[KANAL])
2
{
3
   set_grenzwert_fehler_x(KANAL);
4
}

Gruss

von Gruenschnabel (Gast)


Lesenswert?

>Hier wird ganz klar von der Projektleitung: "Never touch a running
>system" propagiert. Was ja auch irgendwo verständlich ist.

Es ist völlig egal, was Du machst: Du mußt das laufende System ändern.
Meine Erfahrung ist die, daß mir einer Neuprogrammierung am meisten 
Platz gespart werden kann.
Die große Frage wird keiner beantworten können, ob durch Veränderungen 
am bestehenden Programm, die benötigte Code-Einsparung erreicht werden 
kann. Wenn der Compiler halbwegs gut optimiert hat, vermutlich nicht!

Im Laufe einer Entwicklung wird ein Programm häufig verändert, um 
geänderten Vorgaben gerecht zu werden. Bereits hier läßt man die 
funktionierenden Teile so, wie sie sind, um keine neuen Fehler 
einzubringen. Somit entsteht ein Flickwerk mit Ballst, dessen Code 
zwangsläufig größer ausfällt. Bei Dir scheint das ja wohl der Fall zu 
sein.

Viel Code kann man natürlich einsparen, wenn man große Teile in 
Assembler optimiert. Aber .....

von Oliver (Gast)


Lesenswert?

Eigentlich wäre der erste Schritt, den aktuellen Speicherverbrauch zu 
analysieren, um dann zu entscheiden, wo das größte Optimierungspotential 
besteht.

Fragen wie diese:

>Reserviert ein struct nicht mehr Speicher wenn die Datentypen wegen dem
>alignment nicht genau in den Speicherbereich passen?

zeigen da noch Nachholbedarf.

Oliver

von Programmierer (Gast)


Lesenswert?

> Nur ist Funktion 4 etwa 1000 Zeilen groß!

Reif für die Tonne... Aber mal ganz ehrlich:

Katastrophen-Code zu reparieren geht natürlich, aber dazu braucht man:

  a.) Sehr viel Erfahrung
  b.) Sehr viel Erfahrung
  c.) Experte der verwendeten Sprache
  d.) Sehr viel Erfahrung
  e.) Sehr viel Erfahrung
  f.) Experte des Problemfelds
  g.) Sehr viel Erfahrung
  h.) Sehr viel Erfahrung

Ach, und habe ich schon erwähnt, dass man für solche Aktioen viel 
Erfahrung benötigt?

Alles andere führt ins Desaster.

von Gast4 (Gast)


Lesenswert?

i.) sehr viel Zeit

Gast4

von Winfried (Gast)


Lesenswert?

Du kannst das grundsätzlich so machen, wie du es vorgeschlagen hast. Das 
wird wohl der schnellste Weg sein, ohne viel an der Struktur des 
Gesamtprogrammes zu ändern. Und das ist ja glaub ich dein Ziel.

Schlussendlich läuft alles auf eine sinnvolle Abwägung raus, 
Änderungsaufwand versus vernünftige Struktur.

Ich kenne solche Projekte auch, wo es mich anwidert, überhaupt was dran 
zu machen, aber man muss und es muss billig sein. Dann muss man alles, 
was man über saubere Programmierung gelernt hat über Board werfen und 
kostensparend dranrumstricken...

Viel Erfolg!

von Oliver (Gast)


Lesenswert?

>Dann muss man alles,
>was man über saubere Programmierung gelernt hat über Board werfen und
>kostensparend dranrumstricken...

Muß man das? Bei Stückzahlen in der Größenordnung 10^5 bis 10^6 und der 
Produktklasse "Steuerung" schiesst man sich da selber ganz schnell ins 
Knie. Jede "Rumstrickerei" holt einen da früher oder später wieder ein.

Mach ein sauberes Konzept, schätz den Aufwand sicher ab, und dann mit 
der Projektleitung abstimmen, die soll entscheiden. Dafür wird die 
bezahlt.

Oliver

von schobbe (Gast)


Lesenswert?

Danke für die vielen Beiträge!

Um wirklich was am Steuerungsalgorithmus selbst zu optimieren braucht 
man viel Erfahrung und auch viel Expertenwissen, da gebe ich euch völlig 
recht.
(Das versuche ich mir Stück für Stück anzueignen, man muss ja irgendwo 
ins Projekt hineinwachsen. Also abgesehen davon was man aus dem 
Pflichtenheft, SDD herauslesen kann).

Bisher habe ich keine Zeile Code geändert.
Ich habe den Code nur auf Optimierungspotential hin untersucht. 
Hauptsächlich habe ich mich erstmal auf Code Redundanz konzertiert, die 
zu Genüge in diesem Projekt vorhanden ist.

Beispielsweise hat Modul A 5 Funktionen. Diese 5 Funktionen beinhalten 
exakt den selben Code bis auf die Verwendung von verschiedenen Variablen 
und verschiedenen AD Kanäle. Geschätzt kann man hier bis zu 80 % Code 
einsparen durch die Verwendung eines Unterfunktion Prototypes mit 
passenden Schnittstellen.

@Winfried: Danke, ich werd mein bestes tun ;-)

Module die doppelt vorhanden sind (redundant) versuche ich zu 
vereinheitlichen in dem ich die spezifischen Variablen kapsle und den 
Funktionen parametrierbare Schnittstellen verpasse.

Wie gesagt analysiere ich im Moment nur und stelle Konzepte auf wie man 
optieren könnte. Ich will erst so gut wie möglich alle Querverbindungen 
zwischen den Modulen identifizieren bevor ich damit beginne etwas zu 
ändern.

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.