|
Оптимизация кода. |
|
|
|
Dec 31 2015, 09:19
|
Гуру
     
Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025

|
Цитата(Jenya7 @ Dec 31 2015, 09:50)  У меня мэйн функция выходит довольно большая. Многие куски кода можно было вынести в отдельные функции. Но мне важна скорость а переход в функцию и обратно это 4 такта если я не ошибаюсь. помножить на количество функций... или это уже паранойя? и еще я заметил если функцию вынести в отдельный модуль код увеличивается примерно на 100 байт. Это паранойя. Имеет право присутствовать (в разумных пределах) при написании специальных функций, например в прерывании или в ограниченном по объему пространстве (бутлоадер, например). Но никак не при простой писанине в main(). Если такты так критичны- значит что-то не так с выбором элементной базы (нет запаса по скорости/размеру памяти). ну и инлайны никто не отменял. Про размер: функция должна выполнять одну функцию, потому она и названа функцией  Не пихайте все вместе, никакого выигрыша это не принесет, одна головная боль. P.S. Жена с кухни выгнала, делать нечего- вот и пишу любые ответы на любые вопросы. С наступающим!
|
|
|
|
|
Dec 31 2015, 09:28
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(Ruslan1 @ Dec 31 2015, 14:19)  Это паранойя. Имеет право присутствовать (в разумных пределах) при написании специальных функций, например в прерывании или в ограниченном по объему пространстве (бутлоадер, например). Но никак не при простой писанине в main(). Если такты так критичны- значит что-то не так с выбором элементной базы (нет запаса по скорости/размеру памяти). ну и инлайны никто не отменял. Про размер: функция должна выполнять одну функцию, потому она и названа функцией  Не пихайте все вместе, никакого выигрыша это не принесет, одна головная боль. P.S. Жена с кухни выгнала, делать нечего- вот и пишу любые ответы на любые вопросы. С наступающим!  спасибо. с наступающим.
|
|
|
|
|
Dec 31 2015, 10:39
|
Гуру
     
Группа: Свой
Сообщений: 2 223
Регистрация: 3-03-06
Из: Tomsk
Пользователь №: 14 925

|
Цитата(Jenya7 @ Dec 31 2015, 13:50)  У меня мэйн функция выходит довольно большая. Многие куски кода можно было вынести в отдельные функции. Но мне важна скорость а переход в функцию и обратно это 4 такта если я не ошибаюсь. помножить на количество функций... или это уже паранойя? и еще я заметил если функцию вынести в отдельный модуль код увеличивается примерно на 100 байт. 4 такта это где? Может и больше быть. Если вам надо сократить код, то в функцию выносим часто повторяющиеся куски кода. Если надо ускорить работу, то не выносим, но тогда естественно объем кода увеличится. Для удобства написания можно писать функции, но с ключевым словом inline - тогда код функции будет линейно включен в программу при компиляции.
|
|
|
|
|
Dec 31 2015, 11:38
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(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 такта это где? Может и больше быть. Если вам надо сократить код, то в функцию выносим часто повторяющиеся куски кода. Если надо ускорить работу, то не выносим, но тогда естественно объем кода увеличится. в том то и был вопрос много ли я выигрываю не вынося код в отдельные функции
Сообщение отредактировал Jenya7 - Dec 31 2015, 11:41
|
|
|
|
|
Dec 31 2015, 12:15
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Jenya7 @ Dec 31 2015, 14:38)  а где лучше прописать инлайновую функцию? Как в месте вызова будет встроена inline функция, если текст ее не виден? Отсюда и исходите. Цитата(Jenya7 @ Dec 31 2015, 14:38)  в том то и был вопрос много ли я выигрываю не вынося код в отдельные функции Важно, что вы теряете - понимание кода, понятную структуру, иерархию в проекте. Сейчас все контроллеры стоят практически одинаково, что AVR, что CM4. Есть ли смысл затруднять себе жизнь? Кстати, если разрешить максимальную оптимизацию, то сам компилятор развернет некоторые функции.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Dec 31 2015, 12:23
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(Dog Pawlowa @ Dec 31 2015, 15:15)  Кстати, если разрешить максимальную оптимизацию, то сам компилятор развернет некоторые функции. живой пример - Keil 5, последний с -O0 размер кода 33кб с -O3 - 22кб с включенной Cross-Module optimization - 13(!!!)кб правда, не смотрел, как там функции разворачиваются
|
|
|
|
|
Jan 1 2016, 03:11
|
Частый гость
 
Группа: Свой
Сообщений: 100
Регистрация: 13-06-06
Из: г.Улан-Удэ
Пользователь №: 18 024

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

Профессионал
    
Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718

|
Цитата(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 и никаких лишних вызовов
|
|
|
|
|
Jan 3 2016, 02:53
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(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; } }
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jan 3 2016, 13:30
|

Профессионал
    
Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718

|
Цитата Не уверен, что это корректный пример, с одной функцией в том же файле. с чего вдруг один? три файла использовано, две компилируемых единицы... Цитата Более интересно такое: это кардинально противоположно тому, что хотел ТС... а-а-а-а... понял, понял. НГ. Поправляйтесь)) Тем не менее Цитата 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>
|
|
|
|
|
Jan 3 2016, 20:24
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(smalcom @ Jan 3 2016, 22:36)  что вам даст т.н. "преамбула"? Мне, и в общем случае - ничего. Может, в конкретном случае это даст что-то топикстартеру (а именно он интересовался потерями быстродействия на вызов функций): Цитата(Jenya7 @ Dec 31 2015, 10:50)  переход в функцию и обратно это 4 такта если я не ошибаюсь Ошибается, еще регистры сохранять надо, а при оптимизации без функций у компилятора больше возможностей.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jan 4 2016, 07:27
|

Профессионал
    
Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718

|
Цитата Может, в конкретном случае это даст что-то топикстартеру (а именно он интересовался потерями быстродействия на вызов функций): я вам отвечу: ничего она не даст. если вы посмотрите на листинг, то увидите, что ничего из сторонних адресов(и др. ресурсов) не используется. вот с преамбулой для авр Код 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>
|
|
|
|
|
Jan 4 2016, 09:28
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(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 такта и все. Ни реальных требований не прозвучало, ни реальных потерь.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jan 4 2016, 10:36
|

Профессионал
    
Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718

|
Цитата Это потому что функции пустые, в них не изменяются регистры. так напишите реальный пример. а то сначала угадать ваши мысли надо, потом опять не так, потом то не так. Цитата Так о каких функциях в главном цикле говорит топикстартер? перед нажатием кнопки "Ответить" пробуйте читать, что написал ТС. Цитата Да он сам не знает - 4 такта и все. вызов и возврат - 4 такта. приведённые вами куски дизасма - бред. ТС сразу написал, в чём проблема. Мне парили про преамбулу, а сами выложили "рванину". уже вроде прошёл НГ. ----------------------------------- ps. пролог и эпилог функции добавляется по решению компилятора, также компилятор решает какой размер этих кусков. ну и ещё NAKED есть.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|