Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/mobench/ios10/BenchRunnerApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import UIKit

@UIApplicationMain
final class BenchRunnerApp: UIResponder, UIApplicationDelegate {
var window: UIWindow?

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = BenchRunnerViewController()
window.makeKeyAndVisible()
self.window = window
return true
}
}
150 changes: 150 additions & 0 deletions .github/mobench/ios10/ContentView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import UIKit

private struct ProfileLaunchOptions {
let benchDelayMs: UInt64
let resultHoldMs: UInt64
let repeatUntilMs: UInt64
let warmupOnly: Bool

static func resolved() -> ProfileLaunchOptions {
let info = ProcessInfo.processInfo

var benchDelayMs = UInt64(info.environment["MOBENCH_BENCH_DELAY_MS"] ?? "0") ?? 0
var resultHoldMs = UInt64(
info.environment["MOBENCH_PROFILE_RESULT_HOLD_MS"] ?? "5000"
) ?? 5000
var repeatUntilMs = UInt64(
info.environment["MOBENCH_PROFILE_REPEAT_UNTIL_MS"] ?? "0"
) ?? 0
var warmupOnly = info.environment["MOBENCH_PROFILE_WARMUP_ONLY"] == "1"

for arg in info.arguments {
if arg.hasPrefix("--mobench-profile-bench-delay-ms="),
let value = arg.split(separator: "=", maxSplits: 1).last,
let parsed = UInt64(value) {
benchDelayMs = parsed
} else if arg.hasPrefix("--mobench-profile-result-hold-ms="),
let value = arg.split(separator: "=", maxSplits: 1).last,
let parsed = UInt64(value) {
resultHoldMs = parsed
} else if arg.hasPrefix("--mobench-profile-repeat-until-ms="),
let value = arg.split(separator: "=", maxSplits: 1).last,
let parsed = UInt64(value) {
repeatUntilMs = parsed
} else if arg == "--mobench-profile-warmup-only"
|| arg == "--mobench-profile-warmup-only=1" {
warmupOnly = true
}
}

NSLog(
"[BenchRunner] Profile launch options: delayMs=%llu, repeatUntilMs=%llu, resultHoldMs=%llu, warmupOnly=%@",
benchDelayMs,
repeatUntilMs,
resultHoldMs,
warmupOnly ? "true" : "false"
)

return ProfileLaunchOptions(
benchDelayMs: benchDelayMs,
resultHoldMs: resultHoldMs,
repeatUntilMs: repeatUntilMs,
warmupOnly: warmupOnly
)
}
}

final class BenchRunnerViewController: UIViewController {
private let reportLabel = UILabel()
private let completedLabel = UILabel()
private let jsonLabel = UILabel()
private let stack = UIStackView()
private var started = false

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white

reportLabel.accessibilityIdentifier = "benchmarkReport"
reportLabel.font = UIFont(name: "Menlo", size: 13) ?? UIFont.systemFont(ofSize: 13)
reportLabel.numberOfLines = 0
reportLabel.text = "Running benchmarks..."

completedLabel.accessibilityIdentifier = "benchmarkCompleted"
completedLabel.isAccessibilityElement = true
completedLabel.text = ""
completedLabel.accessibilityLabel = ""

jsonLabel.accessibilityIdentifier = "benchmarkReportJSON"
jsonLabel.isAccessibilityElement = true
jsonLabel.text = ""
jsonLabel.accessibilityLabel = ""
jsonLabel.numberOfLines = 1

stack.addArrangedSubview(reportLabel)
stack.axis = .vertical
stack.spacing = 8
stack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stack)

NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 12),
stack.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -12),
stack.topAnchor.constraint(equalTo: view.topAnchor, constant: 28),
stack.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -12)
])
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard !started else {
return
}
started = true

DispatchQueue.global(qos: .userInitiated).async {
let options = ProfileLaunchOptions.resolved()
if options.benchDelayMs > 0 {
Thread.sleep(forTimeInterval: Double(options.benchDelayMs) / 1_000.0)
}

let repeatDeadline = Date().addingTimeInterval(
Double(options.repeatUntilMs) / 1_000.0
)
var repeatedRuns = 1
var result = BenchRunnerFFI.runCurrentBenchmark()
while !options.warmupOnly && options.repeatUntilMs > 0 && Date() < repeatDeadline {
result = BenchRunnerFFI.runCurrentBenchmark()
repeatedRuns += 1
}

DispatchQueue.main.async {
self.reportLabel.text = result.displayText
self.jsonLabel.text = result.jsonReport
self.jsonLabel.accessibilityLabel = result.jsonReport
self.completedLabel.text = "completed"
self.completedLabel.accessibilityLabel = "completed"
if self.completedLabel.superview == nil {
self.stack.addArrangedSubview(self.completedLabel)
self.stack.addArrangedSubview(self.jsonLabel)
}
}

NSLog("BENCH_REPORT_JSON_START")
NSLog("%@", result.jsonReport)
NSLog("BENCH_REPORT_JSON_END")
if repeatedRuns > 1 {
NSLog("Repeated benchmark %d time(s) during profile capture", repeatedRuns)
}

if options.warmupOnly {
NSLog("Warmup-only profile run complete")
return
}

NSLog("Displaying results for \(options.resultHoldMs) ms for capture output...")
Thread.sleep(forTimeInterval: Double(options.resultHoldMs) / 1_000.0)
NSLog("Display hold complete")
}
}
}
6 changes: 3 additions & 3 deletions .github/workflows/mobile-bench-pr-auto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ jobs:
secrets: inherit
with:
crate_path: ./bench-mobile
functions: '["bench_mobile::bench_passport_complete_age_check_prove"]'
functions_ios: '["bench_mobile::bench_passport_complete_age_check_prove"]'
functions_android: '["bench_mobile::bench_passport_complete_age_check_prove"]'
functions: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
functions_ios: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
functions_android: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
platform: both
device_profile: smoke
iterations: "2"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/mobile-bench-pr-command.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ jobs:
secrets: inherit
with:
crate_path: ./bench-mobile
functions: '["bench_mobile::bench_passport_complete_age_check_prove"]'
functions_ios: '["bench_mobile::bench_passport_complete_age_check_prove"]'
functions_android: '["bench_mobile::bench_passport_complete_age_check_prove"]'
functions: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
functions_ios: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
functions_android: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
platform: ${{ needs.resolve.outputs.platform }}
device_profile: ${{ needs.resolve.outputs.device_profile }}
iterations: ${{ needs.resolve.outputs.iterations }}
Expand Down
83 changes: 56 additions & 27 deletions .github/workflows/mobile-bench-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ on:
description: "PR number for reporting"
required: false
type: string
report_repository:
description: "owner/repo to receive the sticky benchmark comment; defaults to the workflow repository"
required: false
type: string
default: ""
requested_by:
description: "Who triggered the run"
required: false
Expand Down Expand Up @@ -102,13 +107,14 @@ jobs:
env:
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
IPHONEOS_DEPLOYMENT_TARGET: "13.0"
CFLAGS_aarch64_apple_ios: "-miphoneos-version-min=13.0"
CFLAGS_aarch64_apple_ios_sim: "-mios-simulator-version-min=13.0"
CFLAGS_x86_64_apple_ios: "-mios-simulator-version-min=13.0"
CARGO_TARGET_AARCH64_APPLE_IOS_RUSTFLAGS: "-C link-arg=-miphoneos-version-min=13.0"
CARGO_TARGET_AARCH64_APPLE_IOS_SIM_RUSTFLAGS: "-C link-arg=-mios-simulator-version-min=13.0"
CARGO_TARGET_X86_64_APPLE_IOS_RUSTFLAGS: "-C link-arg=-mios-simulator-version-min=13.0"
IOS_DEPLOYMENT_TARGET: "10.0"
IPHONEOS_DEPLOYMENT_TARGET: "10.0"
CFLAGS_aarch64_apple_ios: "-miphoneos-version-min=10.0"
CFLAGS_aarch64_apple_ios_sim: "-mios-simulator-version-min=10.0"
CFLAGS_x86_64_apple_ios: "-mios-simulator-version-min=10.0"
CARGO_TARGET_AARCH64_APPLE_IOS_RUSTFLAGS: "-C link-arg=-miphoneos-version-min=10.0"
CARGO_TARGET_AARCH64_APPLE_IOS_SIM_RUSTFLAGS: "-C link-arg=-mios-simulator-version-min=10.0"
CARGO_TARGET_X86_64_APPLE_IOS_RUSTFLAGS: "-C link-arg=-mios-simulator-version-min=10.0"
steps:
- name: Checkout caller repo
uses: actions/checkout@v4
Expand All @@ -124,16 +130,16 @@ jobs:
set -euo pipefail
case "${DEVICE_PROFILE}" in
smoke)
device_specs="iPhone 16 Pro-18"
fetch_timeout_secs="1200"
device_specs="iPhone 7-10"
fetch_timeout_secs="3600"
;;
worst)
device_specs="iPhone SE 2020-16"
fetch_timeout_secs="1800"
device_specs="iPhone 7-10"
fetch_timeout_secs="3600"
;;
triad)
device_specs="iPhone SE 2020-16,iPhone 15-17,iPhone 16 Pro-18"
fetch_timeout_secs="2400"
device_specs="iPhone 7-10,iPhone 15-17,iPhone 16 Pro-18"
fetch_timeout_secs="3600"
;;
*)
echo "::error::Unsupported device_profile '${DEVICE_PROFILE}'. Supported values: smoke, triad, worst."
Expand Down Expand Up @@ -204,6 +210,24 @@ jobs:
--target ios \
$RELEASE_FLAG \
--crate-path "$CRATE_PATH"

project_yml="target/mobench/ios/BenchRunner/project.yml"
if [[ ! -f "$project_yml" ]]; then
echo "::error::Expected generated XcodeGen project at ${project_yml}"
exit 1
fi

if ! grep -q 'deploymentTarget: "15.0"' "$project_yml"; then
echo "::error::No deploymentTarget entries were rewritten in ${project_yml}"
exit 1
fi
perl -0pi -e "s/deploymentTarget: \"15\\.0\"/deploymentTarget: \"${IOS_DEPLOYMENT_TARGET}\"/g" "$project_yml"
cp .github/mobench/ios10/BenchRunnerApp.swift target/mobench/ios/BenchRunner/BenchRunner/BenchRunnerApp.swift
cp .github/mobench/ios10/ContentView.swift target/mobench/ios/BenchRunner/BenchRunner/ContentView.swift
perl -0pi -e 's/options: \[\.sortedKeys\]/options: []/g' target/mobench/ios/BenchRunner/BenchRunner/BenchRunnerFFI.swift
(cd target/mobench/ios/BenchRunner && xcodegen generate)
grep -n 'deploymentTarget' "$project_yml"

cargo-mobench package-ipa --method adhoc --crate-path "$CRATE_PATH"
cargo-mobench package-xcuitest --crate-path "$CRATE_PATH"
test -f target/mobench/ios/BenchRunner.ipa
Expand Down Expand Up @@ -237,7 +261,7 @@ jobs:
local attempt_log="$1"
local json_path

if grep -Eiq 'BrowserStack API .*status 5[0-9]{2}|This website is under heavy load|fetch did not recover any benchmark payloads' "$attempt_log"; then
if grep -Eiq 'BrowserStack API .*status 5[0-9]{2}|This website is under heavy load|fetch did not recover any benchmark payloads|Timeout waiting for build .* to complete' "$attempt_log"; then
return 0
fi

Expand Down Expand Up @@ -342,16 +366,16 @@ jobs:
set -euo pipefail
case "${DEVICE_PROFILE}" in
smoke)
device_specs="Google Pixel 7-13.0"
fetch_timeout_secs="1200"
device_specs="Vivo Y21-11.0"
fetch_timeout_secs="7200"
;;
worst)
device_specs="Motorola Moto G9 Play-10.0"
fetch_timeout_secs="1800"
device_specs="Vivo Y21-11.0"
fetch_timeout_secs="7200"
;;
triad)
device_specs="Motorola Moto G9 Play-10.0,Google Pixel 7-13.0,Samsung Galaxy S24-14.0"
fetch_timeout_secs="2400"
device_specs="Vivo Y21-11.0,Google Pixel 7-13.0,Samsung Galaxy S24-14.0"
fetch_timeout_secs="7200"
;;
*)
echo "::error::Unsupported device_profile '${DEVICE_PROFILE}'. Supported values: smoke, triad, worst."
Expand Down Expand Up @@ -474,7 +498,7 @@ jobs:
local attempt_log="$1"
local json_path

if grep -Eiq 'BrowserStack API .*status 5[0-9]{2}|This website is under heavy load|fetch did not recover any benchmark payloads' "$attempt_log"; then
if grep -Eiq 'BrowserStack API .*status 5[0-9]{2}|This website is under heavy load|fetch did not recover any benchmark payloads|Timeout waiting for build .* to complete' "$attempt_log"; then
return 0
fi

Expand Down Expand Up @@ -772,8 +796,9 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ inputs.pr_number }}
REPO: ${{ github.repository }}
REPO: ${{ inputs.report_repository != '' && inputs.report_repository || github.repository }}
run: |
set -euo pipefail
MARKER="<!-- mobench-summary -->"
BODY="${MARKER}
## Mobench Benchmark Results
Expand All @@ -794,17 +819,21 @@ jobs:
---
*Posted by [mobench](https://github.com/worldcoin/mobile-bench-rs) at $(date -u '+%Y-%m-%d %H:%M UTC')*"

EXISTING_COMMENT_ID=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \
--jq ".[] | select(.body | contains(\"${MARKER}\")) | .id" \
2>/dev/null | head -1)
comments_json="$(mktemp)"
if gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" > "${comments_json}"; then
EXISTING_COMMENT_ID=$(jq -r --arg marker "${MARKER}" '.[] | select(.body | contains($marker)) | .id' "${comments_json}" | head -1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace jq|head pipeline in strict mode comment lookup

With set -euo pipefail enabled in this step, jq ... | head -1 can fail the script when head exits after the first match and jq receives SIGPIPE while still writing, which aborts sticky-comment handling instead of falling back to the warning paths. This is most likely when multiple marker-matching comments exist or the response is large; selecting the first ID inside jq avoids the pipeline failure mode.

Useful? React with 👍 / 👎.

else
echo "::warning::Unable to list comments for ${REPO}#${PR_NUMBER}; skipping sticky benchmark comment."
exit 0
fi

if [ -n "$EXISTING_COMMENT_ID" ]; then
gh api "repos/${REPO}/issues/comments/${EXISTING_COMMENT_ID}" \
-X PATCH \
-f body="${BODY}" \
--silent
--silent || echo "::warning::Unable to update sticky benchmark comment ${EXISTING_COMMENT_ID} in ${REPO}."
else
gh api "repos/${REPO}/issues/${PR_NUMBER}/comments" \
-f body="${BODY}" \
--silent
--silent || echo "::warning::Unable to create sticky benchmark comment in ${REPO}#${PR_NUMBER}."
fi
12 changes: 9 additions & 3 deletions .github/workflows/mobile-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ on:
description: "JSON array of benchmark functions"
required: false
type: string
default: '["bench_mobile::bench_passport_complete_age_check_prove"]'
default: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
functions_ios:
description: "Optional iOS-specific benchmark functions"
required: false
type: string
default: '["bench_mobile::bench_passport_complete_age_check_prove"]'
default: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
functions_android:
description: "Optional Android-specific benchmark functions"
required: false
type: string
default: '["bench_mobile::bench_passport_complete_age_check_prove"]'
default: '["bench_mobile::bench_passport_complete_age_check_prove","bench_mobile::bench_oprf_prove","bench_mobile::bench_p256_bigcurve_prove"]'
platform:
description: "android | ios | both"
required: false
Expand Down Expand Up @@ -66,6 +66,11 @@ on:
required: false
type: string
default: ""
report_repository:
description: "owner/repo to receive the sticky benchmark comment; defaults to this repository"
required: false
type: string
default: ""
head_sha:
description: "Exact commit SHA to benchmark"
required: false
Expand Down Expand Up @@ -125,5 +130,6 @@ jobs:
mobench_version: ${{ inputs.mobench_version }}
mobench_ref: ${{ inputs.mobench_ref }}
pr_number: ${{ inputs.pr_number }}
report_repository: ${{ inputs.report_repository }}
head_sha: ${{ inputs.head_sha }}
requested_by: ${{ inputs.requested_by }}
Loading
Loading