[Zlecę] wykonanie interface'u Ethernetowego do archi

Moją magisterkę na ARMa z 8k flash i 32k flash piszę w hardcore C++ z:

- obiektami

- szablonami

- metaprogramowaniem (łącznie z testem, czy boost::mpl zadziała) W planach właśnie dodanie polimorfizmu dynamicznego.

Dopisałem do projektu następujące klasy: class foo{ public: virtual void f(){uart_print("foo\r\n");} }; class bar:public foo{ void f(){uart_print("bar\r\n");} }; class foobar:public bar{ void f(){uart_print("foobar\r\n");} }; class oof:public foo{ void f(){uart_print("oof\r\n");} };

I do main dopisałem: int ll=uart_read_int(); foo f; bar b; foobar fb; oof o; foo* ff; if(ll==1){ ff=&f; }else if(ll==2){ ff=&b; }if(ll==3){ ff=&fb; }else{ ff=&o; } ff->f();

Binarka przytyła po tym o 200 bajtów: text data bss dec hex filename 4012 8 168 4188 105c firmware.elf 4212 8 168 4388 1124 firmware2.elf

- 28 bajtów to sam wypisywany tekst

- po 8 bajtów na metodę [1]

- 48 bajtów dodatkowego kodu w main (o tym za chwilę)

- po 16 bajtów na vtable dla klasy

W main został wygenerowany następujący kod: 0x000006a4 <+56>: ldr r3, [pc, #224] ; (0x788 <main()+284>) 0x000006a6 <+58>: str r3, [sp, #4] 0x000006a8 <+60>: ldr r3, [pc, #224] ; (0x78c <main()+288>) 0x000006aa <+62>: str r3, [sp, #8] 0x000006ac <+64>: ldr r3, [pc, #224] ; (0x790 <main()+292>) 0x000006ae <+66>: str r3, [sp, #12] 0x000006b0 <+68>: ldr r3, [pc, #224] ; (0x794 <main()+296>) 0x000006b2 <+70>: str r3, [sp, #16] 0x000006b4 <+72>: ldr r3, [r4, #0] //czyli po 2 instrukcje na stworzenie obiektu na stosie

0x000006b6 <+74>: cmp r3, #1 0x000006b8 <+76>: beq.n 0x6c6 <main()+90> 0x000006ba <+78>: cmp r3, #2 0x000006bc <+80>: beq.n 0x6ca <main()+94> 0x000006be <+82>: cmp r3, #3 0x000006c0 <+84>: bne.n 0x6ce <main()+98> 0x000006c2 <+86>: add r0, sp, #12 0x000006c4 <+88>: b.n 0x6d0 <main()+100> 0x000006c6 <+90>: add r0, sp, #4 0x000006c8 <+92>: b.n 0x6d0 <main()+100> 0x000006ca <+94>: add r0, sp, #8 0x000006cc <+96>: b.n 0x6d0 <main()+100> 0x000006ce <+98>: add r0, sp, #16 // 13 instrukcji na obsłużenie 4 if-else 0x000006d0 <+100>: ldr r3, [r0, #0] 0x000006d2 <+102>: ldr r3, [r3, #0] 0x000006d4 <+104>: blx r3 // 3 instrukcje na wywołanie funkcji wirtualnej

To gdzie są te straszne koszta 'virtual'?

[1] Dump of assembler code for function foo::f(): 0x00000670 <+0>: ldr r0, [pc, #4] ; (0x678 <foo::f()+8>) 0x00000672 <+2>: b.w 0x3b4 <uart_print(char const*)> 0x00000676 <+6>: nop 0x00000678 <+8>: lsrs r7, r3, #18 0x0000067a <+10>: movs r0, r0
Reply to
Michoo
Loading thread data ...

Ale to jest jakieś nieporozumienie - ochrona praw producenta nie sięga tak daleko. Ochronie podlegają równiez prawa autora.

Na przykład ja zawsze zastrzegam projektując jakąkolwiek elektronikę, że klient otrzymuje _niewyłączne_ prawo do korzystania z projektu. Przecież nie wymyślę nowej konfiguracji przetwornicy czy też nie policze inaczej transformatora dla podanych parametrów.

Uprzedzając: żylem 20 lat z programowania i tu też zawsze bylo podobne zastrzeżenie - uprzedzałem klientów, że o ile rzeczy, które sa unikalnego dla niego można trakttować na wyłączność, to sposoby realizacji - jako nieunikalne - nie dają się zastrzec. Klienci na przykład chcieli zastrzec interfejs. To tlumaczę, że np. układ pól, przycisków i sposób nawigacji są uniwersalne i nie mogę go uznać za zastrzeżony tylko dla nich, bo to byłoby absurdem.

(tak, wiem - Apple i inni patentują takie pierdoły, że zęby bolą)

Reply to
RoMan Mandziejewicz

Dnia 05-05-2012 o 22:50:52 Michoo <michoo snipped-for-privacy@vp.pl napisał(a):

[snip kod]

[snip szczegóły]

Nie będzie to żaden argument w dyskusji na temat metod wirtualnych, ale z ciekawości do małego programu w C+asm (na PIC24) dopisałem następujące wiersze:

const char msg1[] = "foo\r\n"; const char msg2[] = "bar\r\n"; const char msg3[] = "foobar\r\n"; const char msg4[] = "off\r\n";

Następnie w main():

const char *msg; int ll = recv(0); /* odczyt z czegoś innego niż uart, nieistotne z czego,

0 to numer kanału */

if (ll == 1) { msg = msg1; } else if (ll == 2) { msg = msg2; } if (ll == 3) { /* tuś się chyba pomylił, ale zostawiłem bez else, żeby było tak samo */ msg = msg3; } else { msg = msg4; } uart_send_str(msg);

Przy -O0 binarka zwiększyła się z 1452 do 1575 bajtów (123 bajty). Przy -Os binarka zwiększyła się z 1197 do 1269 bajtów (72 bajty).

Po poprawieniu buga z "else":

-O0 : 1452 do 1578 (126)

-Os : 1197 do 1287 (90)

Ogólna zmiana przy włączeniu optymalizacji jest mała, bo to program tylko do testowania sporego kawałka kodu pisanego w asemblerze i C tam mało jest.

Sam nie wiem czy i jakie wnioski z tego wyciągać.

ae

Reply to
Andrzej Ekiert

Ja nie mam nic przeciwko - klient nasz pan. Tak chce, tak ma, taka bedzie tez faktura. Przeciez nie powiem nie ;-) Dla niektorych klientow jest to wazne, dla innych nie ma znaczenia. Byl jeden klient, gdzie przy dyskusji o kodzie zrodlowym padlo sdtwierdzenie: "Fabryka bedzie wiedziala jak to zaprogramowac? Tak? No to mi kod zrodlowy nie potrzebny - jak cos bede chcial zmienic to mi to zmienicie".

To jest roznie. U mnie tematy sa tak rozne od siebie, ze tego typu decyzje sa indywidualne dla kazdego projektu.

Ano mielismy jednego co chcial - zastrzeglismy. Znaczy klient zastrzegl sam, mysmy mu cala papierkologie przygotowali.

Jak placi? Prosze bardzo, pomozemy.

Reply to
Jerry1111

[...] Tylko zauważ, że chciałem tu zaprezentować koszt związany z funkcjami wirtualnymi - użycie klas i funkcji wirtualnych do wypisywania kilku napisów to 'trochę' głupi pomysł.

Odpowiednikiem funkcji wirtualnych z którym się spotkałem w C jest wskaźnik na funkcję a z wtedy użycie metod wirtualnych to dodatkowy koszt VTABLE.

Rzeczywiście się pomyliłem pisząc kod, ale w poście statystyki są dla poprawionego kodu, przeczyłem sam kod.

  • 128 bajtów O0
  • 72 bajty Os
  • 132 bajty O0

Kompiluję na gcc-4.7.0 z:

COMMON_FLAGS= -ggdb -Os $(INCLUDES) -mcpu=cortex-m3 -mthumb

-D__thumb2__ -msoft-float -mfloat-abi=soft CXXFLAGS=$(COMMON_FLAGS) -std=gnu++11 -fno-exceptions -fno-rtti

Że kod w THUMB jest wydajniejszy niż w PIC32 ;) I że hardcore c++ bez optymalizacji jest małą masakrą - całość przy O0 spuchła do 8176 - prawie 2 razy (a przebudowałem tylko projekt, bez bibliotek).

Reply to
Michoo

Wierze. Moje doswiadczenie bylo na Nios2 Altery. Niewykluczone ze to Altera cos pokrecila. Mam to gdzies udokumentowane, ale nie chce mi sie szukac - za pozno. Z drugiej strony to bylo gcc, wiec czemu mialo by nie dzialac?

OIDP to pojawienie sie metody virtual (jednej) skutkowalo zlinkowaniem dodatkowych 15 czy 20kB. OIDP byla mozliwosc naprawienia tego kombinacja switchy do gcc. OIDP rozwiazanie tego problemu zajelo mi mniej niz 3 dni ;-)

Reply to
Jerry1111

Dnia 06-05-2012 o 00:26:23 Michoo <michoo snipped-for-privacy@vp.pl napisał(a):

Zerknąłem w kod wynikowy: same instrukcje to 14 słów (42 bajty). Większy kod wynika ze sposobu przechowywania stringów we Flashu - pakowane są w 2 młodsze bajty trzybajtowego słowa. A jak jest nieparzyście, to na ostatni bajt traci się całe słowo - czyli na stringi poszło 39. A 9 bajtów się nie mogę doliczyć...

PIC24. Kod jest chyba dość podobny, ale stringi się efektywniej pakują w ARMie.

ae

Reply to
Andrzej Ekiert

U mnie 15, ale tylko po 2 bajty na każdą.

W THUMB jest 2 bajty/opcode poza kilkoma przypadkami, więc na tym sporo zarabia.

Pewnie tak - wyrównanie do 2 bajtów na THUMB(ale 4 na ARM).

Reply to
Michoo

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.