注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

永恒的遗失古都-亚特兰蒂斯

一个游戏开发者的个人博客。

 
 
 

日志

 
 

跟踪分析工具-TraceViewer  

2016-01-08 19:38:47|  分类: 程序相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Trace Event System
介绍
    Trace-Viewer是一个为Chrome开发的JavaScript数据分析工具:它能够进行Android systrace的数据分析。
    它提供了多种类型的Trace跟踪文件支持,并提供了丰富的分析和可视化功能,在查看Linux内核Trace(又称为ftrace)以及Chrome的trace_event格式时数据更为方便。但是它本身不提供数据采集功能,如果你需要进行数据采集,则你需要在自己的代码中添加指定采集代码,或者使用第三方软件来进行Trace跟踪。
    它可以很方便的将你采集到的数据转换为HTML文件,直观的界面将便于你进行对复杂数据进行分析。
使用TraceViewer
  1. 下载TraceViewer。因为现在它被整合到catapult项目中,所以请从这里下载:https://github.com/catapult-project/catapult
  2. 去官网下载Python2.7。(FK注:我当前下载版本为2.7.11,)
  3. 设置Python路径,系统路径例如: Path -> D:\Python27,之后用 cmd命令"python -V"查看版本。(注意:V要大写)
  4. 进入catapult文件下内catapult-master\tracing\bin,修改trace2html和vulcanize_trace_viewer两个文件后缀为.py
  5. cmd进入bin目录下,执行 vulcanize_trace_viewer.py
  6. 将采集到的Trace信息(json格式文本)拷贝到bin目录下,执行命令 trace2html.py your_trace_file.json --output=your_trace_file.html
  7. 等待转换完毕,即可得到html格式文件。使用Chrome打开即可。

Trace Event Format
介绍
    Trace Event Format是一种跟踪数据格式。任何一个使用TraceViewer的应用程序都很容易生成该格式。
    TraceViewer源代码链接:https://github.com/catapult-project/catapult
    它包括以下四种格式:
    2个JSON格式:
  •         JSON object对象格式
  •         JSON数组的字符串dump
    2个Linux ftrace格式:
  •         以 # tracer: 开头的dump文本文件
  •         Android systrace HTML dump文件。
本文档介绍了JSON格式,并提供了在Linux ftrace功能的部分信息链接。

JSON数组格式
  1.     通过TraceViewer最简单的格式就是JSON数组格式,一个事件对象的数组。
  2.     这些事件无需根据时间戳进行排序。
    例子如下:
    [ {"name": "Asub", "cat": "PERF", "ph": "B", "pid": 22630, "tid": 22630, "ts": 829},
  {"name": "Asub", "cat": "PERF", "ph": "E", "pid": 22630, "tid": 22630, "ts": 833} ]
    JSON数组格式尾部的 ]  中括号是可选的。TraceViewer在将一个字符串转换为有效的JSON格式时会自动智能添加尾部的 ] 中括号。这样处理的好处是,即使Trace没能完整完成写入操作,该文件依然是有效的。例如,如果我们在一个项目进程结束时写Trace的话,很可能Trace写入被中断。
JSON对象格式
  1.     使用JSON对象格式可以在TraceViewer看到更多的跟踪信息。
  2.     它有一个必要的属性TraceEvents,以及一些其他的可选属性。
  3.     这些事件无需按照时间戳排序。  
    例子如下:
{
  "traceEvents": [
    {"name": "Asub", "cat": "PERF", "ph": "B", "pid": 22630, "tid": 22630, "ts": 829},
    {"name": "Asub", "cat": "PERF", "ph": "E", "pid": 22630, "tid": 22630, "ts": 833}
  ],
  "displayTimeUnit": "ns",
  "systemTraceEvents": "SystemTraceData",
  "otherData": {
    "version": "My Application v1.0"
  },
  "stackFrames": {...}
  "samples": [...],
}
    如果提供的 systemTraceEvents 是一个Linux的ftrace数据或者Windows的ETW跟踪数据字符串。则该字符必须以 # tracer: 为首字符串,其后添加Linux ftrace格式或者Windows的ETW格式。
    displayTimeUnit 是一个可选项,它是一个字符串,该字符串必须是"ms"或者"ns",它表示时间戳的精度,默认为"ms"毫秒。
    battorLogAsString 是一个可选项,它是 BattOr 数据字符串。
    stackFrames 是一个可选项,它是帧堆栈的词典,内部数据包括帧堆栈的ID,父子关系等。
    samples 数组用来存储一些从操作系统OS级别采样获取的数据。
    
事件描述格式
    下面是一个典型的事件例子:
    {
  "name": "myName",
  "cat": "category,list",
  "ph": "B",
  "ts": 12345,
  "pid": 123,
  "tid": 456,
  "args": {
    "someArg": 1,
    "anotherArg": {
      "value": "my value"
    }
  }
}
name:  该事件的名称,它将在TraceViewer中显示
cat: 事件的标签。它是一个以逗号分隔的事件标签列表,在TraceViewer中可以进行分类隐藏和显示。
ph: 事件的类型。它是一个单字符,用以确认事件输出的方式。下面有一个列表详细定义了当前支持的事件类型。
ts: 事件的时间戳。
tts: 可选项。本事件在线程中的时间戳。
pid: 输出本事件的进程ID。
tid: 输出本事件的线程ID。
args: 提供事件的任何参数。这里你可以存放自己定义的任何数据,该数据在TraceViewer中可以查看。
cname: 可选项。它指定了本事件在TraceViewer中的颜色显示。

下面是ph事件类型定义
事件类型
ph标示
持续事件
B (标示开始) E (标示结束)
完成事件
X
瞬时事件
i
计数事件
C
异步事件
b (嵌套开始) n (嵌套的一瞬间)  e (嵌套完成)
流式事件
s (开始) t (执行了一步) f(结束)
采样事件
P
对象事件
N (创建) O (对象快照) D (对象销毁)
元数据事件
M
内存dump事件
V (全局内存) v (线程内存)
标志事件
R
时钟同步事件
c

持续事件
  •     持续事件为一个线程中的持续性工作提供了跟踪方法,很适合进行函数调用堆栈的分析。
  •     它通过 B 和 E 事件指定。
  •     B事件必须在对应的E事件之前。
  •     事件可以嵌套。
  •     通过持续事件,你可以很方便的获得一个线程中函数的调用层级关系。
  •     E事件中,仅需要pid,tid, ph和ts属性即可。
    •         如果E事件和B事件中都有 args 属性且两者属性不同,那么这两个事件的 args 属性将被合并。
    •         如果E事件中有 args 属性且和B事件重复,则B事件中的args属性数据将被覆盖抛弃。

   例1
{"name": "myFunction", "cat": "foo", "ph": "B", "ts": 123, "pid": 2343, "tid": 2347,
 "args": {
   "first": 1
 }
},
{"ph": "E", "ts": 145, "pid": 2343, "tid": 2347,
 "args": {
   "first": 4,
   "second": 2
 }
}
    上面例子中,我们将创建一个TraceViewer中的一个事件片段。该事件名称为 myFunction,它属于 foo 类事件。该事件从 123毫秒时开始,持续执行了22毫秒。该事件在进程2343,线程2347中被执行。该事件由两个参数,第一个参数为4,第二个参数为2.
    例2
[
{ "cat": "foo", "pid": 2343, "ts": 1.0, "tid": 1, "ph": "B", "name": "A"},
{ "cat": "foo", "pid": 2343, "ts": 1.1, "tid": 1, "ph": "B", "name": "Asub"},
{ "cat": "foo", "pid": 2343, "ts": 3.9, "tid": 1, "ph": "E"},
{ "cat": "foo", "pid": 2343, "ts": 4.0, "tid": 1, "ph": "E"}
]
跟踪分析工具-TraceViewer - 自由骑士笃志 - 永恒的遗失古都-亚特兰蒂斯
 
    上面例子中,我们有两个事件片段。一个是函数A执行事件,一个是函数Asub执行事件。TraceViewer中进行绘制图表时,会发现 A 中嵌套了Asub函数,属于函数调用。所以它会认为A持续执行了3.0毫秒,而Asub函数持续执行了2.8毫秒。
    例3
[
  { "cat": "foo", "pid": 2343, "ts": 1.0, "tid": 1, "ph": "B", "name": "A"},
  { "cat": "foo", "pid": 2343, "ts": 0.9, "tid": 2, "ph": "B", "name": "B"},
  { "cat": "foo", "pid": 2343, "ts": 1.1, "tid": 1, "ph": "E"},
  { "cat": "foo", "pid": 2343, "ts": 4.0, "tid": 2, "ph": "E"}
]
    上面例子中,虽然B事件和E事件不是嵌套关系,但TraceViewer依然可以顺利采集分析,因为两个事件在不同的线程中,而单个线程内,函数还是正常执行的。
    虽然持续事件可以很方便的进行跟踪函数调用流程,但是强制要求B事件和E事件要在正常嵌套。所以,如果上面例子中的事件在同一个线程的话,则会出现错误。如果你的确需要不能嵌套的事件关系的话,请使用异步事件来代替持续事件。

使用延时事件进行堆栈跟踪:【TODO】
    首先,你可以使用 sf 属性来指定一个stackFrame对象的ID。
    例:
{
  traceEvents: [
    { ..., "ph": "B", "name": "A", "sf": 7},
    { ..., "ph": "E", "name": "A", "sf": 9}
  ],
  stackFrames: {
    "5": { name: "main", category: "my app" },
    "7": { parent: "5", name: "SomeFunction", category: "my app" },
    "9": { parent: "5", name: "SomeFunction", category: "my app" }
  }
}

完成事件
  •     完成事件逻辑上整合了一组延迟事件,类似于“B事件+E事件”。因为大部分事件都是延迟事件,所以使用完成事件的话,将可以大幅度降低事件个数,从而降低数据大小(大约可以减少一半)。
  •     完成事件其他参数和持续事件基本一致,但有一个额外参数 dur 用来表示本事件持续的时间。
  •     完成事件还有一个可选的额外参数 tidur 用以指定在指定线程中本事件持续的时间。
    例:
[{"name": "myFunction", "cat": "foo", "ph": "X", "ts": 123, "dur": 234, "pid": 2343, "tid": 2347,
 "args": {
   "first": 1
 }
 }]
    完成事件也可以被调用堆栈跟踪,对于 sf 属性,stack属性的支持,也完全类似于延时事件。

瞬时事件
  •     瞬时事件表示那些瞬间发生的事件,它们没有持续执行。它的标示为 i 。
  •     瞬时事件有一些额外参数,s 属性标示本事件发生的范围。其值由四种:g 表示全局,p 表示京城, t 表示线程,无参数则表示它默认为线程事件。这些范围将影响TraceViewer图表绘制。若是一个线程中的瞬时事件,则在图表中仅在该线程中绘制;若是一个进程级事件,则在图表中会在进程的所有线程中绘制;若是一个全局事件,则会在全部进程和线程中绘制该事件。
{"name": "OutOfMemory", "ph": "i", "ts": 1234523.3, "pid": 2343, "tid": 2347, "s": "g"}
    瞬时事件也可以被调用堆栈跟踪,对于 sf  属性,stack属性的支持,也完全类似于延时事件。

计数事件
  •     计数事件可以跟踪一个或者多个数据的更变。
  •     当数据为多个时,每个计数器事件可以在TraceViewer中以一个堆积图的方式显示多个数据状况。
    例1:
[
{ "pid": 22630, "tid": 22630, "name": "ctr", "ph": "C", "ts":  0, "args": {"cats":  0}},
{ "pid": 22630, "tid": 22630, "name": "ctr", "ph": "C", "ts": 10, "args": {"cats": 10}},
{ "pid": 22630, "tid": 22630, "name": "ctr", "ph": "C", "ts": 20, "args": {"cats":  0}}
]
    在上例中,一个叫 ctr 的计数器跟踪着一个叫 cats 的数据。该数据在20毫秒内值从0更变为10又回到了0.
    例2:
[
{"pid": 22630, "tid": 22630, "name": "ctr", "ph": "C", "ts":  0, "args": {"cats":  0, "dogs": 7}},
{"pid": 22630, "tid": 22630, "name": "ctr", "ph": "C", "ts": 10, "args": {"cats": 10, "dogs": 4}},
{"pid": 22630, "tid": 22630, "name": "ctr", "ph": "C", "ts": 20, "args": {"cats":  0, "dogs": 1}}
]
跟踪分析工具-TraceViewer - 自由骑士笃志 - 永恒的遗失古都-亚特兰蒂斯
 
    在上例中,一个叫 ctr 的计数器跟踪着两组数据;在TraceViewer显示时,这两组数据将在一个堆积图中分布显示。

异步事件
  •     异步事件主要用于异步操作跟踪,例如在游戏帧,网络I/O等部分。
  •     异步事件由三种事件类型,b, n, e,分别代表 起始事件,瞬时事件和结束事件。
  •     你可以在不同线程不同进程中提交异步事件。
  •     每个异步事件必须提交一个 id 参数。我们根据 cat 事件标签和 id  事件ID来确定哪些事件属于同一个事件树。
    
    举例来说,如果我们有一个事件A,以及一个其子事件B。TraceViewer将根据他们相同的  cat 事件标签以及相同的 id,推断出其父子关系。所以在图表中,A的起始结束将会包含B的全部持续时间,A将作为B的父事件显示在图表顶端(并以黑色边框包围),而B将在A下面一行进行显示。
    例1:
{"cat": "foo", "name": "async_read", "id": 0x100, "ph": "b", "args": {"name" : "~/.bashrc"}},
{"cat": "foo", "name": "async_read", "id": 0x100, "ph": "e"}
    异步事件也是允许嵌套的,它还可以嵌套其他的异步事件。例如,你可能开始从服务器加载一个文件头;过了一会儿,再从服务器接收一个文件体。嵌套的异步事件应该和其父事件具有相同的 cat 和 id 。
    例2:
{"cat": "foo", "name": "url_request", "ph": "b", "ts": "0", "id": 0x100},
{"cat": "foo", "name": "url_headers", "ph": "b", "ts": "1", "id": 0x100},
{"cat": "foo", "name": "http_cache", "ph": "n", "ts": "3", "id": 0x100},
{"cat": "foo", "name": "url_headers", "ph": "e", "ts": "2", "id": 0x100,
 "args": {
   "step": "headers_complete"
   "response_code": 200,
 }
},
{"cat": "foo", "name": "url_request", "ph": "e", "ts": "4", "id": 0x100}
    上面这个例子,在TraceViewer的UI界面中该事件将显示出一个大的彩色UI条,该UI条从 request 的 b 事件持续到 request 的 e 事件。然后在其下方,有第二个小一些的彩色UI条,该UI条从 headers 的 b 事件持续到 headers 的 e 事件。然后在最下方,会有第三个更细的UI条表示其中的 n 缓存事件。
    TraceViewer会根据事件的 cat 和 id 构建事件树,并且通过 ts 时间戳分布其长度。如果 b 事件和 e 事件不成对匹配,则会在用户点击该UI条时抛出一个警告。
    
流式事件
    流式事件和异步事件很像。但是流式事件允许在持续时间内跨线程。
    在TraceViewer中图表显示时,可以想象流式事件是两个持续事件条外加一个中间的连接箭头。
    多个流式事件单元将会以箭头和线条连接在一起。

    流式事件由 s, t, f 阶段组成。这几个阶段和异步事件的 b, n, e 作用很类似。

采样事件
    采样事件提供了一种在Trace中做采样分析的功能。
    在TraceViewer图表中,他们有自己单独的一行。
    采样事件看起来很类似于瞬时事件,他们的持续时间为0。
    在TraceViewer图表中,每个事件表示是一条细线。
    如果我们有一个功能被频繁调用,我们不希望发出成千上万个事件,但是我们又希望这个函数被调用了多少次,那么此时请使用采样事件。
    采样事件也可以被调用堆栈跟踪,对于 sf  属性,stack 属性的支持和使用方式类似持续事件。
    例:
    {"name": "sample", "cat": "foo", "ph": "P", "ts": 123, "pid": 234, "tid": 645 }

对象事件
    对象事件是用来跟踪复杂的数据结构状态的事件。
    因为Trace是基于时间轴线的,所以对象事件可以进行数据结构随着时间发生变化。
    要确定一个对象,你需要给它一个ID,这个ID通常是对象的指针,例如:ID: "0xd4b2"。但是,如果进行长时间的Trace,一个指针值可能在不同时间时指向的是不同的对象,这点需要参见例2,使用 local 限制。
    对象事件没有额外的 args  参数属性。
    对象事件可以记录对象实体数据。例如,在C++中,我们有一个Foo类,new Foo()就创建了一个对象实体。
    对象事件有三类 , N, O, D 分别表示,创建对象,对象快照和对象销毁事件。
    例1:
{"name": "MyObject", "ph": "N", "id": "0x1000", "ts": 0, "pid": 1, "tid": 1},
{"name": "MyObject", "ph": "D", "id": "0x1000", "ts": 20, "pid": 1, "tid": 1}
    上面例子说明 MyObject 这个对象,生存周期为20毫秒。
    例2:
[
{"name": "MyObject", "id": "0x1000", "ph": "O", "ts": 10, "pid": 1, "tid": 1,
 "args": {
  "snapshot": {
    "objid" : 12,
    "objname" : "test"
  }
 }
},
{"name": "MyObject", "ph": "N", "id": "0x1000", "ts": 0, "pid": 1, "tid": 1},
{"name": "MyObject", "ph": "D", "id": "0x1000", "ts": 20, "pid": 1, "tid": 1},
{"name": "MyOtherObject", "ph": "N", "id": "0x1000", "ts": 20, "pid": 1, "tid": 1},
{"name": "MyOtherObject", "ph": "D", "id": "0x1000", "ts": 25, "pid": 1, "tid": 1}
]
跟踪分析工具-TraceViewer - 自由骑士笃志 - 永恒的遗失古都-亚特兰蒂斯
 
    有时候我们会像上面一样,虽然20毫秒前的MyObject 和20毫秒后的MyOtherObject两者的 id 相同,但是此时对象已经更变了。
    我们或许会想到一个简单的主意,我们不使用内存地址做ID,但是这样的话,为避免重复,我们还需要一套ID管理分配机制。所以这里我推荐使用 local 限制。当我们设置 local 参数为true时,我们检查对象时,ID不作为唯一标示,其 name 参数也将作为区别标示。
    例3:
{"name": "MyObject", "ph": "N", "id": "0x1000", "local": true, "ts": 0, "pid": 1,  "tid": 1}

对象快照
        在软件流程中,很少有对象能在其生命周期内保持不变,通常他们会随着时间发生变化。对象快照允许你输出对象瞬时的状态。
        例4:
{"name": "MyObject", "id": "0x1000", "ph": "O", "ts": 10, "pid": 1, "tid": 1,
 "args": {
  "snapshot":{ 
    "objid" : 12,
    "objname" : "test"}
 }
}
        快照字段中的省略号可以是你自定义的任何需要的数据。如果你愿意,你甚至可以将整个渲染系统信息全部写入这个快照数据中。
        但是在实际使用的时候,我们通常将不同的对象数据保存在不同命名的对象中。因为这样的话,在TraceViewer中,不同的对象快照将使用不同的颜色,我们更容易分辨malloc堆内存大小和帧率(作者假设这俩数据作为两种不同的对象)。

继承类对象快照
        通常来说,一个对象在创建,快照,销毁时使用的 name 属性是相同的。如下:
{"name": "MyObject", "id": "0x1000", "ph": "N", ...}
{"name": "MyObject", "id": "0x1000", "ph": "O", ...}
{"name": "MyObject", "id": "0x1000", "ph": "D", ...}
        但是,随着类继承的发展,很多时间我们在构造或者析构时并不能准确获取其子类型,那么此时的解决方法如下:
{"name": "MyObject", "id": "0x1000", "ph": "N", ...}
{"name": "MyObjectSubType", "id": "0x1000", "ph": "O", "args": {
  "snapshot": {
    "base_type": "MyObject",
    ... regular args fields as usual…
    }
  }
}
{"name": "MyObject", "id": "0x1000", "ph": "D", ...}

引用对象
        一些情况下,我们的一个对象中有对另一个对象的引用。
        在任何允许有 args 参数的事件中(例如:延时事件,异步事件,对象快照事件等),我们都可以加入引用对象数据如下:{"field": {"id_ref": "0xcdcd"} },其中的 id_ref 的值必须和被引用的对象事件的 id 相同。
        例5:
[
{"name": "MyObject", "id": "0x1000", "ph": "O", "ts": 8, "pid": 1, "tid": 1,
 "args": {
  "snapshot": {
    "objid" : 12,
    "objname" : "test"
  }
 }
},
{"name": "MyObject", "ph": "N", "id": "0x1000", "ts": 0, "pid": 1, "tid": 1},
{"name": "MyObject", "ph": "D", "id": "0x1000", "ts": 20, "pid": 1, "tid": 1},

{"name": "SliceA", "ph": "B", "ts": 10, "pid": 1, "tid": 1,
 "args": {
  "obj": {
   "id_ref": "0x1000"
  }
 }
}
]
元数据事件
  •     元数据事件是用来通知TraceViewer一些事件之外的额外信息的。(例如,进程名称,线程名称等)
  •     元数据事件的参数列表可以为空。
  •     当前提供的元数据项有五种:
  1.     process_name:     设置指定pid的线程名称。其名称由args参数中的 name 字段指定。
  2.     process_labels:    设置指定pid的额外线程标签。该标签由args参数中的 labels 字段指定。
  3.     process_sort_index:     设置进程排序位置。排序位置编号通过args参数中的 sort_index 字段指定。
  4.     thread_name:    设置指定tid的线程名称。该标签由args参数中的 name 字段指定。
  5.     thread_sort_index:    设置线程排序位置。排序位置编号由args参数中的 sort_index 字段指定。
    其中,排序位置值越小,则在TraceViewer中排序越靠上。
    例1:
 {"name": "thread_name", "ph": "M", "pid": 2343, "tid": 2347,
 "args": {
  "name" : "RendererThread"
 }
}
    上面的例子中,我们设置 tid 为2347的线程名为 RenderThread

内存dump事件
    内存Dump事件用来记录进程中的内存信息。有两种内存dump事件:
  •     全局内存dump事件。它包含了系统存储器信息(例如RAM大小),由 V 表示。
  •     线程内存dump事件。它包含了单个进程中的内存使用状况(例如分配的内存),由 v 表示。
    例1:
[
  {"id": "dump_id", "ts": 10, "ph": "V", "args": {"globalMem" : 1023}},
  {"id": "dump_id", "ts": 11, "ph": "v", "pid": 42, "args": {"sound_Mem" : "1024kb", "texture_Mem" : "1023kb"}}
]
跟踪分析工具-TraceViewer - 自由骑士笃志 - 永恒的遗失古都-亚特兰蒂斯
 
标志事件
    标志事件通常是通过 http://www.w3.org/TR/navigation-timing/#sec-navigation-timing 标志生成。
    当然,我们也可以手动对一些用户操作行为进行记录(例如:用户点击事件,搜索完成事件等)。
    它是一种瞬发事件。
    例1:
[
  {"name": "firstLayout", "ts": 10, "ph": "R", "cat": "blink.user_timing",  "pid": 42, "tid": 983}
]
时钟同步事件
    TraceViewer可以通过时钟域来同时处理跟踪多个Trace日志。
    时钟同步消息用以TraceViewer上进行时钟同步。
    请参见下图:
     A----------------t1-----------------t3(sync_id=123 issue_ts:t1)-------------
     B----------------------------t2(sync_id:123)-----------------------
    首先,时钟同步消息要求有一个发送者和一个接收者。发送者A发送一个事件同步消息,要求接收者B发布该消息并返还该消息给A。A在收到消息后,记录该事件并记录其发布时间。
    时钟同步有两个重要的 args 参数:
  •         sync_id: 时钟同步消息的ID
  •         issue_ts: 时钟同步消息发出时的瞬时时间戳
     接收者是不需要 issue_ts 参数的。
    例1:
    接收者:
[
  { "name": "clock_sync", "ph": "c", "ts":  t2,
    "args": {
      "sync_id": 123
    }
  }
]    
    发布者:
[
  { "name": "clock_sync", "ph": "c", "ts": t3,
    "args": {
      "sync_id": 123,
      "issue_ts": t1
    }
  }
]
    例子中,接收者的 ts 为接收者在其线程中接收到事件消息的时间。发布者的 ts 为其接收到事件消息反馈的时间,而 issue_ts 为其发布事件消息的时间。
    注意:t3必然大于等于t1,但t2未必处于t3,t1之间,因为他们线程甚至进程可能是不同的。这是被许可的。

StackFrames 词典
    为了进行高效的调用堆栈跟踪,我们记录了一个map字典。它是一个ID和堆栈帧对象的映射,ID可以是任意的字符串或者整数。这两者都必须提供。
    例1:StackFrames 词典整体格式:
{
  frame_id: { ... stack frame… },
  ... more frames
}
    例2:单Stack帧数据
{
  'category': 'libchrome.so',
  'name': 'CrRendererMain',
  'parent': 1
}
    例3:根Stank帧数据(没有父节点)
{
  'category': 'libc.so',
  'name': '_crtmain',
}
  评论这张
 
阅读(42)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017