Skip to content

パフォーマンスの問題

このガイドでは、kazunoko を使用したイベント読み込みの速度と安定性に関する問題を説明します。


パフォーマンス指標

読み出し速度

イベント読み込みの速度を測定します。

# 1000 イベント読み込みにかかる時間を測定
time uv run kazunoko read 1000 > /dev/null

出力例:

real    0m45.234s
user    0m2.345s
sys     0m1.234s
  • real: 実際の経過時間
  • user: CPU が処理に使った時間
  • sys: システムコール(ディスク I/O など)に使った時間

読み出し速度の目安

イベント数 予想時間 速度
100 5-10 秒 10-20 イベント/秒
1000 40-60 秒 15-25 イベント/秒
10000 400-600 秒 15-25 イベント/秒

目安となる式:

読み込み時間 ≈ イベント数 / 15-25 イベント/秒

読み出し速度が遅い場合

原因の診断フロー

1. 環境要因(poll_count、スレッショルド)か?
   → パラメータ調整で改善するか試す

2. デバイス/通信の問題か?
   → デバイスのリセット、ケーブル確認

3. PC の問題か?
   → CPU/メモリ使用率を確認

4. USB 接続の問題か?
   → USB ハブを外す、別のポートを試す

パラメータによる速度改善

poll_count を下げる(高速化するが取りこぼす可能性あり)

# 大きめ(遅い)
time uv run kazunoko read 100 --poll-count 50000

# 高速化
time uv run kazunoko read 100 --poll-count 1000

期待値:

poll_count: 50000 → 約 50-60 秒/1000 イベント
poll_count: 1000  → 約 10-15 秒/1000 イベント

イベントタイムアウトを短縮(不安定になる可能性あり)

# デフォルト(遅い)
time uv run kazunoko read 100 --event-timeout 5.0

# 短縮(高速だが失敗率増加)
time uv run kazunoko read 100 --event-timeout 1.0

時間計測で最適なパラメータを探す

# 異なる poll_count で速度比較
for poll_count in 1000 5000 10000 50000; do
  echo "Testing poll_count=$poll_count"
  /usr/bin/time -p uv run kazunoko read 100 --poll-count $poll_count > /dev/null 2>&1
  echo
done

CPU/メモリ使用率が高い場合

CPU 使用率の確認

# リアルタイム監視(macOS/Linux)
top

# または、単一コマンドで確認
ps aux | grep kazunoko

# または、バックグラウンドで実行して監視
uv run kazunoko read 1000 &
watch -n 0.5 'ps aux | grep kazunoko'

正常な値:

CPU: 5-15% (シングルスレッド)
メモリ: 50-100 MB

異常な値:

CPU: >30% (過度に高い)
メモリ: >500 MB (過度に高い)

メモリ使用率の確認

# メモリ使用量を確認
ps -o pid,vsz,rss,comm | grep kazunoko

# VSZ: 仮想メモリ(予約メモリ)
# RSS: 実メモリ(使用中のメモリ)

高い場合の対応

方法 1: ストリーミング処理(メモリ効率的)

イベントを全て読み込まず、1 個ずつ処理します。

# ファイルに保存しながら処理
uv run kazunoko read 10000 | \
  while read line; do
    echo "$line" >> events.jsonl
    # 他の処理
  done

方法 2: バッチ処理

一定数ずつ分割して読み込みます。

# 100 イベント × 100 回に分割
for i in {1..100}; do
  uv run kazunoko read 100 >> events.jsonl
done

方法 3: 不要なプロセスを停止

# 他のアプリケーションを終了
killall Slack
killall Firefox
# など

長時間測定での安定性

長時間実行のテスト

# 10 分間、イベント読み込みを続ける
timeout 600 uv run kazunoko read 100000 --use-sec > events.jsonl

# または、複数回実行
for run in {1..10}; do
  echo "Run $run..."
  uv run kazunoko read 1000 >> events_${run}.jsonl || echo "Failed on run $run"
done

メモリリークの確認

# 複数回実行してメモリ使用量を確認
for i in {1..5}; do
  echo "Run $i"
  uv run kazunoko read 1000 > /dev/null
  ps aux | grep kazunoko | grep -v grep | awk '{print $6}' | \
    awk '{print "Memory: " $1/1024 " MB"}'
done

正常:

Run 1: Memory: 75 MB
Run 2: Memory: 78 MB
Run 3: Memory: 76 MB

異常(メモリリーク):

Run 1: Memory: 75 MB
Run 2: Memory: 150 MB
Run 3: Memory: 225 MB

ハング/クラッシュ対策

# タイムアウト付きで実行
timeout 300 uv run kazunoko read 100000 --use-sec || \
  echo "Timeout or crash detected"

# 定期的にデバイスをリセット
uv run kazunoko reset
sleep 5
uv run kazunoko read 1000

ネットワーク遅延(リモート接続時)

USB ケーブルが長い場合や USB ハブ経由の場合、遅延が発生します。

遅延の測定

# ラウンドトリップタイムを測定
uv run kazunoko status --timeout 0.1 && echo "Fast" || echo "Slow"

# 複数回実行して平均を取る
for i in {1..10}; do
  time uv run kazunoko status > /dev/null
done

遅延がある場合の対応

# 1. USB ハブを外す
#    ケーブルを直接 PC に接続

# 2. より短いケーブルを使う
#    USB 2.0 または USB 3.0 対応のケーブル

# 3. タイムアウト値を増やす
uv run kazunoko read 1000 --timeout 0.5 --event-timeout 10.0

# 4. poll_count を減らす(高速化)
uv run kazunoko read 1000 --poll-count 1000

ディスク I/O の最適化

大量のイベント読み込みをファイルに保存する場合、ディスク I/O がボトルネックになることがあります。

ディスク速度の確認

# ディスク書き込み速度を測定
dd if=/dev/zero of=test_file bs=1M count=100
rm test_file

# または、ツールを使用
diskutil info / | grep "Device Block"

高速保存方法

方法 1: バッファリング(複数イベントを同時に書き込み)

# 一度に 1000 イベント読み込んで書き込み
for i in {1..10}; do
  uv run kazunoko read 1000 >> events.jsonl
done

方法 2: 高速ストレージを使用

# SSD に保存(HDD より高速)
uv run kazunoko read 10000 > /Volumes/FastSSD/events.jsonl

# または、メモリディスクに一時保存
mkramdisk 1024  # 1GB のメモリディスク作成
uv run kazunoko read 10000 > /Volumes/ramdisk/events.jsonl
mv /Volumes/ramdisk/events.jsonl ~/events.jsonl

方法 3: 圧縮ファイルに保存

# gzip で圧縮しながら保存(ディスク使用量削減)
uv run kazunoko read 10000 | gzip > events.jsonl.gz

# 復元する場合
gunzip events.jsonl.gz

Python スクリプトでのパフォーマンス最適化

効率的なストリーミング処理

from kazunoko import connect, Reader
import time

def benchmark_reading():
    """読み込み速度をベンチマーク"""
    start_time = time.time()
    event_count = 0

    with connect() as device:
        reader = Reader(device)

        # ストリーミング方式(メモリ効率的)
        for event in reader.stream_by_count(1000):
            event_count += 1
            # イベント処理(軽い処理なら毎回)
            if event_count % 100 == 0:
                print(f"Progress: {event_count} events")

    elapsed = time.time() - start_time
    rate = event_count / elapsed
    print(f"\nResults:")
    print(f"  Events: {event_count}")
    print(f"  Time: {elapsed:.1f} seconds")
    print(f"  Rate: {rate:.1f} events/second")

benchmark_reading()

バッチ処理で高速化

from kazunoko import connect, Reader
import json

def batch_processing():
    """バッチ処理で高速化"""
    with connect() as device:
        reader = Reader(device)
        batch_size = 100
        batch = []

        with open("events.jsonl", "w") as f:
            for event in reader.stream_by_count(10000):
                batch.append(event.model_dump_json())

                # バッチが満杯になったら一括書き込み
                if len(batch) >= batch_size:
                    f.write("\n".join(batch) + "\n")
                    batch = []

            # 残りを書き込み
            if batch:
                f.write("\n".join(batch) + "\n")

batch_processing()

並列処理(複数デバイスの場合)

import concurrent.futures
from kazunoko import connect, Reader

def read_from_device(port, device_id):
    """デバイスからイベント読み込み"""
    with connect(port=port) as device:
        reader = Reader(device)
        events = reader.read_by_count(1000)
        return device_id, len(events)

# 複数デバイスを並列読み込み
ports = ["/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2"]

with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    futures = [
        executor.submit(read_from_device, port, i)
        for i, port in enumerate(ports)
    ]

    for future in concurrent.futures.as_completed(futures):
        device_id, count = future.result()
        print(f"Device {device_id}: {count} events")

ログからパフォーマンス情報を取得

実行時間をログから確認

# 実行開始と終了のログを確認
tail ~/Library/Logs/kazunoko/kazunoko.json | \
  jq 'select(.record.message | contains("Event collection")) | .record.time.repr'

処理速度の推定

# ログからイベント読み込み速度を計算
tail -100 ~/Library/Logs/kazunoko/kazunoko.json | \
  jq -r '.record.time.repr, .record.message' | \
  grep -B1 "event" | head -20

トラブルシューティングチェックリスト

読み出し速度が遅い場合のチェックリスト:

□ poll_count は適切か?(1000-50000 の範囲)
□ イベントタイムアウトは長すぎないか?(5-10 秒程度)
□ スレッショルド値は高すぎないか?
□ USB ハブを使用していないか?(直接接続推奨)
□ ケーブルの長さは適切か?(5m 以下推奨)
□ PC のリソースに余裕があるか?(CPU/メモリ確認)
□ 他のプロセスが CPU を占有していないか?
□ ディスクの空き容量は十分か?
□ デバイスは正常に動作しているか?(status で確認)

次のステップ