Skocz do zawartości

Szybkość wykonywania porównań na STM32L4


Pomocna odpowiedź

Napisano

Zainspirowany tym filmem chciałem sprawdzić jak to działa na STM32L4:

 

Napisałem 4 funkcje:

int smaller_v1(int a, int b){
	if(a<b)
		return a;
	if(b<a)
		return b;
}

int smaller_v2(int a, int b){
	if(a<b)
		return a;
	return b;
}

int smaller_v3(int a, int b){
	return (a<b)?a:b;
}

int smaller_v4(int a, int b){
	return a * (a<b) + b*(a>=b);
}

Przetestowałem każdą wykonując na danych z tablic 1000 losowych zmiennych 1000 razy:

  startTime = HAL_GetTick();
  for(int j = 0; j < laps; ++j) {
	  for(int i = 0; i < dsize; ++i){
		  smaller_v4(data_a[i], data_b[i]);
	  }
  }
  deltaTime = HAL_GetTick() - startTime;

Program wykonywałem z wyborem optymalizacji kompilacji ale nic to nie zmieniło.

  • _v1 - 3064 ms,
  • _v2 - 2854 ms,
  • _v3 - 2635 ms,
  • _v4 - 3764 ms.

Jestem w stanie zrozumieć dlaczego _v4 jednak działa wolno - pewnie znaczenie ma tu sprzęt, ale nie rozumiem dlaczego _v3 jest szybsze?

Też sprawdziłem _v3 dla różnych typów danych:

  • int/uint32_t/uint_fast8_t - 2635 ms,
  • char/uint8_t - 3075 ms,
  • float - 3635 ms.

size.PNG.e60dc5221a3f8334baa3653332ace62a.PNG

Rozumiem dlaczego pierwsze 3 mają ten sam czas, ale ciekawi mnie dlaczego 1 bajtowe zmienne są gorsze, czy wynika to z potrzeby dopisania 3 bajtów żeby dało się wykonać na nich operacje? Pewnie dlatego zmienne fast są fast, bo mają 4 B.

  • Lubię! 1

@Elvis Na początek  -O0 później -O3. Czasy które spisały są z -O3.

Sprawdzałem też jednen temat: -O3 podobno wyrzuca takie kwiatki jak puste pętle. Wrzuciłem w kod pustą pętlę i w debuggerze dalej była, zmiana liczby iteracji zmieniała czas wykonania i można było prześledzić ją w poleceniach asm. Może to zostało przez odpalanie w debuggerze?

@Gieneq Możesz udostępnić pliki .elf? Fajnie byłoby zobaczyć co ten kompilator faktycznie wygenerował. Debugger nie najlepiej sobie radzi przy -O3, kodu w C nie potrafi zmieniać i czasem pokazuje co innego niż faktycznie działa.

A nie możesz zerknąć na wygenerowany kod asemblera? Co ciekawsze: v2 i v4 z -O3 generują praktycznie ten sam kod (pozostałych nie sprawdziłem bo mi się nie chciało).

A tak poza tym:

int smaller_v1(int a, int b){
	if(a<b)
		return a;
	if(b<a)
		return b;
}

Nie miałeś tu warninga przypadkiem?

Zrobiłem drobny błąd przy wpisywaniu optymalizacji... już działa.

1 godzinę temu, ethanak napisał:

Nie miałeś tu warninga przypadkiem?

@ethanak Warning jest dopiero od O1, przez to że nie wybrałem optymalizacji to tkwiłem w O0.

Poprawiłem kod do testów bo mi już na O1 wszystko wycinało. Teraz wynik jest do czegoś używany i nie wylatuje:

/* USER CODE BEGIN PV */

#define LAPS 200
#define DSIZE 1000

int data_a[DSIZE];
int data_b[DSIZE];
int data_c[DSIZE];

uint32_t tempvalue = 0;
uint32_t startTime;
uint32_t deltaTime;

/* USER CODE END PV */



//....

for(int i = 0; i < DSIZE; ++i){
	  HAL_RNG_GenerateRandomNumber(&hrng, &tempvalue);
	  data_a[i] = (int)(tempvalue % 50);
	  HAL_RNG_GenerateRandomNumber(&hrng, &tempvalue);
	  data_b[i] = (int)(tempvalue % 50);
  }


  startTime = HAL_GetTick();
  for(int j = 0; j < LAPS; ++j) {
	  for(int i = 0; i < DSIZE; ++i){
		  data_c[i] = smaller_v1(data_a[i], data_b[i]);
	  }
  }
  deltaTime = HAL_GetTick() - startTime;

  while (1)
  {
	  HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
	  HAL_Delay(deltaTime);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

Tu spisałem czas wykonania i zajętość pamięci:

image.thumb.png.5ea3c47df60be866d940fea2db4b1cbd.png

Pomiędzy v1 i v2 jest przy każdym stopniu różnica, czyli optymalizacja nie wyrzuci elsa - stąd pewnie ostrzeżenie.

1 godzinę temu, Elvis napisał:

Możesz udostępnić pliki .elf?

@Elvis w załączniku, każdy katalog do osobnego poziomu i w środku 4 pliki do każdej z funkcji.

smaller.zip

(edytowany)

@Gieneq  Chyba musisz zacząć o poprawienia swojego programu testowego.

W pętli wywołujesz smaller_v4(), ale wyników nigdzie nie używasz, nawet do zapisania w zmiennej volatile.

Więc optymalizator wycina całe odwołanie do smaller_v4.

Edit: chociaż w sumie nie jestem tego na 100% pewien, analiza kodu po opytmalizacji wymaga jednak trochę więcej czasu 😉

Edytowano przez Elvis
  • Pomogłeś! 1

@Gieneq Wrzuciłem funkcje smaller* do CompilerExplorer - link do mojego testu - i w wynikowym asemblerze możemy zobaczyć że już przy O1 kod funkcji smaller_v1, smaller_v2 i smaller_v3 generują ten sam kod maszynowy, z kolei smaller_v4 generuje kod maszynowy który ma dwie instrukcje więcej niż pozostała trójka. 

Do testu wziąłem output z STM32CubeIDE:

arm-none-eabi-gcc "../Core/Src/main.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DDEBUG -DUSE_HAL_DRIVER -DSTM32L476xx -c -I../Core/Inc -I../Drivers/STM32L4xx_HAL_Driver/Inc -I../Drivers/STM32L4xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32L4xx/Include -I../Drivers/CMSIS/Include -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"Core/Src/main.d" -MT"Core/Src/main.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Core/Src/main.o"

i do CE wrzuciłem te ważniejsze flagi:

-O1 -mcpu=cortex-m4 -std=gnu11 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb 

Wrzuciłem też kod do benchmarka (link do mojego testu), co prawda benchmark dla C++ i wykonuje się na innej architekturze ale... generalnie wyszło bardzo podobnie:

1211025849_Zrzutekranu2021-05-06223226.thumb.png.a51979e2021bcb946642ced9c46af6ea.png

Natomiast gdy odpalimy test dla innego przykładu benchmarka (testowy dla tego benchmarka):

1836628766_Zrzutekranu2021-05-06223621.thumb.png.30eb9b5c50162046f1c809e99314761c.png

To tutaj już nie ma dyskusji nt. tego która opcja jest szybsza.

Podsumowując asemblerowo (dla Cortex-M4) wszystkie opcje wyglądają bardzo podobnie, gdzie jedynie smaller_v4 generuje więcej instrukcji. Z kolei benchmark potwierdza (przynajmniej dla smaller_v2 i smaller_v3 na x86), że obie te funkcje generują taki sam kod maszynowy. 

Tyle z mojej strony, natomiast bardzo chętnie przeczytałbym jakąś bardziej dokładną analizę 😛 

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...