@@ -912,6 +912,7 @@ final class HealthKitService {
|
||
| 912 | 912 |
archiveObservationID: Int64, |
| 913 | 913 |
progress: SnapshotFetchProgress? |
| 914 | 914 |
) async -> TypeCountFetchResult {
|
| 915 |
+ let dateFetchStartedAt = Date() |
|
| 915 | 916 |
let dateDeadline = Date().addingTimeInterval(timeoutSeconds) |
| 916 | 917 |
async let earliestTask = measureAPICall( |
| 917 | 918 |
queryType: "earliest_sample", |
@@ -932,7 +933,7 @@ final class HealthKitService {
|
||
| 932 | 933 |
let earliestResult = await earliestTask |
| 933 | 934 |
let latestResult = await latestTask |
| 934 | 935 |
var apiCalls = [earliestResult.apiCall, latestResult.apiCall] |
| 935 |
- let dateFetchElapsedSeconds = earliestResult.apiCall.elapsedSeconds + latestResult.apiCall.elapsedSeconds |
|
| 936 |
+ let dateFetchElapsedSeconds = Date().timeIntervalSince(dateFetchStartedAt) |
|
| 936 | 937 |
|
| 937 | 938 |
guard earliestResult.apiCall.status == .complete, latestResult.apiCall.status == .complete else {
|
| 938 | 939 |
let status = firstImpairedStatus(in: apiCalls) |
@@ -343,14 +343,21 @@ struct DashboardView: View {
|
||
| 343 | 343 |
lines.append("Retry of: \(retryOfSnapshotID.uuidString)")
|
| 344 | 344 |
} |
| 345 | 345 |
lines.append("")
|
| 346 |
- lines.append("INTERPRETATION_HINTS")
|
|
| 347 |
- lines.append("Partial snapshot: \(isPartialSnapshot ? "true" : "false")")
|
|
| 348 |
- lines.append("Requires user resolution: \(requiresResolution ? "true" : "false")")
|
|
| 349 |
- lines.append("Failed metrics are excluded from checksum/change analysis")
|
|
| 350 |
- lines.append("Do not infer deletion from partial snapshots")
|
|
| 351 |
- lines.append("All-values-missing metrics require review before saving")
|
|
| 352 |
- lines.append("Timeout means HealthProbe cancelled after configured timeout, not necessarily HealthKit denial")
|
|
| 346 |
+ lines.append("DIAGNOSTIC NOTES")
|
|
| 353 | 347 |
lines.append("Per-metric timing sums are cumulative work and can exceed wall-clock duration because type fetches overlap")
|
| 348 |
+ lines.append("Fetch/processing/insert/finalize fields are measured for import performance comparison")
|
|
| 349 |
+ if isPartialSnapshot {
|
|
| 350 |
+ lines.append("Partial snapshot: true")
|
|
| 351 |
+ lines.append("Failed metrics are excluded from checksum/change analysis")
|
|
| 352 |
+ lines.append("Do not infer deletion from partial snapshots")
|
|
| 353 |
+ } |
|
| 354 |
+ if requiresResolution {
|
|
| 355 |
+ lines.append("Requires user resolution: true")
|
|
| 356 |
+ lines.append("All-values-missing metrics require review before saving")
|
|
| 357 |
+ } |
|
| 358 |
+ if progress.types.contains(where: { $0.apiCallDetails.contains(where: { $0.status == .timeout }) }) {
|
|
| 359 |
+ lines.append("Timeout means HealthProbe cancelled after configured timeout, not necessarily HealthKit denial")
|
|
| 360 |
+ } |
|
| 354 | 361 |
lines.append("")
|
| 355 | 362 |
lines.append("CONFIGURATION")
|
| 356 | 363 |
lines.append("adaptiveTimeoutsEnabled: \(progress.adaptiveTimeoutsEnabled ? "true" : "false")")
|
@@ -393,7 +400,7 @@ struct DashboardView: View {
|
||
| 393 | 400 |
} |
| 394 | 401 |
|
| 395 | 402 |
lines.append("")
|
| 396 |
- lines.append("HEALTHKIT API RESULTS")
|
|
| 403 |
+ lines.append("IMPORT PERFORMANCE BY METRIC")
|
|
| 397 | 404 |
let orderedTypes = progress.types.sorted(by: { $0.displayName < $1.displayName })
|
| 398 | 405 |
let degradedIDs = Set(degraded.map(\.id)) |
| 399 | 406 |
let reportTypes: [SnapshotFetchProgress.TypeProgress] |