natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба Добрый день, Подскажите, пожалуйста, как работать с невыравненными данными на Си. Во внешней памяти данные хранятся в виде последовательности структур, сами структуры при этом могут иметь не кратное 4 количество байт, например {int32_t x;chat y;}. Я начитался, что работа с такими данными медленная, а может и приводить к ошибкам, поэтому готов делать memcpy в выровненный блок данных и с ним уже работать. Сами структуры при этом объявляются packed. Но возникает проблема - я не знаю как объявить область памяти так, чтобы в ней разместить эти же структуры, но выравненными. Получается, что для каждой выравненной структуры я должен делать отдельное выделение памяти что делает код запутанным и нечитаемым. Как быть? Как вообще правильно работать с такими данными? Отдельный вопрос про double. Компилятор не ругается на выравнивание структуры типа {double x[2][3];int16_t y;}. Непонятно почему и как такую структуру следует выравнивать - по 2, 4 или 8 байтам? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 10 minutes ago, natsu said: Я начитался... (C) "Не читайте советских газет по утрам". Очень сильно нужно постараться, чтобы эта "медленная работа" сказывалась на работе проекта. А если она уже сказывается, то проект можно смело закрывать :) По поводу ошибок, так они если и возникают, то вовсе не от того упакованная структура или нет. 10 minutes ago, natsu said: Как быть? Для начала следует указать о каком "железе" идет речь и по возможности о применяемом софте для программирования. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба keil 5.33 для stm32f7 - но это пока. Потом микроконтроллер будет подобран из соображений достаточности. И не хотелось бы переделок программы. А ничего, если адрес время от времени будет оказываться нечетным? Потому и появился новый проект - изза того что прежний не справляется по скорости. приходится обслуживать несколько протоколов одновременно. Да и не только в скорости дело - хотелось бы не только разумно использовать ресурсы процессора, но и научиться делать так, чтобы не создавать узких мест на ровном месте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 31 минуту назад, natsu сказал: Но возникает проблема - я не знаю как объявить область памяти так, чтобы в ней разместить эти же структуры, но выравненными Это-то как раз просто - создайте union вашей структуры с uintX_t. Но это даст вам только выравнивание первого члена упакованной структуры. На выравнивание остальных членов это никак не повлияет. Если порядок данных в этих структурах не прибит вам гвоздями свыше - перетасуйте их таким образом, чтобы все остальные члены тоже оказывались выровненными при выравнивании начала структуры, Если это сделать невозможно - пользуйтесь упакованными структурами и думайте об алгоритмах своей программы - там поле для экономии ресурсов гораздо шире. 31 минуту назад, natsu сказал: что работа с такими данными медленная, а может и приводить к ошибкам, Медленная - да, а все ошибки 99.999% ваши и находятся в вашем исходнике. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 190 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 1) Определить тип структуры. 2) Определить упакованный тип этой структуры. 3) Объекты, которые в памяти не выровнены - типа 2. 4) Нужный объект копируется в объект типа 1, дальнейшая работа ведется с ним. Можно и напрямую обращаться к невыровненным объектам, но нужно пользоваться соотв. квалификаторами __unaligned. А можно и подумать насчет принудительного выравнивания, если память позволяет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 30 minutes ago, natsu said: Во внешней памяти данные хранятся в виде . . . . так что медленно, внутренняя работа STM32 или работа с этим "внешним". Что пишется, архив, лог, параметры итд ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 7 минут назад, Сергей Борщ сказал: Это-то как раз просто - создайте union вашей структуры с uintX_t. Но структуры встречаются не маленькими. Придется высчитывать сколько интов надо чтоб покрыть размер. А если придется что-то изменить? 7 минут назад, Arlleex сказал: 1) Определить тип структуры. 2) Определить упакованный тип этой структуры. Опять таки - создавать две структуры это шанс для ошибок в будущем. И если как объявить упакованную структуру понятно, то как объявить ее же неупакованной? 8 минут назад, k155la3 сказал: ак что медленно, внутренняя работа STM32 или работа с этим "внешним". Что пишется, архив, лог, параметры итд ? Внешняя память по шине 40МГц, не сказать чтоб медленно - (на прерываниях получается дольше чем с опросом!). Но памяти всегда мало, приходится экономить. Пишутся логи событий и несколько разных профилей с измеренными данными, с разной периодичностью и сроком хранения. Для отдачи данных приходится их перечитывать и обрабатывать. На самом деле я спрашивал как работать с такими данными. Т.е. насколько это безопасно и насколько необходимо все таки их выравнивать для обработки. Можно подробнее про __unaligned? Или где почитать, а то толи я неправильно ищу толи не очень понимаю что искать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 190 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 1 минуту назад, natsu сказал: Можно подробнее про __unaligned? Или где почитать, а то толи я неправильно ищу толи не очень понимаю что искать. В описании на ARM Compiler 6. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 7 минут назад, natsu сказал: Но структуры встречаются не маленькими. Придется высчитывать сколько интов надо чтоб покрыть размер. Выравнивается начало структуры. Для этого достаточно union с одним-единственным uintX_t. Все остальные члены структуры автоматически подразумеваются выровненными. Для неупакованных структур это выполняется автоматически - компилятор сам добавляет в структуру пропуски для выравнивания каждого члена исходя из его размера. Для упакованных структур это надо делать вручную, сортируя члены при объявлении структуры. memcpy никак не сможет сделать это за вас. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 31 минуту назад, Сергей Борщ сказал: Это-то как раз просто - создайте union вашей структуры с uintX_t. Самые критичные места у меня в момент записи, там как раз я записываю подготовленные и естественно выравненные данные в поток, внутри структуры все данные расположены по убыванию размера. Но однажды определив __packed структуру компилятор будет ВСЕГДА считать ее невыравненной - в документации на компилятор сказано, что отказаться от невыравненности нельзя. И получится, что вся затея с выравниванием не имеет смысла. (Хотя в описании на __unaligned сказано, что он необходим для упакованных структур, что противоречит описанию __packed) Получается проще делать структуры выравненными. Но тогда истинный (упакованный) размер придется считать руками для каждой структуры. И так и непонятно, нужно ли выравнивание вообще, насколько код медленнее и объемнее с неупакованными данными? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 1 hour ago, natsu said: Во внешней памяти данные хранятся в виде . . . . по поводу упоминания memcpy() Можно вообще "забыть" о выравнивании, если работать не напрямую со структурой, а использовать массив структур, состоящих из указателя на начало поля и его размера. Это улучшает переносимость кода. Если научить драйвер внешней памяти работать напрямую с таким массивом, то можно обойтись без дополнительного расхода RAM. Оноже - сериализация. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 18 минут назад, natsu сказал: Самые критичные места у меня в момент записи, там как раз я записываю подготовленные и естественно выравненные данные в поток, внутри структуры все данные расположены по убыванию размера. Тогда без разницы - упакованной её считает компилятор или неупакованной. Это никак не скажется на скорости доступа к её членам: скорость будет максимальной. Вы смешиваете понятия упакованности и выравнивания. Это 2 разных понятия. Скорость может падать на обращении к невыровненным данным. А в данном случае все данные получаются выравненными. Если конечно базовый адрес самой структуры выравнен на размер её максимального члена. Цитата Но однажды определив __packed структуру компилятор будет ВСЕГДА считать ее невыравненной - в документации на компилятор сказано, что отказаться от невыравненности нельзя. И получится, что вся затея с выравниванием не имеет смысла. Имеет. См. выше. 42 минуты назад, natsu сказал: Опять таки - создавать две структуры это шанс для ошибок в будущем. И если как объявить упакованную структуру понятно, то как объявить ее же неупакованной? Например - с помощью макросов: #define TMPL_ZData { \ u32 data0; \ u8 data1; \ u32 data2; \ u8 data3; \ } struct ZData TMPL_ZData zData; __packed struct ZDataP TMPL_ZData zDataP; Это для IAR, но и для других компиляторов, не поддерживающих __packed, можно сделать аналогично. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 29 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 1 hour ago, Forger said: Очень сильно нужно постараться, чтобы эта "медленная работа" сказывалась на работе проекта. А если она уже сказывается, то проект можно смело закрывать :) у людей разные задачи бывают. У меня почти всегда - это затык и все по несколько раз приходится перетрясывать в памяти, но у меня обычно - это линейная алгебра, то есть приходит сильно упакованное данное по DMA SPI, и если его далее так и использовать, то все садится по производительности из-за кривого доступа по памяти или кеша. 1 hour ago, Forger said: По поводу ошибок, так они если и возникают, то вовсе не от того упакованная структура или нет. совсем не соглашусь. На двух современных контроллерах, которые я использую (esp32,IMXRT106x) , попытка прочитать 4 байтовое целое или число с плавающей точкой по невыровненному адресу из внутренней памяти (во внешней и подавно так) приводит к полному останову контроллера. 2ТС: правильно заметили, что саму структуру надо в памяти выравнять, но и не забыть выравнять все внутри, чтобы 4-байтовые с адреса кратного 4, 2-байтовые с адреса кратного 2 лежали, ну и про 8 байтовые не забыть. Если есть битовые поля, их засунуть так, чтобы было минимальное число случаев, когда одно поле находится в нескольких байтах, и чтобы никогда не было, чтобы поле было в двух 4-байтовых словах. Все остальное - обычно не помогает, так как сама струрктура кешируется и все более-менее быстро доступно. В некоторых процессорах длина кэшевой строки может быть больше 4 байт, и тогда все надо выравнивать под эту длину, если хочется выжать максимум производительности, но не забывать, что кеш - это всегда очень мало, около 16Кбайт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 6 минут назад, iiv сказал: совсем не соглашусь. На двух современных контроллерах, которые я использую (esp32,IMXRT106x) , попытка прочитать 4 байтовое целое или число с плавающей точкой по невыровненному адресу из внутренней памяти (во внешней и подавно так) приводит к полному останову контроллера. Какие-то чудеса рассказываете. На Cortex-M невыровненность доступа добавит наверное 1 такт к длительности команды чтения. И всё. Вместо 2 тактов станет 3. А с учётом того, что как правило - не бывает кода состоящего из одних только операций обращения к памяти, а они перемешаны с другими командами, то суммарный % замедления должен быть совсем невелик. PS: Может у вас там (на ESP32) тупо разрешена генерация fault-ов при невыровненном доступе? И вызовы их обработчика и замедляют работу программы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба Да, действительно, я думал что компилятор упакованную структуру считает не выравненной. Если это не так, то все заметно упрощается. Тогда получается что (обычная) структура из упакованных структур будет всегда содержать выровненные данные? По первому члену структуры. Тогда две структуры описывать не нужно, на все сгодится упакованная. И остается изначальный вопрос, а надо ли после чтения блока данных извлекать структуру и копировать ее в гарантированно выравненную область памяти (та самая структура для структур из предыдущего абзаца)? Или можно пользоваться __unaligned? По какому критерию выбрать один из этих двух методов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться