13
3

More than 3 years have passed since last update.

CPU Info を開発している時にわかった Nerves 対応のコツ

Last updated at Posted at 2019-12-04

この記事は「#NervesJP Advent Calendar 2019」5日目の記事です。

昨日は「Pelemayを開発している時にわかった Nerves 対応のコツ」でした。今日も Nerves 対応のコツについてご紹介します。

Nerves 対応のコツその2: 外部コマンドを極力使わない

当初,CPU Info では,下記のウェブサイトの方針にしたがい,外部コマンドを使って CPU の情報を取得していました。

物理 CPU、CPU コア、および論理 CPU の数を確認する https://access.redhat.com/ja/solutions/2159401

また,uname を使ってカーネル情報を取得していました。

結果,下記の外部コマンドを使用していました。

  • cat
  • grep
  • sort
  • wc
  • uname

ところが,Nerves ではこれらの外部コマンドはデフォルトで備わっていません。その理由は,ファームイメージのサイズを小さくするためだと思います。

そこで,これらの外部コマンドを用いず,Elixir で同等機能を実装してあげました。

カーネルのリリース番号 (uname -r)

    kernel_release = case File.read("/proc/sys/kernel/osrelease") do
      {:ok, result} -> result
      _ -> nil
    end

カーネルバージョン (uname -v)

    kernel_version = case File.read("/proc/sys/kernel/version") do
      {:ok, result} -> result
      _ -> nil
    end

CPU タイプ (uname -m)

    cpu_type =
      :erlang.system_info(:system_architecture) |> List.to_string() |> String.split("-") |> hd

CPU モデル (grep model.name /proc/cpuinfo | sort -u)

    info =
      File.read!("/proc/cpuinfo")
      |> String.split("\n\n")
      # drop last (emtpy) item
      |> Enum.reverse()
      |> tl()
      |> Enum.reverse()
      |> Enum.map(fn cpuinfo ->
        String.split(cpuinfo, "\n")
        |> Enum.map(fn item ->
          [k | v] = String.split(item, ~r"\t+: ")
          {k, v}
        end)
        |> Map.new()
      end)

    cpu_models = Enum.map(info, &Map.get(&1, "model name")) |> List.flatten()

    cpu_model = hd(cpu_models)

CPU の数 (grep physical.id /proc/cpuinfo | sort -u | wc -l)

    # info は CPU モデルと共通 

    num_of_processors =
      Enum.map(info, &Map.get(&1, "physical id"))
      |> Enum.uniq()
      |> Enum.count()

CPU1つあたりのコア数 (grep cpu.cores /proc/cpuinfo | sort -u),全コア数

    # num_of_processors は共通

    t =
      Enum.map(info, &Map.get(&1, "cpu cores"))
      |> Enum.uniq()
      |> Enum.reject(& is_nil(&1))
      |> Enum.map(&(&1 |> hd |> String.to_integer()))
      |> Enum.sum()
    total_num_of_cores = if t == 0, do: 1, else: t

    num_of_cores_of_a_processor = div(total_num_of_cores, num_of_processors)

全スレッド数 (grep processor /proc/cpuinfo | wc -l)

    total_num_of_threads =
      Enum.map(info, &Map.get(&1, "processor"))
      |> Enum.count()

Nerves 対応のコツその3: /etc/os-release でディストリビューション情報を取る

Nerves でディストリビューション情報を取るときには,/etc/issue は存在しないので使えません。代わりに /etc/os-release を用います。

システムバージョン (cat /etc/issue)

    os_info = File.read!("/etc/os-release")
    |> String.split("\n")
    |> Enum.reverse |> tl |> Enum.reverse
    |> Enum.map(& String.split(&1, "="))
    |> Enum.map(fn [k, v] -> {k, v |> String.trim("\"")} end)
    |> Map.new()

    system_version = Map.get(os_info, "PRETTY_NAME")

おわりに

Nerves では通常の Linux と色々異なるので注意が必要という話でした。

明日は @Yoosuke さんの「Nerves と GraphQLsever の組み合わせを考える「ポエム」」です。よろしくお願いします。

次も「#NervesJP Advent Calendar 2019」12日目にNerves の可能性は IoT だけじゃない(前編)〜ElixirとPelemayで世界の消費電力を抑えるをお送りします。お楽しみに。

13
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3