Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Оптимизация кода.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Jenya7
У меня мэйн функция выходит довольно большая. Многие куски кода можно было вынести в отдельные функции. Но мне важна скорость а переход в функцию и обратно это 4 такта если я не ошибаюсь. помножить на количество функций... или это уже паранойя? и еще я заметил если функцию вынести в отдельный модуль код увеличивается примерно на 100 байт.

Ruslan1
Цитата(Jenya7 @ Dec 31 2015, 09:50) *
У меня мэйн функция выходит довольно большая. Многие куски кода можно было вынести в отдельные функции. Но мне важна скорость а переход в функцию и обратно это 4 такта если я не ошибаюсь. помножить на количество функций... или это уже паранойя? и еще я заметил если функцию вынести в отдельный модуль код увеличивается примерно на 100 байт.

Это паранойя. Имеет право присутствовать (в разумных пределах) при написании специальных функций, например в прерывании или в ограниченном по объему пространстве (бутлоадер, например). Но никак не при простой писанине в main().
Если такты так критичны- значит что-то не так с выбором элементной базы (нет запаса по скорости/размеру памяти).
ну и инлайны никто не отменял.

Про размер: функция должна выполнять одну функцию, потому она и названа функцией sm.gif
Не пихайте все вместе, никакого выигрыша это не принесет, одна головная боль.

P.S. Жена с кухни выгнала, делать нечего- вот и пишу любые ответы на любые вопросы. С наступающим! sm.gif
Jenya7
Цитата(Ruslan1 @ Dec 31 2015, 14:19) *
Это паранойя. Имеет право присутствовать (в разумных пределах) при написании специальных функций, например в прерывании или в ограниченном по объему пространстве (бутлоадер, например). Но никак не при простой писанине в main().
Если такты так критичны- значит что-то не так с выбором элементной базы (нет запаса по скорости/размеру памяти).
ну и инлайны никто не отменял.

Про размер: функция должна выполнять одну функцию, потому она и названа функцией sm.gif
Не пихайте все вместе, никакого выигрыша это не принесет, одна головная боль.

P.S. Жена с кухни выгнала, делать нечего- вот и пишу любые ответы на любые вопросы. С наступающим! sm.gif


спасибо. с наступающим. sm.gif
HardEgor
Цитата(Jenya7 @ Dec 31 2015, 13:50) *
У меня мэйн функция выходит довольно большая. Многие куски кода можно было вынести в отдельные функции. Но мне важна скорость а переход в функцию и обратно это 4 такта если я не ошибаюсь. помножить на количество функций... или это уже паранойя? и еще я заметил если функцию вынести в отдельный модуль код увеличивается примерно на 100 байт.

4 такта это где? Может и больше быть.
Если вам надо сократить код, то в функцию выносим часто повторяющиеся куски кода.
Если надо ускорить работу, то не выносим, но тогда естественно объем кода увеличится.
Для удобства написания можно писать функции, но с ключевым словом inline - тогда код функции будет линейно включен в программу при компиляции.
Jenya7
Цитата(HardEgor @ Dec 31 2015, 15:39) *
4 такта это где? Может и больше быть.
Для удобства написания можно писать функции, но с ключевым словом inline - тогда код функции будет линейно включен в программу при компиляции.

а где лучше прописать инлайновую функцию?
так
Код
module.h
static inline void Func(void)
{
     // do something
}

или так
Код
module.h
void Func(void);

module.c
inline void Func(void)
{
     // do something
}


Цитата(HardEgor @ Dec 31 2015, 15:39) *
4 такта это где? Может и больше быть.
Если вам надо сократить код, то в функцию выносим часто повторяющиеся куски кода.
Если надо ускорить работу, то не выносим, но тогда естественно объем кода увеличится.

в том то и был вопрос много ли я выигрываю не вынося код в отдельные функции
Dog Pawlowa

Цитата(Jenya7 @ Dec 31 2015, 14:38) *
а где лучше прописать инлайновую функцию?


Как в месте вызова будет встроена inline функция, если текст ее не виден?
Отсюда и исходите.


Цитата(Jenya7 @ Dec 31 2015, 14:38) *
в том то и был вопрос много ли я выигрываю не вынося код в отдельные функции


Важно, что вы теряете - понимание кода, понятную структуру, иерархию в проекте.

Сейчас все контроллеры стоят практически одинаково, что AVR, что CM4.
Есть ли смысл затруднять себе жизнь?
Кстати, если разрешить максимальную оптимизацию, то сам компилятор развернет некоторые функции.
toweroff
Цитата(Dog Pawlowa @ Dec 31 2015, 15:15) *
Кстати, если разрешить максимальную оптимизацию, то сам компилятор развернет некоторые функции.

живой пример - Keil 5, последний
с -O0 размер кода 33кб
с -O3 - 22кб
с включенной Cross-Module optimization - 13(!!!)кб

правда, не смотрел, как там функции разворачиваются sm.gif
HardEgor
Цитата(Jenya7 @ Dec 31 2015, 17:38) *
в том то и был вопрос много ли я выигрываю не вынося код в отдельные функции

Дак откуда же кто знает. Код у вас, берем и считаем на циклах которые критичны для вас по времени.

Цитата(Dog Pawlowa @ Dec 31 2015, 18:15) *
Сейчас все контроллеры стоят практически одинаково, что AVR, что CM4.
Есть ли смысл затруднять себе жизнь?

Т.е. надо затруднить себе жизнь освоением новой архитектуры или нового процессора? sm.gif
Dog Pawlowa
Цитата(HardEgor @ Dec 31 2015, 15:33) *
Т.е. надо затруднить себе жизнь освоением новой архитектуры или нового процессора?

Это рутинная работа, отсидеться в кустах все равно не получится.
SlavaV
Цитата(Jenya7 @ Dec 31 2015, 15:50) *
У меня мэйн функция выходит довольно большая. Многие куски кода можно было вынести в отдельные функции. Но мне важна скорость а переход в функцию и обратно это 4 такта если я не ошибаюсь. помножить на количество функций... или это уже паранойя? и еще я заметил если функцию вынести в отдельный модуль код увеличивается примерно на 100 байт.


Каждый разработчик решает для себя сам исходя из размеров проекта, что использовать, какую методологию: спагетти-код (в Вашем случае), структурное, объектно-ориентированное программирование

Всё упирается в дальнейшую возможность поддержки и расширения. Если у Вас проект до 100 строк кода и завтра про него забудете навсегда зачем заморачиваться со структурой и тем более с проектированием объектов (классов).

PS Но вот если у Вас перспективы вырасти до 1 млн. строк кода то тут уже только объектно-ориентированное программирование
smalcom
Цитата(Jenya7 @ Dec 31 2015, 09:50) *
У меня мэйн функция выходит довольно большая. Многие куски кода можно было вынести в отдельные функции. Но мне важна скорость а переход в функцию и обратно это 4 такта если я не ошибаюсь. помножить на количество функций... или это уже паранойя? и еще я заметил если функцию вынести в отдельный модуль код увеличивается примерно на 100 байт.


главное чтобы костюмчик сидел компилятор хороший был
Код
smalcom [ ~/test_gc ]$ cat mod.h mod.c main.c
int foo(int p);
int foo(int p)
{
volatile int t;

    t = p * 2;

    return t * 2;
}
#include "mod.h"

int main()
{
volatile int k = 4;

    k = foo(k);
    
    return 0;
}


Код
smalcom [ ~/test_gc ]$ gcc -c main.c -flto -O2 -o main.o && gcc -c mod.c -flto -O2 -o mod.o && gcc main.o mod.o -flto -O2 -o prog1
smalcom [ ~/test_gc ]$ objdump -h -S ./prog1 | grep \<main\> -A 12
00000000004003a0 <main>:
  4003a0:       c7 44 24 f8 04 00 00    movl   $0x4,-0x8(%rsp)
  4003a7:       00
  4003a8:       8b 44 24 f8             mov    -0x8(%rsp),%eax
  4003ac:       01 c0                   add    %eax,%eax
  4003ae:       89 44 24 fc             mov    %eax,-0x4(%rsp)
  4003b2:       8b 44 24 fc             mov    -0x4(%rsp),%eax
  4003b6:       01 c0                   add    %eax,%eax
  4003b8:       89 44 24 f8             mov    %eax,-0x8(%rsp)
  4003bc:       31 c0                   xor    %eax,%eax
  4003be:       c3                      retq  
  4003bf:       90                      nop

и никаких лишних вызовов
Dog Pawlowa
Цитата(smalcom @ Jan 3 2016, 01:08) *
главное чтобы костюмчик сидел компилятор хороший был

Не уверен, что это корректный пример, с одной функцией в том же файле.
Более интересно такое:

Код
typedef void (*tVECTOR)(void);
const tVECTOR function[stQTY] = {Reset, Init, Run, Failure};

void main(void)
{
    InitStateService();
    for (;;)
    {
        event=GetEvent();
        function[state]();
        event=0;
    }
}

smalcom
Цитата
Не уверен, что это корректный пример, с одной функцией в том же файле.

с чего вдруг один? три файла использовано, две компилируемых единицы...

Цитата
Более интересно такое:

это кардинально противоположно тому, что хотел ТС...


а-а-а-а... понял, понял. НГ. Поправляйтесь))



Тем не менее

Цитата
typedef void (*tVECTOR)(void);

void Reset() {}
void Init() {}
void Run() {}
void Failure() {}
void InitStateService() {}
int GetEvent() {}

const tVECTOR function[] = {Reset, Init, Run, Failure};

int event;
int state;

void main(void)
{
InitStateService();
for (;;)
{
event=GetEvent();
function[state]();
event=0;
}
}


без оптимизации
Код
00000000004004b0 <main>:
  4004b0:       55                      push   %rbp
  4004b1:       48 89 e5                mov    %rsp,%rbp
  4004b4:       b8 00 00 00 00          mov    $0x0,%eax
  4004b9:       e8 e4 ff ff ff          callq  4004a2 <InitStateService>
  4004be:       b8 00 00 00 00          mov    $0x0,%eax
  4004c3:       e8 e1 ff ff ff          callq  4004a9 <GetEvent>
  4004c8:       89 05 3e 05 20 00       mov    %eax,0x20053e(%rip)        # 600a0c <event>
  4004ce:       8b 05 3c 05 20 00       mov    0x20053c(%rip),%eax        # 600a10 <state>
  4004d4:       48 98                   cltq  
  4004d6:       48 8b 04 c5 a0 05 40    mov    0x4005a0(,%rax,8),%rax
  4004dd:       00
  4004de:       ff d0                   callq  *%rax
  4004e0:       c7 05 22 05 20 00 00    movl   $0x0,0x200522(%rip)        # 600a0c <event>
  4004e7:       00 00 00
  4004ea:       eb d2                   jmp    4004be <main+0xe>
  4004ec:       0f 1f 40 00             nopl   0x0(%rax)


-O2 -flto
Код
00000000004003a0 <main>:
  4003a0:       eb fe                   jmp    4003a0 <main>

Dog Pawlowa
Цитата(smalcom @ Jan 3 2016, 16:30) *
Тем не менее

Дизассемблер в этом виде мало что дает, т.к. преамбулы не видны.
А вообще напрашивается вывод, что нужно правильно закладывать ресурсы, чтобы хватало на все, в том числе на структурирование проекта.
smalcom
Цитата
Дизассемблер в этом виде мало что дает, т.к. преамбулы не видны.

вот для повышения общего уровня образования. скажите мне, что вам даст т.н. "преамбула"?
Dog Pawlowa
Цитата(smalcom @ Jan 3 2016, 22:36) *
что вам даст т.н. "преамбула"?

Мне, и в общем случае - ничего.
Может, в конкретном случае это даст что-то топикстартеру (а именно он интересовался потерями быстродействия на вызов функций):
Цитата(Jenya7 @ Dec 31 2015, 10:50) *
переход в функцию и обратно это 4 такта если я не ошибаюсь

Ошибается, еще регистры сохранять надо, а при оптимизации без функций у компилятора больше возможностей.
smalcom
Цитата
Может, в конкретном случае это даст что-то топикстартеру (а именно он интересовался потерями быстродействия на вызов функций):

я вам отвечу: ничего она не даст. если вы посмотрите на листинг, то увидите, что ничего из сторонних адресов(и др. ресурсов) не используется.

вот с преамбулой для авр
Код
prog:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .data         00000000  00800100  000000a8  0000011c  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  1 .text         000000a8  00000000  00000000  00000074  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .stab         00000078  00000000  00000000  0000011c  2**2
                  CONTENTS, READONLY, DEBUGGING
  3 .stabstr      00000058  00000000  00000000  00000194  2**0
                  CONTENTS, READONLY, DEBUGGING
  4 .comment      00000011  00000000  00000000  000001ec  2**0
                  CONTENTS, READONLY
  5 .note.gnu.avr.deviceinfo 00000040  00000000  00000000  00000200  2**2
                  CONTENTS, READONLY
  6 .debug_info   000006cc  00000000  00000000  00000240  2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_abbrev 0000066e  00000000  00000000  0000090c  2**0
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_line   0000001d  00000000  00000000  00000f7a  2**0
                  CONTENTS, READONLY, DEBUGGING
  9 .debug_str    00000255  00000000  00000000  00000f97  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:   0c 94 3e 00     jmp     0x7c   ; 0x7c <__ctors_end>
   4:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
   8:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
   c:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  10:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  14:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  18:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  1c:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  20:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  24:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  28:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  2c:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  30:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  34:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  38:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  3c:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  40:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  44:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  48:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  4c:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  50:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  54:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  58:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  5c:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  60:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  64:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  68:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  6c:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  70:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  74:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>
  78:   0c 94 48 00     jmp     0x90   ; 0x90 <__bad_interrupt>

0000007c <__ctors_end>:
  7c:   11 24           eor     r1, r1
  7e:   1f be           out     0x3f, r1       ; 63
  80:   cf ef           ldi     r28, 0xFF      ; 255
  82:   d0 e1           ldi     r29, 0x10      ; 16
  84:   de bf           out     0x3e, r29      ; 62
  86:   cd bf           out     0x3d, r28      ; 61
  88:   0e 94 4e 00     call    0x9c   ; 0x9c <main>
  8c:   0c 94 4f 00     jmp     0x9e   ; 0x9e <exit>

00000090 <__bad_interrupt>:
  90:   0c 94 00 00     jmp     0      ; 0x0 <__vectors>

00000094 <Reset>:
  94:   08 95           ret

00000096 <Failure>:
  96:   08 95           ret

00000098 <Run>:
  98:   08 95           ret

0000009a <Init>:
  9a:   08 95           ret

0000009c <main>:
  9c:   ff cf           rjmp    .-2            ; 0x9c <main>

0000009e <exit>:
  9e:   f8 94           cli
  a0:   0c 94 52 00     jmp     0xa4   ; 0xa4 <_exit>

000000a4 <_exit>:
  a4:   f8 94           cli

000000a6 <__stop_program>:
  a6:   ff cf           rjmp    .-2            ; 0xa6 <__stop_program>
Dog Pawlowa
Цитата(smalcom @ Jan 4 2016, 10:27) *
я вам отвечу: ничего она не даст.

Это потому что функции пустые, в них не изменяются регистры.
Допустим, регистры все-таки изменяются, тогда они при вызове будут сохраняться, а при возврате - восстанавливаться, и время, потраченное на это, может быть намного больше чем собственно сохранение-восстановления PC.
Это может быть определяющим для выбора цикл с функциями/цикл без функций

Вот начало какой-то функции текущего проекта на MSP430, перед выполнением значащих действий 6 подготовительных команд:

Код
void ConvertStatSeconds(unsigned long sec)
{   unsigned long my_hour;
ConvertStatSeconds:
00D60C    120A               push.w  R10
00D60E    120B               push.w  R11
00D610    1208               push.w  R8
00D612    1209               push.w  R9
00D614    4C08               mov.w   R12,R8
00D616    4D09               mov.w   R13,R9
    my_hour=sec/3600;
00D618    403E 0E10          mov.w   #0xE10,R14
......


А вот функция инициализации портов, в которой регистры не искажаются. "Две большие разницы"

Код
ClockConfiguration:
00E614    40F2 0056 0056     mov.b   #0x56,&DCOCTL
    BCSCTL1=0x7;                //  CPU faster  RSEL=7
00E61A    40F2 0007 0057     mov.b   #0x7,&BCSCTL1
    BCSCTL2=SELS;               //select SMCLK=XT2CLK
00E620    42F2 0058          mov.b   #0x8,&BCSCTL2
    WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
00E624    40B2 5A80 0120     mov.w   #0x5A80,&WDTCTL
    OnLed();
00E62A    D0F2 0080 001D     bis.b   #0x80,&P4OUT
}


Так о каких функциях в главном цикле говорит топикстартер?
Да он сам не знает - 4 такта и все. Ни реальных требований не прозвучало, ни реальных потерь.
smalcom
Цитата
Это потому что функции пустые, в них не изменяются регистры.

так напишите реальный пример. а то сначала угадать ваши мысли надо, потом опять не так, потом то не так.

Цитата
Так о каких функциях в главном цикле говорит топикстартер?

перед нажатием кнопки "Ответить" пробуйте читать, что написал ТС.

Цитата
Да он сам не знает - 4 такта и все.

вызов и возврат - 4 такта.

приведённые вами куски дизасма - бред. ТС сразу написал, в чём проблема. Мне парили про преамбулу, а сами выложили "рванину".
уже вроде прошёл НГ.
-----------------------------------
ps. пролог и эпилог функции добавляется по решению компилятора, также компилятор решает какой размер этих кусков. ну и ещё NAKED есть.
Dog Pawlowa
Цитата(smalcom @ Jan 4 2016, 13:36) *
куски дизасма - бред... выложили "рванину"... уже вроде прошёл НГ...

Тю...
Jenya7
вобщем инлайнить функции и будет всем счастье. sm.gif с новым годом! sm.gif
smalcom
говоришь, показываешь - бестолку sm.gif да-да, с НГ ))
-------------
инлайнами тоже надо уметь пользоваться, farjump - он такой
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.