Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swift Macroでメソッドの実行時間を計測できるようにしてみた
Search
Ryu-nakayama
October 25, 2024
Programming
1
68
Swift Macroでメソッドの実行時間を計測できるようにしてみた
2024/10/25 mobile.stmn #8の登壇資料です
Ryu-nakayama
October 25, 2024
Tweet
Share
More Decks by Ryu-nakayama
See All by Ryu-nakayama
Appleの審査担当の方とお話ししてみた!
ryunakayama
0
220
大公開!iOS開発の悩みトップ5 〜iOSDC Japan 2024〜
ryunakayama
0
240
Translation API について 〜WWDC24〜
ryunakayama
0
220
効率化に挑戦してみたらモバイル開発が少し快適になった話
ryunakayama
0
1.7k
新卒1年目がプロジェクトを進めるときにコケたポイント
ryunakayama
1
1.7k
期限が近づいてきた!Privacy Manifests対応
ryunakayama
5
10k
新卒iOSエンジニアとしてやってきたこと
ryunakayama
0
1.8k
今年学んだ便利ツール_便利技
ryunakayama
0
1.7k
git worktreeを使って複数ブランチを扱いやすくする
ryunakayama
0
3k
Other Decks in Programming
See All in Programming
flutterkaigi_2024.pdf
kyoheig3
0
120
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
110
シェーダーで魅せるMapLibreの動的ラスタータイル
satoshi7190
1
480
見せてあげますよ、「本物のLaravel批判」ってやつを。
77web
7
7.8k
C++でシェーダを書く
fadis
6
4.1k
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
190
Jakarta EE meets AI
ivargrimstad
0
560
카카오페이는 어떻게 수천만 결제를 처리할까? 우아한 결제 분산락 노하우
kakao
PRO
0
110
みんなでプロポーザルを書いてみた
yuriko1211
0
260
Nurturing OpenJDK distribution: Eclipse Temurin Success History and plan
ivargrimstad
0
920
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
250
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
2
1.1k
Featured
See All Featured
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
The Invisible Side of Design
smashingmag
298
50k
Why Our Code Smells
bkeepers
PRO
334
57k
What's in a price? How to price your products and services
michaelherold
243
12k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
329
21k
Navigating Team Friction
lara
183
14k
Thoughts on Productivity
jonyablonski
67
4.3k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
26
1.4k
YesSQL, Process and Tooling at Scale
rocio
169
14k
How to Think Like a Performance Engineer
csswizardry
20
1.1k
Fireside Chat
paigeccino
34
3k
Transcript
Swift Macroでメソッドの実行時間を 計測できるようにしてみた CP本部 iOSアプリ開発部 中山 龍 2024年10月25日 mobile.stmn #8
自己紹介 中山 龍 (なかやま りゅう) • 株式会社kubell ◦ 新卒2年目のiOSエンジニア(22) ◦
「Chatwork」アプリの開発を担当 • 愛知県在住 ◦ 日曜に引っ越しをし、熱田区民 → 中区民に @ryu_develop
今更ながらSwift Macro (Swift Syntax) で遊んでみたのでその内容を紹介します
注意事項 • 本スライドの内容や登場するコードは趣味で作成しているものであり、業 務で扱っているプログラム・プロダクト・開発環境とは一切関係ありません • 「試しに触ってみた」という趣旨の紹介であり、必ずしもベストプラクティス を紹介しているわけではありません • スライド・GitHubに掲載しているコードも完璧な動作を保証するものでは ありません
01 | Swift Macroとは
Swift Macroとは? - Swiftプログラム内でコンパイル時にコードを自動生成したり、変換したりする ための機能 - Swift5.9以降で導入 - @〜〜〜 や
#〜〜〜といった感じで使用する 参考: Swiftマクロの書き方 - WWDC2023 代表的なものだと - Observation (@Observable) - SwiftUIのプレビュー (#Preview) 強力で便利な機能だが、可読性などの観点から乱用しないように注意が必要!
02 | 実行時間を計測するMacroを書いてみた
完成イメージ 8 @(自作のMacro) 型に対して自作のMacroを付ける 型のメソッドを実行した時に、 実行したメソッド と時間 が表示され る
コードが見づらい部分も多いと思うので... https://github.com/Ryu-nakay/measuri ng-method-execution-time-macro.git コードを中心に説明をすると字が小さくて見づらいことが 想定されるので、文字中心で説明します〜!🙏 コードは必要に応じてGitHubをご覧ください → (スライドはイベント終了後に公開するので、その際に照ら し合わせながら見ていただくでも問題なし) 会場の様子を見ながら、必要そうであればライブコーディング風にお見せします
1. 単体のメソッドを計測可能にする
ルール: メソッドの実行時間の計測 メソッドの 処理開始時の時刻 と 処理終了時の時刻 の差を実行時間とする 11 終了時刻 開始時刻
実行時間 10時 20分 40秒 10時 20分 30秒 10秒 ざっくりとしたイメージ
ルール: メソッドの実行時間の計測 メソッドの 処理開始時の時刻 と 処理終了時の時刻 の差を実行時間とする 12 終了時刻 開始時刻
実行時間 10時 20分 40秒 10時 20分 30秒 10秒 ざっくりとしたイメージ メソッドの開始時刻と終了時刻を取得し、その差を 出力すればよさそう!
ルール: メソッドの実行時間の計測 -作成するMacroのイメージ- 13 展開 @自作Macro @自作Macro (今回、defer文などは考慮していません )
ルール: メソッドの実行時間の計測 -計測に使用する便利な型- 14 計測の事前準備として、MeasureTimeLoggerという型を作りました - 初期化時に時刻でプロパティを初期化 - stop呼び出しで実行時間の計算とprint出力
ルール: メソッドの実行時間の計測 -計測に使用する便利な型- 15 展開 BodyMacro を使ってメソッドの中身を書き換えよう!
2. BodyMacroを実装する
実装 -型の準備- BodyMacroに準拠した型を定義し、expansionメソッドを準備します // 実装
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) - expansionメソッドの引数 declaration が FunctionDeclSyntax型に変換できるかで判定する - FunctionDeclSyntax.body?.statements がメソッドの中身の構文となる
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける - 1.で取得した『メソッドの中身の構文』を 1行ずつ取り出し、その型が ReturnStmtSyntaxかどうか でreturn構文を判定することができる - 元の構文 + 処理終了時の構文となったものが出来上がる 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に `measureTimeLogger.stop()` を付け加える return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`を付け加 える
実装 -expansionメソッドの中身- 1. Macroが付与されている対象がメソッド構文であることを確認し、そのメソッドの中身の構文を取得する (できなければ何もイジらずに return) 2. メソッドの中身の構文を 1行ずつ取り出し、その行が return構文だった場合には、その前に
`measureTimeLogger.stop()` をくっつける return構文が存在していなかった場合には、メソッドの中身の構文の末尾に `measureTimeLogger.stop()`をくっつ ける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`をくっつける 3. メソッドの中身の先頭に `let measureTimeLogger = MeasureTimeLogger()`を付け加える - 2.で作成した『元のメソッドの構文 + メソッド終了時の構文』の先頭にメソッド開始時の構文を付け 加えてreturnする
最終的なBodyMacroの実装 https://github.com/Ryu-nakay/measuri ng-method-execution-time-macro.git
実装 あとは、Macroを使えるようにするために各所に記述を追加し ...
実装 無事に時間計測ができるようになりました!
Macro展開時 ↑ Macroを展開すると計測開始・終了の処理が付け加えられ ていることがわかります
一括でつけたい 無事に計測可能になったものの... 毎回メソッドに付与していくの面倒だなぁ... 一括で型のメソッド全てを計測可能にできないかな?
再掲: 完成イメージ 27 @(自作のMacro) 型に対して自作のMacroを付ける 型のメソッドを実行した時に、 実行したメソッド と時間 が表示され る
こうすればいける? 28 @(自作のMacro) Macroを展開 メソッド単体での計測はできるので、型に対してMacroをつけた時に右のように各 メソッドに @MeasureTimeが付与されるようにすればいいのでは?
3. MemberAttributeMacroを実装する
実装 -最終的なMemberAttributeMacroのコード- さっきと比べるとすごくシンプル!
実装 -最終的なMemberAttributeMacroのコード- expansionを実装 memberがメソッドの 構文であるかを判定 メソッドの構文であるものに対して @MeasureTimeを付与
実装 -最終的なMemberAttributeMacroのコード- expansionを実装 memberがメソッドの 構文であるかを判定 メソッドの構文であるものに対して @MeasureTimeを付与 これだけで完成!
実装 あとは、Macroを使えるようにするために各所に記述を追加し ...
使ってみる 34 Macroを展開 型に @TimeMeasureable を付けることで、その型が持つメソッドに @MeasureTimeを付与できました!
まとめ
まとめ・感想 36 まとめ • メソッド単体で計測可能することができる @MeasureTime を実装した ◦ BodyMacro •
型のメソッドに @MeasureTimeを付与できる @TimeMeasureableを実装した ◦ MemberAttributeMacro 感想 • 「Swift Macro / Swift Syntaxって専門知識がないと難しそう」と食わず嫌いしていたが、実際に 触ってみると動くものを作れるぐらいにはできた • Swift AST Explorer が便利すぎた ◦ Syntaxの深い知識を持ち合わせていなくても構造や型を調べられた • 本当は「Swiftのコードから実行された処理のシーケンス図を出力したい」というモチベーションで 始めたので、今後実現できたらと ...
働くをもっと楽しく、創造的に 37