|
|
 |
Ответов
(60 - 74)
|
Jun 28 2010, 21:09
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Прежде, чем писать новое, изучил в отладчике работу обеих моих программ - начальной si16toad и измененной itoa, в которой операции % и / были заменены вызовом библиотечной функции div. Напомню: Keil uVision - RealView MDK-ARM 4.10, STM32F103. Результаты оказались интересными.
После компиляции в окне Build Ouitput для обеих программ выдаются одинаковые размеры для кода - 548 байтов при оптимизации O0 и 536 байтов при оптимизации O3. Почему они одинаковые, не понимаю (см. ниже)?! Размеры данных всех типов тоже одинаковые вообще всегда, но это, как раз, не удивляет.
Посчитал размер обеих функций по листингу C компилятора (есть галочка в настройках генерировать листинг). При O0 для si16toad насчитал 84 байта, для itoa 98 байтов (не считая 14 байтов в самой функции div, это уже в отладчике увидел). При O3 - 80 байтов и 94 байта, соответственно. Причем, при оптимизации O0 в si16toad команда деления использовалась дважды, а при O3 только один раз. В-общем, мой первый вариант оказался компактнее.
Посчитал в отладчике количество тактов. Счетчик тактов виден в окне регистров, засекал значение перед вызовом своей функции и после нее. При O0 si16toad выполнялась за 171 такт, itoa за 232 такта. При O3 - 121 такт и 210 тактов, соответственно. Мой первый вариант оказался еще и быстрее.
Увидел лишние знаковые и беззнаковые расширения для переменных меньше 32 байтов. Вот здесь буду совершенствовать программу. Массив или указатель - тоже проверю. Заносить пробелы сразу - их, к сожалению, максимум 5 (не 4). Над этим и др. пока думаю.
|
|
|
|
|
Jun 28 2010, 21:57
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 29 2010, 00:33)  Их у Вас четыре. Можете попробовать на пальцах посчитать от X0 (раз-два) до X32768(раз-два-..шесть). Ну и размер должен быть на на уровне 60 байт, ну и тактов заметно менее. Перед "0" я символ + или - не ставлю (считаю, так "красивее" и "правильнее"), потому и обработка такая в начале программ. Итого _ _ _ _ _ 0 \0. По поводу размеров и тактов - могу выдать весь проект в заархивированном виде. В настройках есть какие-то "галочки", которых не трогал. Может, что-то и упустил...
|
|
|
|
|
Jun 28 2010, 22:03
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 00:57)  Перед "0" я символ + или - не ставлю Вы ставите один из 3x символов. Вот и ставьте. Таки 4  QUOTE По поводу размеров и тактов - могу выдать весь проект в заархивированном виде. Я говорю об аккуратно написанном, посему про 80 байтов в Вашем варианте верю. Сделайте 60  .
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 13:48
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Код void itoad(int number, uint8_t *string) { uint8_t sign; *(int32_t *) string = ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24; *(int32_t *)(string + 4) = ' ' | ' ' << 8 | ' ' << 16 | ' ' << 24; *(int32_t *)(string += 8) = ' ' | ' ' << 8 | '0' << 16 | '\0'<< 24; if (!number) return; if (number > 0) sign = '+'; else { number = -number; sign = '-'; } string += 2; do { *string-- = number % 10 + '0'; } while (number /= 10); *string = sign; } Работает с 32-битовыми числами со знаком. string должна быть 12 байтов для 32-битового числа. 60 байтов (+ 4 байта хранят константу "_ _ 0"). ~207 тактов.
|
|
|
|
|
Jun 29 2010, 14:18
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ViKo @ Jun 29 2010, 16:48)  Код *(int32_t *) string = Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 29 2010, 14:34
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (Сергей Борщ @ Jun 29 2010, 17:18)  Знатная грабля. Исключение при первой же string, начало которой не попадает на границу 4 байт. Или просто порушенные соседние данные. Это гнулось под Cortex - такая вот игра. QUOTE (ViKo @ Jun 29 2010, 16:48)  60 байтов Чуть симпатичнее и скорее всего еще короче: CODE void itoad(int number, uint8_t *string) { uint8_t sign; *(uint32_t *) string = ' '; *(uint32_t *)(string + 4) = ' '; *(uint32_t *)(string += 10) = (uint32_t )" 0"; if (!number) return; if (number > 0) sign = '+'; else { number = -number; sign = '-'; } // string += 2; do { *string-- = number % 10 + '0'; } while (number /= 10); *string = sign; } Осталось первоначальную 16bit оптимизировать.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 14:45
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 17:39)  Кавычки не двойные? В первых двух - нет. Возможны warnings, правда, поскольку символ wide получается ИЗ 4x ПРОБЕЛОВ. А так нормально. В третьей - три символа в двойных. QUOTE Из этой 16-битов автоматически получается, если малое число использовать и буфер соответствующий. Автоматически, не значит оптимально.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 17:23
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 29 2010, 17:34)  Код *(uint32_t *)(string += 10) = (uint32_t )" 0"; Так - нельзя, пропускается два байта. С кавычками - понял, но варнинги... как бы удовлетворить требованиям компилятора? Код #define FOUR_SPACES 0x20202020 *(uint32_t *) string = FOUR_SPACES; Нормально?
|
|
|
|
|
Jun 29 2010, 17:40
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 20:23)  Так - нельзя, пропускается два байта. А, да. Что-то ошибся. Тогда так: CODE *(uint32_t *)(string += sizeof(int32_t)) = ' '; *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )" 0"; string += 2; Есть шанс на экономию пары байт. QUOTE С кавычками - понятно, но варнинги... как бы удовлетворить требованиям компилятора? Ну, например, отключить их локально прагмой, либо таки (long)" ", но константа займет 8 байт. QUOTE (ViKo @ Jun 29 2010, 20:23)  Нормально? Да.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jun 29 2010, 18:29
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(zltigo @ Jun 29 2010, 20:40)  Код *(uint32_t *)(string += sizeof(int32_t)) = ' '; *(uint32_t *)(string += sizeof(int32_t)) = (uint32_t )" 0"; string += 2; Есть шанс на экономию пары байт. В смысле, прилепить string +=2 сразу к предыдущему выражению, использующему указатель? А, заменить +8 +2 на +4 +4 +2? upd. Попробовал и так, и сяк, и +10, лучше не становится. 16-битовую хочу попробовать с применением формата 4.28, как у aaarrr. А с тем, что сделал для 32 битов, и не знаю, куда уж дальше "копать" для 16 битов. Я, собственно, с 16-битовой и возился, пока не увидел, что 32-битовая из нее получается практически "даром":)
|
|
|
|
|
Jun 29 2010, 18:38
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (ViKo @ Jun 29 2010, 21:29)  В смысле, прилепить string +=2 сразу к предыдущему выражению, использующему указатель? Вот как написано, так пробуйте. QUOTE что 32-битовая из нее получается практически "даром":) Полагаю, что там есть как минимум один нюанс - не ухудшить шестнадцатибитовостью ну и чуть поджать за счет меньшего буфера.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|