Jump to content
    

упаковка данных в структуре

 

2 минуты назад, natsu сказал:

Тогда две структуры описывать не нужно, на все сгодится упакованная.

Не совсем. Думаю - размер у них будет разным.

2 минуты назад, natsu сказал:

И остается изначальный вопрос, а надо ли после чтения блока данных извлекать структуру и копировать ее в гарантированно выравненную область памяти (та самая структура для структур из предыдущего абзаца)?

Надо для кого/чего? Сначала на этот вопрос ответьте.

Share this post


Link to post
Share on other sites

10 минут назад, natsu сказал:

Тогда получается что (обычная) структура из упакованных структур будет всегда содержать выровненные данные?

Увы нет. Упакованные (в т.ч. разные) структуры ложатся по невыравненным адресам.

9 минут назад, jcxz сказал:
Цитата

И остается изначальный вопрос, а надо ли после чтения блока данных извлекать структуру и копировать ее в гарантированно выравненную область памяти (та самая структура для структур из предыдущего абзаца)?

Надо для кого/чего? Сначала на этот вопрос ответьте.

Для данного конкретного случая. После чтения блока данных внутри него окажется требуемая структура с произвольного адреса. А данные надо обработать и передать по другому интерфейсу.

 

Меня интересуют критерии, на основании которых можно будет принять решения. Я не прошу принять решения за меня. Я прошу помочь мне научиться самому принимать обоснованные решения.

Share this post


Link to post
Share on other sites

34 minutes ago, jcxz said:

На Cortex-M невыровненность доступа добавит наверное 1 такт к длительности команды чтения. И всё. Вместо 2 тактов станет 3.

это совершенно не вяжется с тем, что я наблюдаю на IMXRT1062, конкретно на teensy 4.1. Возьмите пример

#pragma GCC push_options
#pragma GCC optimize ("Ofast")

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <Arduino.h>


unsigned char  DMAMEM DmaMem[480*1024];
unsigned char  EXTMEM ExtMem[16*1024*1024];
unsigned char         GenMem[460*1024];

// each class is only 8 bytes
class cTestData1
{ public: unsigned char A1, A2, A3, A4, A5, A6, A7, A8;
};


class cTestData2
{ public: unsigned short A1, A2, A3, A4;
};


class cTestData3
{ public: unsigned int A1:24, A2:20, A3:13, A4:7;
};


class cTestData4
{ public: unsigned int A1, A2;
};


void TestDataS(unsigned char *p1, unsigned char *p2) // copy data from one test memory block to other and measure the total amount of CPU tacts for 64K transfer
{ unsigned long begin, end;
  unsigned int *pI1, *pI2;
#if 0 // если поставить здесь 1, то падает при копировании этих структур 
  cTestData1 *pT1;
  cTestData2 *pT2;
  cTestData3 *pT3;
  cTestData4 *pT4;
  cTestData4 *pT41;
  pT1=(cTestData1*)p1;
  pT2=(cTestData2*)p2;
  begin=ARM_DWT_CYCCNT;
  for(int i=0; i<8192; i++)
  { pT2[i].A1=pT1[i].A1;
    pT2[i].A2=pT1[i].A2;
    pT2[i].A3=pT1[i].A3;
    pT2[i].A4=pT1[i].A4+pT1[i].A5+pT1[i].A6+pT1[i].A7+pT1[i].A8;
  }
  end=ARM_DWT_CYCCNT;
  Serial.print(end-begin); Serial.print(" ");

  pT2=(cTestData2*)p2;
  pT3=(cTestData3*)p1;
  begin=ARM_DWT_CYCCNT;
  for(int i=0; i<8192; i++)
  { pT3[i].A1=pT2[i].A1;
    pT3[i].A2=pT2[i].A2;
    pT3[i].A3=pT2[i].A3;
    pT3[i].A4=pT2[i].A4;
  }
  end=ARM_DWT_CYCCNT;
  Serial.print(end-begin); Serial.print(" ");

  pT3=(cTestData3*)p1;
  pT4=(cTestData4*)p2;
  begin=ARM_DWT_CYCCNT;
  for(int i=0; i<8192; i++)
  { pT4[i].A1=pT3[i].A1;
    pT4[i].A2=pT3[i].A2+pT3[i].A3+pT3[i].A4;
  }
  end=ARM_DWT_CYCCNT;
  Serial.print(end-begin); Serial.print(" ");

  pT4=(cTestData4*)p2;
  pT1=(cTestData1*)p1;
  begin=ARM_DWT_CYCCNT;
  for(int i=0; i<8192; i++)
  { pT1[i].A1=pT4[i].A1;
    pT1[i].A2=pT4[i].A1;
    pT1[i].A3=pT4[i].A1;
    pT1[i].A4=pT4[i].A1;

    pT1[i].A5=pT4[i].A2;
    pT1[i].A6=pT4[i].A2;
    pT1[i].A7=pT4[i].A2;
    pT1[i].A8=pT4[i].A2;
  }
  end=ARM_DWT_CYCCNT;
  Serial.print(end-begin); Serial.print(" ");

  pT4=(cTestData4*)p1;
  pT41=(cTestData4*)p2;
  begin=ARM_DWT_CYCCNT;
  for(int i=0; i<8192; i++)
  { pT41[i].A1=pT4[i].A1;
    pT41[i].A2=pT4[i].A2;
  }
  end=ARM_DWT_CYCCNT;

  Serial.print(end-begin); Serial.print(" ");
#endif

  pI1=(unsigned int*)p2;
  pI2=(unsigned int*)p1;
  begin=ARM_DWT_CYCCNT;
  for(int i=0; i<32768; i++)
    pI2[i]=pI1[i];
  end=ARM_DWT_CYCCNT;

  Serial.print(((end-begin)/16384+1)/2); Serial.print(" "); Serial.print(end-begin); Serial.print(" ");

  pI1=(unsigned int*)p2;
  begin=ARM_DWT_CYCCNT;
  for(int i=0; i<32768; i++)
    pI1[i]=i;
  end=ARM_DWT_CYCCNT;

  Serial.print(((end-begin)/16384+1)/2); Serial.print(" "); Serial.println(end-begin);
}


int ShiftList1[] = {0, 4, 8, 12, 16, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3};
int ShiftList2[] = {0, 4, 8, 12, 16, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3};


void TestData(unsigned char *p)
{ Serial.printf("Testing memory of %p\n", p);
  for(int i=0; i<5; i++)
//for(int i=0; i<sizeof(ShiftList1)/sizeof(ShiftList1[0]); i++)
  { Serial.printf("%p(%d) to %p(%d) started\n", p+ShiftList1[i], ShiftList1[i], p+65536+ShiftList1[i], 65536+ShiftList1[i]);
    TestDataS(p+ShiftList1[i], p+(256*1024)+ShiftList1[i]);
  }
}


void setup()
{ while(!Serial);
  if (CrashReport)
  { Serial.print(CrashReport);
    delay(10000);
  }
}


void loop()
{ 
  Serial.println("GenMem"); TestData(GenMem);
  Serial.println("DmaMem"); TestData(DmaMem);
  Serial.println("ExtMem"); TestData(ExtMem);
  Serial.println("GenDma"); TestDataS(GenMem, DmaMem);
  Serial.println("DmaExt"); TestDataS(DmaMem, ExtMem);
  Serial.println("GenExt"); TestDataS(GenMem, ExtMem);
  Serial.println("DmaGen"); TestDataS(DmaMem, GenMem);
  Serial.println("ExtDma"); TestDataS(ExtMem, DmaMem);
  Serial.println("ExtGen"); TestDataS(ExtMem, GenMem);
  delay(1000);
}

#pragma GCC pop_options

что я как-то на форуме teensy 4.1эту проблему рассматривал, в этом примере измеряется скорость доступа к разной памяти с точным "allign" и нет и скорость падает в разы, а не с 2 на 3 такта, а если включить блок копирования структур, то все падает сразу. В esp32 все точно также с той лишь разницей, что доступ к памяти там существенно медленнее.

Share this post


Link to post
Share on other sites

42 минуты назад, jcxz сказал:

Какие-то чудеса рассказываете. На Cortex-M невыровненность доступа добавит наверное 1 такт к длительности команды чтения...

Ну как сказать... Cortex-M разные бывают, и unaligned access в M0 - это Fault, а в других ядрах - задается специальным битом в регистрах настройки ядра CPU (по умолчанию - поддержка невыровненного доступа). А на "настоящих" ARM-ах любой unaligned access - это Data Abort.

Share this post


Link to post
Share on other sites

50 минут назад, Arlleex сказал:

Ну как сказать... Cortex-M разные бывают, и unaligned access в M0 - это Fault, а в других ядрах - задается специальным битом в регистрах настройки ядра CPU (по умолчанию - поддержка невыровненного доступа).

Ну естественно я имел в виду Cortex-M >= Cortex-M3. В тех МК, о которых шла речь, нету M0.

53 минуты назад, iiv сказал:

это совершенно не вяжется с тем, что я наблюдаю на IMXRT1062, конкретно на teensy 4.1

Ну так значит - читаем п.2:  :biggrin:

1 час назад, jcxz сказал:

PS: Может у вас там (на ESP32) тупо разрешена генерация fault-ов при невыровненном доступе? :biggrin: И вызовы их обработчика и замедляют работу программы.

55 минут назад, iiv сказал:

и скорость падает в разы, а не с 2 на 3 такта, а если включить блок копирования структур, то все падает сразу. В esp32 все точно также с той лишь разницей, что доступ к памяти там существенно медленнее.

У Вас эмулятор есть? Если есть, то с ним причина выясняется за несколько минут.  :unknw:

Share this post


Link to post
Share on other sites

6 minutes ago, jcxz said:

У Вас эмулятор есть? Если есть, то с ним причина выясняется за несколько минут.  :unknw:

у меня не эмулятор, а натурные эксперименты, которые показывают падение скорости на teensy 4.1 c IMXRT1062 почти в 10 раз при копировании по структуре, а при доступе через 4-байтовые вызывают фаулт. Я не понимаю, что вы припераетесь?

Share this post


Link to post
Share on other sites

1 час назад, natsu сказал:

Для данного конкретного случая. После чтения блока данных внутри него окажется требуемая структура с произвольного адреса. А данные надо обработать и передать по другому интерфейсу.

Меня интересуют критерии, на основании которых можно будет принять решения. Я не прошу принять решения за меня. Я прошу помочь мне научиться самому принимать обоснованные решения.

Критерии вы сами определяете. Исходя из того, как используете данные. Здесь ясновидцев нету.

Если Вы полученную структуру потом 1000 раз читаете/пишете, то наверное есть выигрыш в скорости от того, чтобы скопировать её в отдельное место и работать с ней уже выровненной. А если вы её всего несколько раз читаете/пишете - ну добавляет вам невыровненный доступ десяток лишних тактов - и что? А копирование - занимает несколько десятков тактов как минимум. Так есть выигрыш или проигрыш от копирования? Мы же не знаем сколько раз вы её читаете/пишете.

 

PS: Да и вообще - в вашем МК есть все средства чтобы измерить время. И самому посмотреть разницу между работой с выровненной и невыровненной структурой. Достаточно нескольких минут чтобы сравнить.  :unknw:

 

16 минут назад, iiv сказал:

у меня не эмулятор, а натурные эксперименты, которые показывают падение скорости на teensy 4.1 c IMXRT1062 почти в 10 раз при копировании по структуре, а при доступе через 4-байтовые вызывают фаулт. Я не понимаю, что вы припераетесь?

Вы поняли что я писал? Судя по всему - нет. Советую ещё раз внимательно перечитать мой пост и внимательно подумать.

Share this post


Link to post
Share on other sites

возвращаясь к вопросу выравнивания...

 

Сделал я упакованные структуры, поместил их в обычную структуру с атрибутом aligned каждую и все вроде бы хорошо, компилятор все структуры выровнял, теперь можно копировать и работать  с выровненными данными. Все данные внутри от большего размера к меньшему - т.е. если выровнен первый элемент, то остальные и подавно. Но несмотря на то, что я явно запросил align, компилятор выводит предупреждения (иногда сразу, иногда только во время компиляции) и их много. Что не так или как подавить эти предупреждения?

 

\fdata.c(326): warning: padding struct 'struct my' with 4 bytes to align 'ennow' [-Wpadded]
                __attribute__((aligned (8))) double ennow[2][3];

                                                    ^

 

Share this post


Link to post
Share on other sites

6 minutes ago, natsu said:

                __attribute__((aligned (8))) double ennow[2][3];

я бы double тоже по 8 байт выравнивал бы, ну а если структура с оными, то и структуру тоже. Я за все контроллеры не овечаю, но это очень распространенная проблема потери скорости и на обычных процессорах, и на контроллерах. Основная причина - попадание одного double в две строки кеша.

Share this post


Link to post
Share on other sites

3 минуты назад, iiv сказал:

я бы double тоже по 8 байт выравнивал бы

так aligned (8) разве не оно?

Share this post


Link to post
Share on other sites

28 minutes ago, natsu said:

так aligned (8) разве не оно?

Оно-то и оно. Так надо и саму структуру тоже также выравнивать. ИМХО, компиллер именно из-за этого и ругается.

Share this post


Link to post
Share on other sites

6 минут назад, iiv сказал:

так надо и саму структуру тоже также выравнивать

У меня собирательная структура состоит из нескольких структур и одного массива double как описано выше, у всех элементов структуры атрибут aligned(8). Что еще надо выровнять? Обнаружил, что если я вставляю между элементами в одном месте char pad[4]; в другом char pad2[6]; то предупреждения исчезают. Вот только зачем они там?

 

    struct my {
        __attribute__((aligned (8))) zagprof_t zag;
        char pad1[6];
        __attribute__((aligned (8))) datprof_t dat;
        char pad2[4];
        __attribute__((aligned (8))) double ennow[2][3];
        };

 

Share this post


Link to post
Share on other sites

А я бы по-другому написал бы, и все выровнялось бы само собой:

struct my
{ double ennow[2][3];
  datprof_t dat; // она у вас 4 байта?
  zagprof_t zag; // а эта 2 байта?
  char pad1[2]; // а это окончательное выравнивание всей структуры
};

 

Share this post


Link to post
Share on other sites

9 часов назад, natsu сказал:

Вот только зачем они там?

zagprof_t и datprof_t покажите.

Share this post


Link to post
Share on other sites

typedef struct {double energy[2][3];uint16_t mask;} __attribute__((packed)) zagprof_t;
typedef struct {uint32_t stamp;float data[16];} __attribute__((packed)) datprof_t;
 

10 часов назад, iiv сказал:

А я бы по-другому написал бы, и все выровнялось бы само собой:

а вот так не получается. Правда одна из ошибок исчезает, если в конце структуры добавить char pad[8]; но как то не выглядит это разумным.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...