4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

株式会社ゆめみAdvent Calendar 2024

Day 22

Swift の DateFormatter のコストを計測する

Last updated at Posted at 2024-12-21

Swift のコードレビューをしてるとき、『DateFormatter の生成コストは高いから、毎回生成せずに使い回すといいよ』と指摘することがあります。ただ、実際にコストを計測したことがなかったので、実際はどれぐらいなんだろう。ならば、計測しましょう。

本記事の計測について

本記事で扱う計測は、厳密な計測ではないことに注意してください。実装の差によって「負荷がこれぐらい違うよ」程度の目安として、読んでください。厳密な計測は、厳密な計測結果を知りたいと思ったアナタが計測します。

計測対象は macOS 上のターミナルで実行するシンプルな実行ファイルとします。その実行ファイルを実行して、計算時間、CPU使用量、メモリ使用量を計測します。

計測環境は、MacBook Pro 14インチ 2021 / Apple M1 Pro / メモリ 32 GB / macOS Sonoma 14.6.1 で行いました。また、計測ツールに Python、対象コードのビルドに swiftc を利用しました。

% python --version
Python 3.11.2

% swiftc --version
swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

Python で計測関数を作る

計測対象の実行ファイルを実行して、その計算時間、実行中のCPUとメモリの利用量を計測するツールを Python で作成しました。

measure.py
import psutil
import subprocess
import time
import argparse

def monitor_process(executable_path):
    # 測定対象のプログラムを開始
    process = subprocess.Popen([executable_path], stdout=subprocess.PIPE)

    # 初期値を取得
    initial_cpu = psutil.cpu_percent(interval=0.1)  # 実行前のCPU使用率
    initial_memory = psutil.virtual_memory().used  # 実行前のメモリ使用量 (バイト)

    # 最大値を記録するための変数
    max_cpu_usage = 0
    max_memory_usage = 0

    # 開始時間
    start_time = time.time()

    # プロセスが終了するまでモニタリング
    while process.poll() is None:
        # 現在のCPUとメモリの使用量を取得
        cpu_usage = psutil.cpu_percent(interval=0.1)
        memory_info = psutil.virtual_memory().used

        # 最大値を更新
        max_cpu_usage = max(max_cpu_usage, cpu_usage)
        max_memory_usage = max(max_memory_usage, memory_info)

        # 情報を表示する(計測中は、この表示が負荷となるのでコメントアウトする)
        # print(f"CPU Usage: {cpu_usage}%, Memory Usage: {(memory_info - initial_memory) / (1024 ** 2):.2f} MB")

    # 終了時間
    end_time = time.time()

    # 実行時間を計算
    execution_time = end_time - start_time

    # 結果を表示
    print("\n--- Monitoring Results ---")
    print(f"Execution time: {execution_time:.2f} seconds")
    print(f"Maximum CPU Usage: {max_cpu_usage:.2f} %")
    print(f"Maximum Memory Usage: {(max_memory_usage - initial_memory) / (1024 ** 2):.2f} MB")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Monitor CPU and memory usage of an executable.")
    parser.add_argument("executable", help="Path to the executable file")
    args = parser.parse_args()

    monitor_process(args.executable)

この関数を実行するために、psutil をインストールしてください。

pip install psutil

計測したい実行ファイルを引数に設定して、計測を行います。

python measure.py {実行ファイル}
# python measure.py ./code

--- Monitoring Results ---
Execution time: **.** seconds
Maximum CPU Usage: **.** %
Maximum Memory Usage: **.** MB

繰り返しになりますが、この実装は厳密な計測ではありません。計測中に他プロセスが動作したら、その影響も受けます。また、この計測ツール自体の実行負荷も影響します。

DateFormatter のコストを計測する

DateFormatter の生成コストを計測するため、簡単なコードを用意しました。code1.swift は毎回 DateFormatter を生成します。

code1.swift
import Foundation

for _ in 0..<1_000_000 {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    _ = dateFormatter.string(from: Date())
}

一方で、code2.swift は1つの DateFormatter を利用します。

code2.swift
import Foundation

let dateFormatter = DateFormatter()
for _ in 0..<1_000_000 {
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    _ = dateFormatter.string(from: Date())
}

これらコードは次のようにビルドして、計測関数に渡しました。

% swiftc code1.swift -o code1
% swiftc code1.swift -o code2
% python measure.py code1
% python measure.py code2

では、実際に計測した結果です。

計算時間 最大CPU使用量 最大メモリ使用量
code1 44.86 秒 19.80% 184.53 MB
code2 2.62 秒 14.70% 7.62 MB

DateFormatter を逐次生成した code1 は、1つの DateFormatter を利用した code2 と比べると明らかに負荷が大きいですね。実際に計測すると、ここまで差が大きく出るとは驚きです。ただ、時間変換を大量に for ループで処理するのは実アプリではないと思うので、実際にどう実装するかはコードによるかなと思います。

まとめ

「推測するな、計測せよ」とも言われてますが、実際に計測すると面白いですね。以上、終わり。

4
0
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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?