美文网首页iOS
iOS MetricsKit 收集电量和性能数据

iOS MetricsKit 收集电量和性能数据

作者: V_coa | 来源:发表于2020-02-10 17:33 被阅读0次

    App 的耗电量和性能是用户体验的重要部分,在 iOS 13 中推出了MetricKit,它用于收集和处理电池和性能指标。Improving Battery Life and Performance 中提出了三个用于不同阶段的工具进行电量和性能数据的收集,便于发现各个阶段出现的电量和性能问题。

    • XCTest Metrics (开发和测试阶段)
      • 可以使用 blocks 测试性能
    • MetricsKit (Beta 和 Public Release 阶段)
      • 用于收集电量和性能数据
    • Xcode Metrics Organizer (Public Release 阶段)
      • Xcode 中汇总了,电池,性能和 I/O 的指标

    重要的两个分类指标

    • Battery
    • Performance

    耗电的体现在下面这几种情况:

    • Processing (CPU 和 GPU 耗时时间)
    • Location (累计使用时长和后台使用时长)
    • Display (平均像素亮度)
    • Networking (上传和下载字节,连接性)
    • Accessories(外围设备:蓝牙等)
    • Multimedia(多媒体)
    • Camera(相机)

    性能的体现在下面这几种情况:

    • Hangs (主线程卡顿)
    • Disk (I/O)
    • Application Launch (启动时间)
    • Memory (内存)

    开发和测试阶段

    可以通过下方代码来测试一些操作的指标

    - (void)testReSizeImagePerformance {
        __auto_type app = [XCUIApplication new];
        [self
            measureWithMetrics:@[
                XCTMemoryMetric.new,
                XCTClockMetric.new,
                XCTCPUMetric.new
            ]
            block:^{
                [app.buttons[@"reSize"] tap];
            }];
    }
    

    启动时间

    - (void)testLaunchPerformance {
        if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
            [self measureWithMetrics:@[XCTOSSignpostMetric.applicationLaunchMetric] block:^{
                [[[XCUIApplication alloc] init] launch];
            }];
        }
    }
    

    MetricsKit

    #import "AppMetricManagerSubscriber.h"
    @import MetricKit;
    
    @interface AppMetricManagerSubscriber()
    <
    MXMetricManagerSubscriber
    >
    
    @end
    
    @implementation AppMetricManagerSubscriber
    
    - (instancetype)init {
        self = [super init];
        if (!self) { return nil; }
        // 1.添加订阅
        [MXMetricManager.sharedManager addSubscriber:self];
        return self;
    }
    
    // 2.实现指标数据回调
    - (void)didReceiveMetricPayloads:(NSArray<MXMetricPayload *> *)payloads {
        [payloads enumerateObjectsUsingBlock:^(MXMetricPayload * _Nonnull payload, NSUInteger idx, BOOL * _Nonnull stop) {
            NSLog(@"%@", payload.DictionaryRepresentation);
        }];
    }
    
    - (void)dealloc {
        // 3.移除订阅
        [MXMetricManager.sharedManager removeSubscriber:self];
    }
    
    @end
    

    回调时机是,当 App 累计运行了 24 小时 就进行回调

    回调数据格式

    {
        appVersion = "1.0";
        applicationLaunchMetrics =     {
            histogrammedResumeTime =         {
                histogramNumBuckets = 3;
                histogramValue =             {
                    0 =                 {
                        bucketCount = 60;
                        bucketEnd = "210 ms";
                        bucketStart = "200 ms";
                    };
                    1 =                 {
                        bucketCount = 70;
                        bucketEnd = "310 ms";
                        bucketStart = "300 ms";
                    };
                    2 =                 {
                        bucketCount = 80;
                        bucketEnd = "510 ms";
                        bucketStart = "500 ms";
                    };
                };
            };
            histogrammedTimeToFirstDrawKey =         {
                histogramNumBuckets = 3;
                histogramValue =             {
                    0 =                 {
                        bucketCount = 50;
                        bucketEnd = "1,010 ms";
                        bucketStart = "1,000 ms";
                    };
                    1 =                 {
                        bucketCount = 60;
                        bucketEnd = "2,010 ms";
                        bucketStart = "2,000 ms";
                    };
                    2 =                 {
                        bucketCount = 30;
                        bucketEnd = "3,010 ms";
                        bucketStart = "3,000 ms";
                    };
                };
            };
        };
        applicationResponsivenessMetrics =     {
            histogrammedAppHangTime =         {
                histogramNumBuckets = 3;
                histogramValue =             {
                    0 =                 {
                        bucketCount = 50;
                        bucketEnd = "100 ms";
                        bucketStart = "0 ms";
                    };
                    1 =                 {
                        bucketCount = 60;
                        bucketEnd = "400 ms";
                        bucketStart = "100 ms";
                    };
                    2 =                 {
                        bucketCount = 30;
                        bucketEnd = "700 ms";
                        bucketStart = "400 ms";
                    };
                };
            };
        };
        applicationTimeMetrics =     {
            cumulativeBackgroundAudioTime = "30 sec";
            cumulativeBackgroundLocationTime = "30 sec";
            cumulativeBackgroundTime = "40 sec";
            cumulativeForegroundTime = "700 sec";
        };
        cellularConditionMetrics =     {
            cellConditionTime =         {
                histogramNumBuckets = 3;
                histogramValue =             {
                    0 =                 {
                        bucketCount = 20;
                        bucketEnd = "1 bars";
                        bucketStart = "1 bars";
                    };
                    1 =                 {
                        bucketCount = 30;
                        bucketEnd = "2 bars";
                        bucketStart = "2 bars";
                    };
                    2 =                 {
                        bucketCount = 50;
                        bucketEnd = "3 bars";
                        bucketStart = "3 bars";
                    };
                };
            };
        };
        cpuMetrics =     {
            cumulativeCPUTime = "100 sec";
        };
        diskIOMetrics =     {
            cumulativeLogicalWrites = "1,300 kB";
        };
        displayMetrics =     {
            averagePixelLuminance =         {
                averageValue = "50 apl";
                sampleCount = 500;
                standardDeviation = 0;
            };
        };
        gpuMetrics =     {
            cumulativeGPUTime = "20 sec";
        };
        locationActivityMetrics =     {
            cumulativeBestAccuracyForNavigationTime = "20 sec";
            cumulativeBestAccuracyTime = "30 sec";
            cumulativeHundredMetersAccuracyTime = "30 sec";
            cumulativeKilometerAccuracyTime = "20 sec";
            cumulativeNearestTenMetersAccuracyTime = "30 sec";
            cumulativeThreeKilometersAccuracyTime = "20 sec";
        };
        memoryMetrics =     {
            averageSuspendedMemory =         {
                averageValue = "100,000 kB";
                sampleCount = 500;
                standardDeviation = 0;
            };
            peakMemoryUsage = "200,000 kB";
        };
        metaData =     {
            appBuildVersion = 1;
            deviceType = "iPhone11,8";
            osVersion = "iPhone OS 13.3 (17C54)";
            regionFormat = CN;
        };
        networkTransferMetrics =     {
            cumulativeCellularDownload = "80,000 kB";
            cumulativeCellularUpload = "70,000 kB";
            cumulativeWifiDownload = "60,000 kB";
            cumulativeWifiUpload = "50,000 kB";
        };
        signpostMetrics =     (
                    {
                signpostCategory = TestSignpostCategory1;
                signpostIntervalData =             {
                    histogrammedSignpostDurations =                 {
                        histogramNumBuckets = 3;
                        histogramValue =                     {
                            0 =                         {
                                bucketCount = 50;
                                bucketEnd = "100 ms";
                                bucketStart = "0 ms";
                            };
                            1 =                         {
                                bucketCount = 60;
                                bucketEnd = "400 ms";
                                bucketStart = "100 ms";
                            };
                            2 =                         {
                                bucketCount = 30;
                                bucketEnd = "700 ms";
                                bucketStart = "400 ms";
                            };
                        };
                    };
                    signpostAverageMemory = "100,000 kB";
                    signpostCumulativeCPUTime = "30,000 ms";
                    signpostCumulativeLogicalWrites = "600 kB";
                };
                signpostName = TestSignpostName1;
                totalSignpostCount = 30;
            },
                    {
                signpostCategory = TestSignpostCategory2;
                signpostIntervalData =             {
                    histogrammedSignpostDurations =                 {
                        histogramNumBuckets = 3;
                        histogramValue =                     {
                            0 =                         {
                                bucketCount = 60;
                                bucketEnd = "200 ms";
                                bucketStart = "0 ms";
                            };
                            1 =                         {
                                bucketCount = 70;
                                bucketEnd = "300 ms";
                                bucketStart = "201 ms";
                            };
                            2 =                         {
                                bucketCount = 80;
                                bucketEnd = "500 ms";
                                bucketStart = "301 ms";
                            };
                        };
                    };
                    signpostAverageMemory = "60,000 kB";
                    signpostCumulativeCPUTime = "50,000 ms";
                    signpostCumulativeLogicalWrites = "700 kB";
                };
                signpostName = TestSignpostName2;
                totalSignpostCount = 40;
            }
        );
        timeStampBegin = "2020-02-08 16:00:00 +0000";
        timeStampEnd = "2020-02-09 15:59:00 +0000";
    }
    

    自定义打点, 收集某个范围内的指标数据

    __auto_type reSizeLog = [MXMetricManager makeLogHandleWithCategory:@"Image"];
    os_signpost_id_t signpost_id = os_signpost_id_generate(reSizeLog);
    MXSignpostIntervalBegin(reSizeLog, signpost_id, "reSizeImage");
    [self reSizeImage];
    MXSignpostIntervalEnd(reSizeLog, signpost_id, "reSizeImage");
    

    Xcode Metrics Organizer

    什么是 Xcode Metrics Organizer?

    • 开箱即用的电量和性能分析工具
    • 无须改动 App
    • 数据收集满足用户隐私

    Xcode Metrics Organizer 如何运作

    当使用 App 时候,iOS 会记录各项指标,然后发送到苹果服务端上,并自动生成相关的可视化报告。

    可以通过 Window -> Organizer -> Metrics 查看,可以查看各项指标,并且和历史版本进行对比。

    • 内存提供了峰值和平均内存
    • 电量有前后台占用情况,CPU 、定位和网络的比重等。
    • 历史版本启动耗时
    • 主线程卡顿情况
    • 写磁盘数据量

    相关文章

      网友评论

        本文标题:iOS MetricsKit 收集电量和性能数据

        本文链接:https://www.haomeiwen.com/subject/erxzxhtx.html