Chromium Histogram的使用

阿凡达2018-07-27 09:23

简介

Histogram是base库的统计功能,用于方便、高效地址代码里面插入一些统计打点。统计结果既可以由程序自发地在VLOG打开的情况下打印出来,也可以自己决定要输出哪些统计项目。
统计结果主要包含了统计个数、总和、每个打点的落点分布,这些信息可以用多种方式展示,例如ASCII文本、HTML、JSON。
文本方式的输出结果可以打开chrome,输入 chrome://histograms/ 看到。

准备

要用这个功能很简单,只需要在模块代码的入口处加上 base::StatisticsRecorder::Initialize(); 即可。如果需要让程序退出时能够自动打印出统计结果,则这行代码需要放在日志的初始化以后,以便统计模块初始化时能够正确判断出VLOG有没有打开,从而把程序退出时写日志的函数注册到AtExitManager里。

用法

用的地方更加简单,包含头文件base/metrics/histogram_macros.h,这个文件wrap了供外部使用的常用统计宏,如果不够,可以在自己的代码里再类似地加个这样的文件。

在这些宏定义里,STATIC_HISTOGRAM_POINTER_BLOCK是最终的实现,不需要直接使用。由它衍生而来的有2类:LOCAL 开头和 UMA 开头的定义,区别在于 LOCAL_ 开头的定义中,flag是统一设成kNoFlags,而UMA是一种可以把统计信息通过IPC消息实时地发送给UMA HOST的机制,它的实现类似于MFC的消息处理,以下是一段示例:

int32_t PepperFlashBrowserHost::OnResourceMessageReceived(
    const IPC::Message& msg,
    ppapi::host::HostMessageContext* context) {
  PPAPI_BEGIN_MESSAGE_MAP(PepperFlashBrowserHost, msg)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_UpdateActivity,
                                        OnUpdateActivity)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetLocalTimeZoneOffset,
                                      OnGetLocalTimeZoneOffset)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
        PpapiHostMsg_Flash_GetLocalDataRestrictions, OnGetLocalDataRestrictions)
  PPAPI_END_MESSAGE_MAP()
  return PP_ERROR_FAILED;
}

由于还没有场景要用到,没有细看。

LOCAL_系列的宏定义常用的有如下几种:LOCAL_HISTOGRAM_CUSTOM_COUNTSLOCAL_HISTOGRAM_CUSTOM_TIMES (以及衍生出来的几个) 、LOCAL_HISTOGRAM_BOOLEANLOCAL_HISTOGRAM_ENUMERATION等,以 LOCAL_HISTOGRAM_CUSTOM_COUNTS 为例来说明,它的定义如下:

#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
        base::Histogram::FactoryGet(name, min, max, bucket_count, \
                                    base::HistogramBase::kNoFlags))
  • name 统计项的名称,字符串。
  • sample 样本值,在这里是一个整数,理应介于min max之间。
  • min 统计的最小值
  • max 统计的最大值
  • bucket_count 桶的数量。例如min=1,max=100,bucket_count=5 的情况,则1--100将会被分割为5个桶,每个桶都是一个区间。每个样本在Add的时候,会由一个算法决定落入哪个桶里。这样最终在展示的时候,就能看出来所有样本的分布了。

最后是一个简单用法示例:

LOCAL_HISTOGRAM_BOOLEAN("X509CertificateReuseCount", true);

输出

以chrome里的时间类型的统计项为例说明如何读它的输出结果( 在代码里可以用base::StatisticsRecorder::StatisticsRecorder::WriteGraph("item_name")来得到 ):

Histogram: DiskCache.2.TotalIOTime recorded 29 samples, mean = 5.3 (flags = 0x1)
0   ------------------------------------------------------------------------O (20 = 69.0%)
1   ... 
8   --O                                                                       (1 = 3.4%) {69.0%}
10  --O                                                                       (1 = 3.4%) {72.4%}
12  ----O                                                                     (2 = 6.9%) {75.9%}
14  -O                                                                        (1 = 3.4%) {82.8%}
17  ----O                                                                     (3 = 10.3%) {86.2%}
20  ... 
40  -O                                                                        (1 = 3.4%) {96.6%}
48  ...

这里表示一共有29个样本,平均值5.3,其中有20个样本落在了0--1的区间,2个值为12的样本,占比6.9%,此时之前的样本累计占比75.9%.

拓展:应用场景

性能监测

例如监测每个任务执行以后的内存占用情况:
LOCAL_HISTOGRAM_MEMORY_KB(name, sample)

// For measuring memory usage after each task. Behind a command line flag.
class MemoryObserver : public base::MessageLoop::TaskObserver {
...
  void DidProcessTask(const base::PendingTask& pending_task) override {
    LOCAL_HISTOGRAM_MEMORY_KB("Memory.RendererUsed", GetMemoryUsageKB());
  }
...
};

统计耗时

对于网络、数据库等情况, VS的分析工具并不能或不能精确地分析耗时,例如mail_operation里的网络请求。
用到的宏:LOCAL_HISTOGRAM_TIMES(name, sample)

阈值设定

例如探测字符集的情况,可以直接用ICU获得所有可能的字符集,也可以先快速地先对我们优先考虑的字符集探测一遍(顺序为UTF-8 --> GBK --> BIG5 ),如果失败再用ICU。 这种方法对小字符串的探测性能和准确度提升明显,通过统计,使用这个函数判断的95%以上都是256字节以内,因此取阈值256.

用到的宏:LOCAL_HISTOGRAM_COUNTS_10000(name, sample)

Histogram: SmartConvertString_Size recorded 939 samples, average = 58.3
0     O                                                                         (0 = 0.0%)
1     ------------------------------O                                           (41 = 4.4%) {0.0%}
2     --------------------------------------------------O                       (69 = 7.3%) {4.4%}
3     ---------------------------------------------------------O                (78 = 8.3%) {11.7%}
4     ------------------------------------------------------------------------O (99 = 10.5%) {20.0%}
5     --------O                                                                 (11 = 1.2%) {30.6%}
6     ------------O                                                             (16 = 1.7%) {31.7%}
7     --O                                                                       (3 = 0.3%) {33.4%}
8     -------O                                                                  (20 = 2.1%) {33.8%}
10    -----O                                                                    (14 = 1.5%) {35.9%}
12    ---------------O                                                          (41 = 4.4%) {37.4%}
14    -------------O                                                            (52 = 5.5%) {41.7%}
17    ------O                                                                   (26 = 2.8%) {47.3%}
20    ----------O                                                               (56 = 6.0%) {50.1%}
24    ----------O                                                               (66 = 7.0%) {56.0%}
29    ------------O                                                             (80 = 8.5%) {63.0%}
34    --O                                                                       (14 = 1.5%) {71.6%}
40    ------O                                                                   (41 = 4.4%) {73.1%}
48    O                                                                         (3 = 0.3%) {77.4%}
57    -O                                                                        (6 = 0.6%) {77.7%}
68    ----O                                                                     (28 = 3.0%) {78.4%}
81    O                                                                         (0 = 0.0%) {81.4%}
96    --------O                                                                 (54 = 5.8%) {81.4%}
114   ---O                                                                      (23 = 2.4%) {87.1%}
135   O                                                                         (0 = 0.0%) {89.6%}
160   -------O                                                                  (50 = 5.3%) {89.6%}
190   O                                                                         (0 = 0.0%) {94.9%}
226   O                                                                         (3 = 0.3%) {94.9%}
268   -O                                                                        (5 = 0.5%) {95.2%}
318   ---O                                                                      (20 = 2.1%) {95.7%}
378   -O                                                                        (8 = 0.9%) {97.9%}
449   ... 
633   -O                                                                        (7 = 0.7%) {98.7%}
752   O                                                                         (0 = 0.0%) {99.5%}
894   O                                                                         (1 = 0.1%) {99.5%}
1062  O                                                                         (1 = 0.1%) {99.6%}
1262  O                                                                         (0 = 0.0%) {99.7%}
1500  O                                                                         (3 = 0.3%) {99.7%}
1782  ...

失败率/出错率

例如字符串的编码自动判断的成功和失败的个数 / 收发信频繁出现网络错误 / 日历同步失败率

用到的宏:LOCAL_HISTOGRAM_BOOLEAN

普通的打点

例如用户习惯统计(例如邮箱大师从哪里启动,发送邮件时是用快捷键还是点按钮,输入邮箱帐号时输了多少字才利用了我们的自动完成功能等)

用到的宏:LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value)

本文来自网易实践者社区,经作者郁利涛授权发布。