PR

Raspberry Pi Picoのマルチコアで処理速度を比較してみる

記事内に広告が含まれています。

 Raspberry Pi Pico(ラズパイPico)のデュアルコア(multicore)を使って並列処理・逐次処理の計算速度を比較してみました。

 ラズパイPicoはArduinoIDEから使う前提です。ArduinoIDEからならマルチコアも割と簡単に使えます。

▼ラズパイPicoでデュアルコアを使う方法▼

 ライプニッツの公式からの円周率計算をシングル/デュアルでそれぞれ計算して、処理速度を比較してみたいと思います。

\begin{align} \sum_{i=0}^\infty \left(-1\right)^{n-1}\frac{1}{2n-1}=\frac{1}{1}-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\frac{1}{9}-\cdots = \frac{\pi}{4}\\\\ \end{align}

▲奇数の逆数をとって、和と差を繰り返していくと円周率の1/4に近づいていく公式です。この円周率計算の処理速度を比較してみます。

 まずはシングルコア/逐次処理で普通にプログラムして処理速度を計測。(2023/05⊿1:シリアル通信が開始されるまでプログラム待機されるようにソース修正。シリアル通信が開始されるまでオンボードLEDを点滅しながら待機、通信開始後にプログラムが起動するよう変更)

// 2021/06/01 imo lab.
// 2023/05/03 起動待機処理追加
// https://garchiving.com/

uint32_t core0_Timer, core0_dt;
double s;

void setup() {
  Serial.begin(115200);
  pinMode(25, OUTPUT);
  while (!Serial) {
    digitalWrite(25, digitalRead(25) == LOW ? 1 : 0);
    delay(200);
  }
  delay(1000);
  Serial.printf("core0:start....\n\n");
}

void loop() {
  core0_Timer = micros();

  s = 0;
  for (uint32_t n = 1; n <= 1000000; n++) {
    if (n % 2 == 1) s += 1.0 / (2 * n - 1.0);
    if (n % 2 == 0) s -= 1.0 / (2 * n - 1.0);
  }
  s *= 4.0;

  core0_dt = micros() - core0_Timer;

  Serial.printf("%+5s%.5f\n", "ans:", s);
  Serial.printf("time:%7d ms\n\n", core0_dt / 1000);
}

▲Arduino言語でそのままラズパイPicoへ書き込み可能です。和と差を百万回繰り返して円周率を計算してます。

▼結果▼

ざっくりした時間計測ですが、シングルコアでおよそ4秒ほどの処理時間です。ちなみにこのソースをUNOで動かすと52秒ほどかかりました。

続いて並列処理(デュアルコア)です。(2023/05⊿1:シリアル通信が開始されるまでプログラム待機されるようにソース修正。シリアル通信が開始されるまでオンボードLEDを点滅しながら待機、通信開始後にプログラムが起動するよう変更)

// 2021/06/01 imo lab.
// 2023/05/03 起動待機処理追加
// https://garchiving.com/

uint32_t core0_Timer, core0_dt;
uint32_t core1_Timer, core1_dt;
uint32_t total_Timer, elapsedTime;
volatile bool F;
double   s0, s1, s;

//core0//////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  pinMode(25, OUTPUT);
  while (!Serial) {
    digitalWrite(25, digitalRead(25) == LOW ? 1 : 0);
    delay(200);
  }
  delay(1000);
  Serial.printf("core0:start....\n");
}

void loop() {
  total_Timer = micros();
  core0_Timer = total_Timer;
  for (uint32_t n = 1; n <= 1000000; n++) {
    if (n % 2 == 1) s0 += 1.0 / (2 * n - 1.0);
  }
  core0_dt = micros() - core0_Timer;
  while (!F);
  s = (s0 + s1) * 4;
  elapsedTime = micros() - total_Timer;
  Serial.printf("  core0 time:%6d ms%7s%9.5f\n", core0_dt / 1000, "s0:", s0);
  Serial.printf("  core1 time:%6d ms%7s%9.5f\n", core1_dt / 1000, "s1:", s1);
  Serial.printf("elapsed time:%6d ms%7s%9.5f\n\n\n", elapsedTime / 1000, "ans:", s);
  while (1);
}

//core1//////////////////////////////////////////////////////////////////////
void setup1() {
  while (!Serial) {
    //digitalWrite(25, digitalRead(25) == LOW ? 1 : 0);
    delay(200);
  }
  delay(1000);
  Serial.printf("core1:start....\n\n");
}

void loop1() {
  core1_Timer = micros();
  double temp = 0;
  for (uint32_t n = 1; n <= 1000000; n++) {
    if (n % 2 == 0) temp -= 1.0 / (2 * n - 1.0);
  }
  s1 = temp;
  F = 1;
  core1_dt = micros() - core1_Timer;
  while (1);
}

 少し見難いですが、積み上げ計算の和の部分と差の部分をcore0/core1で分担して計算処理してます。互いの積み上げ計算が完了したら、core0 で最終処理をして円周率を計算してます。

▼結果▼

▲2秒ほどで計算終了。シングルコアの処理と比較しておよそ1.8倍ほどの速度向上。core0のほうが若干早く演算が終了し、core1の終了待ってる感じですかね。繰り返し処理を単純に2coreで分担しているので処理時間としては、おおむね想定通りです。

  デュアルコアですが思いのほか簡単に使えますね。ただ残念ながら何に使えばいいのか、あまりいい使い道が思い浮かびません。Picoでドローン作るのも面白そうですね。

コメント

タイトルとURLをコピーしました