その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

Over HTTPでやり取りするAWS Lambdaのfunctionを書く時にはKeep-Aliveがパフォーマンスに効く(場合がある)

サーバレスだ! Microservicesだ! というふうなアーキテクチャになってくるとAWS Lambdaのような実行環境でコードを動かすことが多くなってくると思います.そしてそうした環境下で他のコンポーネントとHTTP越しにやりとりをするコードを動かすこともままあるでしょう.
そういった時にKeep-Aliveを有効にしておくとLambdaは一度張ったコネクションを使いまわしてくれるので,「同じエンドポイントを頻繁に叩く」かつ「呼ばれる回数が多い」Lambda functionだと結構パフォーマンスに効いてきます (もちろん接続先がkeep-aliveに対応している必要がありますが).

ということをLambdaのパフォーマンス周りのトラブルシューティングを行っている最中にふと気づき,やってみたところ果たしてパフォーマンスの問題は見事解決したわけですが,その後AWSが出しているLambdaのベストプラクティスのドキュメントを読んでみるとまさに同じことが書いてあり,やはり公式のドキュメントは強い……

> 前回の呼び出しで確立した接続を (HTTP、データベースなど) をキープアライブにして再利用します
AWS Lambda 関数を使用する際のベストプラクティス - AWS Lambda

AWS Lambdaはそのプロセスが立ち上がってからはライフサイクルに従って一定期間同一のプロセスが使用されるので,一度確保したリソースを使い回すことができます.従ってKeep-Aliveを有効にしておくと一度確立したコネクションを使いまわしてくれるため,コネクションを毎度張らずに済んでそのぶんの実行コストが減って経済的という感じです.助かった!


なお他のコンポーネントとOver HTTPでコミュニケーションするタイプのLambdaのアーキテクチャの是非についてはid:y_uukiさんのブログに良い考察があります:


ところで

この件ですがみなさんはどう呼んでいますか? おたよりをお待ちしています.

builderscon tokyo 2018に登壇します

表題の通り,builderscon tokyo 2018に登壇します.JavaCardという環境をテーマにお話する予定です.

builderscon.io

今回はかなりマニアックな話になることが現時点で予想されていますが,内容はかなり面白いと思います (先日社内の専門家にディープな講習を受けました). いつものJavaとは一味違うJavaを目の当たりにすることになるでしょう……

9/7 (金) の15:30からセッション開始ですから,お昼から会場内のHUBで一杯引っ掛けてから来てもちょうど良い感じの時間ですね! 是非会場でお会いしましょう!!!!

pptxファイルから発表者ノートを一括削除する方法

カンペとしてスライドに発表者ノートを書くことはままあるとおもうんですが,そのスライドを共有する際には発表者ノートを削除したくなるのが人情というものです (カンペを見られるのは恥ずかしい).
Windows版のPowerPointであれば発表者ノートを一括削除するメニューがあるのですが,一方macOS版のPowerPointにはなぜかそのメニューが無いため手でポチポチやるしか方法は無いのか……と途方に暮れていたところ,pptxはそもそもzipでアーカイブされたxmlの集合体ということを思い出し,unzipしてxmlを書き換えてzipし直すという手法を思いつきました.

以下スクリプト:

#!/bin/bash

set -eu

PPTX_FILE_PATH="$1"
PPTX_FILE="$(basename "$PPTX_FILE_PATH")"

TMP_DIR="$(mktemp -d)"
trap 'rm -rf $TMP_DIR' EXIT

cp "$PPTX_FILE_PATH" "$TMP_DIR"

pushd "$TMP_DIR"

unzip "$PPTX_FILE"
rm "$PPTX_FILE"
gfind ./ppt/notesSlides/*.xml | xargs gsed -i'' -e's/<a:t>[^<]*<\/a:t>/<a:t><\/a:t>/g' # remove slide note contents
zip -0 -r "$PPTX_FILE" ./* # do not compress (-0)

popd

cp "$TMP_DIR/$PPTX_FILE" "note-removed-$PPTX_FILE"

これで発表者ノートを消すべきpptxファイルがたくさんあっても安心! よかったですね.

ESP32でZephyrを開発する環境を整える - macOS編

ZephyrはApache Lisence, Version 2.0で公開されているRTOSです.多分「ゼファー」と読むはず.
https://www.zephyrproject.org/

このZephyrをESP32のボードで開発する環境をmacOS上に整えるというのがこの記事の目的です.
なおESP32開発ボードは今回以下を使いました: http://akizukidenshi.com/catalog/g/gM-11819/

基本的にZephyrの以下のドキュメントに従うとできます:

http://docs.zephyrproject.org/getting_started/installation_mac.html
http://docs.zephyrproject.org/boards/xtensa/esp32/doc/esp32.html

事前準備
$ brew install direnv cmake ninja dfu-util doxygen qemu dtc python3 gperf

開発環境が問答無用でSystemのPython3を見てくるのでインストールする必要があります.direnvはあるとなにかと便利なので入れています.

(上記開発ボードを使っている場合) CP210x USB to UART Bridge VCP driversを入れる

https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

もしもmacOS High Sierra以降を使っている場合は Security & Privacy でインストール時にBlockしているソフトウェアベンダーをAllowする必要があります (Silicon Laboratoriesとか).
これがないと開発ボードがシリアルデバイスとして認識されない.

Espressif Toolchainを入れる
$ mkdir -p ~/opt/esp
$ cd ~/opt/esp
$ curl -O https://dl.espressif.com/dl/xtensa-esp32-elf-osx-1.22.0-80-g6c4433a-5.2.0.tar.gz
$ tar zxf xtensa-esp32-elf-osx-1.22.0-80-g6c4433a-5.2.0.tar.gz

xtensa-esp32-elf-osxのバージョンについては実際どこを見れば最新なのかがわからなかった (ダウンロード可能なバージョン一覧が取れるページを見つけられなかった) ので,雑に調べて出てきたものを使っています.
確証はありませんが,
arduino-esp32/package_esp32_index.template.json at master · espressif/arduino-esp32 · GitHub
の中身に書いているやつを使っておけば良いような気がしています (espressifの公式リポジトリだし).

ESP32 IDFを入れる

要はRTOS SDKです.

$ git clone --recursive https://github.com/espressif/esp-idf.git
$ cd esp-idf
$ git checkout dc8c33892e0

espressifのリポジトリからESP32 IDFをcloneしてきます.
加えてZephyrのドキュメントにあったので,IDFのリビジョンを過去のものに固定しています.

Since ESP-IDF is an external project in constant development, it’s possible that files that Zephyr depends on will be moved, removed, or renamed. Those files are mostly header files containing hardware definitions, which are unlikely to change and require fixes from the vendor. In addition to setting the environment variables above, also check out an earlier version of ESP-IDF
http://docs.zephyrproject.org/boards/xtensa/esp32/doc/esp32.html

Zephyrをダウンロードして諸々の開発環境を整える
$ git clone git@github.com:zephyrproject-rtos/zephyr.git /path/to/zephyr
$ cd /path/to/zephyr
$ pip3 install --user -r scripts/requirements.txt
$ cat <<EOS >> .envrc

export PATH="$PATH:$HOME/opt/esp/xtensa-esp32-elf/bin
export ZEPHYR_TOOLCHAIN_VARIANT="espressif"
export ESP_IDF_PATH="$HOME/opt/esp/esp-idf"
export ESPRESSIF_TOOLCHAIN_PATH="$HOME/opt/esp/xtensa-esp32-elf/"

source ./zephyr-env.sh
export ESP_DEVICE="/dev/cu.blahblah" # ここは開発ボードによって変わるでしょう
export ESP_BAUD_RATE=115200 # ここは開発ボードによって変わるでしょう
export ESP_FLASH_SIZE="detect"
export ESP_FLASH_FREQ="40m"
export ESP_FLASH_MODE="dio"

EOS
$ direnv allow

ZephyrはGitHubで公開されているので普通にgit cloneしてくれば良いです.
次にpythonで書かれたツールを動かすための依存ライブラリをインストールします.このコマンドではSystem python以下に依存ライブラリが入ります (system pythonを使わずに済ます方法は無いものか……).
あとは諸々の環境変数を.envrcに書き込んでdirenvでそれらを有効にしてやる.

Hello-Worldを動かしてみる
$ cd "$ZEPHYR_BASE/samples/hello_world"
$ mkdir build && cd build
$ cmake -DESP_IDF_PATH="$ESP_IDF_PATH" -GNinja -DBOARD=esp32 ..
$ west flash \
   --esp-device="$ESP_DEVICE" \
   --esp-baud-rate="$ESP_BAUD_RATE" \
   --esp-flash-size="$ESP_FLASH_SIZE" \
   --esp-flash-freq="$ESP_FLASH_FREQ" \
   --esp-flash-mode="$ESP_FLASH_MODE"
$ screen $ESP_DEVICE $ESP_BAUD_RATE # and push reset button

以上のようにコマンドを叩くとプログラムのビルドとボードへの書き込みを行うことができます.
公式ドキュメントでは ESP_DEVICEESP_BAUD_RATE といった環境変数を設定しておくと ninja flash コマンドはそれらをリスペクトするように書いてあるが,実際にそのような処理が行われている気配はない (ざっとコードを読んだ) ので, ninja コマンドの代わりに west を利用し,そのコマンドラインオプションで各種設定を与えるようにしています.
あとはscreenでTTYにつないでボードのリセットボタンを押すと "Hello World: esp32" が表示されるはずです!


以上です.これでmacOS上でESP32向けのZephyrプログラムが開発できます.やりましたね.

Scrapboxのコンテンツエリアが広いと嬉しい!!!!

scrapbox.io
ユーザースクリプト機能で以下のCSSを読み込ませると……

.page-wrapper{
  width:100%;
  position: absolute;
  left: 0px;
}
.col-page-side{
  position: absolute;
  right: 0px;
}

f:id:moznion:20180601134210p:plain

嬉しい!!!!

expectコマンドを使ってシリアル接続で非対話的にコマンドを流し込む

シリアル接続でコマンドを実行する際は cu コマンドや screen コマンドなどでシリアルコンソールに接続して対話的にコマンドを実行することになると思うんですが,しかし「一定周期ごとにシリアルでコマンドを実行して結果を取得したい」みたいなときに対話モードだとだるいわけです.
というわけで expect の出番です.以下のように expect コマンドを利用すると非対話的にシリアルにコマンドを流し込むことができます. expect コマンドについてはこちらを参照されたい:
expect(1) - Linux man page

expect -c "
  spawn cu -l ${TTY} -s 9600
  send \"AT+CGREG=2\\n\"
  expect \"OK\"
  send \"AT+CGREG?\\n\"
  expect \"+CGREG:\"
  exit 0
"

これは

soracom.zendesk.com

にあるLACとCIDを取得するATコマンドの例ですが,こうしてやることで非対話的にATコマンドを流し込むことができます.

while :
do
  RESULT="$(expect -c "
    spawn cu -l ${TTY} -s 9600
    send \"AT+CGREG=2\\n\"
    expect \"OK\"
    send \"AT+CGREG?\\n\"
    expect \"+CGREG:\"
    exit 0
  " | grep '^+CGREG:')"

  PCRE_LAC_CID_PATTERN='"(.+?)",\s*"(.+?)"'
  LAC="$(echo "$RESULT" | perl -ale "/${PCRE_LAC_CID_PATTERN}/; print \$1")"
  CID="$(echo "$RESULT" | perl -ale "/${PCRE_LAC_CID_PATTERN}/; print \$2")"

  echo "{\"LAC\":$LAC, \"CID\":$CID}"

  sleep 60
done

例えばこうしてやると1分ごとにcell locationが取れて便利.expect コマンド最高!!!! (しかし難しい)

C言語のジェネリクスサポート

全く知らなかったのだけれど,C11の新機能として_Genericという組み込み関数が提供されていた.
Generic selection - cppreference.com


jameshfisher.com

というのをこのブログを見て気づいたんですが,

#include <stdio.h>
int main() {
  char* x = "foo";
  printf("Type of x is: %s\n", _Generic(x, char*: "string", int: "int"));
  return 0;
}

これは完全に動くコード (最初よく文章を読んでなくて,大方擬似コードだろうと侮っていたら本当に動いて驚いた).
だいたい分かると思うんですが,上記のコードは char*の引数が_Genericに渡されるとstringという文字列を出力し,intの引数が与えられるとintという文字列が出力されるという挙動をします.

しかしこれが「リッチなgenericsか」というとそうではなくて,_Genericの引数に延々と型とそれに対応するvalueを書いていかなければならないので,どちらかと言うとType Assertionに近いイメージ.JavagenericsC++のTemplateのようにコンパイル時に良い感じに自動解決してくれるような類のものではない.惜しいですね.とはいえ便利ではある.

問題としてはC11なんてモダンなものを使う環境ってあるの……? という部分であるが……

Code sampleとしては以下がわかりやすかった: http://www.robertgamble.net/2012/01/c11-generic-selections.html