LoginSignup
3

More than 3 years have passed since last update.

posted at

updated at

Organization

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

この記事は「#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で世界の消費電力を抑えるをお送りします。お楽しみに。

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
What you can do with signing up
3