blob: 45aaccac7abeed8111ee5c68a2a46e78ecef870c [file] [log] [blame]
Chet Haase9c1e23b2011-03-24 10:51:31 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "DisplayListLogBuffer.h"
18
19// BUFFER_SIZE size must be one more than a multiple of COMMAND_SIZE to ensure
20// that mStart always points at the next command, not just the next item
Chet Haase9c1e23b2011-03-24 10:51:31 -070021#define NUM_COMMANDS 50
Chris Craik2af46352012-11-26 18:30:17 -080022#define BUFFER_SIZE ((NUM_COMMANDS) + 1)
Chet Haase9c1e23b2011-03-24 10:51:31 -070023
24/**
25 * DisplayListLogBuffer is a utility class which logs the most recent display
26 * list operations in a circular buffer. The log is process-wide, because we
27 * only care about the most recent operations, not the operations on a per-window
28 * basis for a given activity. The purpose of the log is to provide more debugging
29 * information in a bug report, by telling us not just where a process hung (which
30 * generally is just reported as a stack trace at the Java level) or crashed, but
31 * also what happened immediately before that hang or crash. This may help track down
32 * problems in the native rendering code or driver interaction related to the display
33 * list operations that led up to the hang or crash.
34 *
35 * The log is implemented as a circular buffer for both space and performance
36 * reasons - we only care about the last several operations to give us context
37 * leading up to the problem, and we don't want to constantly copy data around or do
38 * additional mallocs to keep the most recent operations logged. Only numbers are
39 * logged to make the operation fast. If and when the log is output, we process this
40 * data into meaningful strings.
41 *
42 * There is an assumption about the format of the command (currently 2 ints: the
43 * opcode and the nesting level). If the type of information logged changes (for example,
44 * we may want to save a timestamp), then the size of the buffer and the way the
45 * information is recorded in writeCommand() should change to suit.
46 */
47
48namespace android {
49
50#ifdef USE_OPENGL_RENDERER
51using namespace uirenderer;
52ANDROID_SINGLETON_STATIC_INSTANCE(DisplayListLogBuffer);
53#endif
54
55namespace uirenderer {
56
57
58DisplayListLogBuffer::DisplayListLogBuffer() {
Chris Craik2af46352012-11-26 18:30:17 -080059 mBufferFirst = (OpLog*) malloc(BUFFER_SIZE * sizeof(OpLog));
Chet Haase9c1e23b2011-03-24 10:51:31 -070060 mStart = mBufferFirst;
61 mBufferLast = mBufferFirst + BUFFER_SIZE - 1;
62 mEnd = mStart;
63}
64
65DisplayListLogBuffer::~DisplayListLogBuffer() {
66 free(mBufferFirst);
67}
68
69/**
70 * Called from DisplayListRenderer to output the current buffer into the
71 * specified FILE. This only happens in a dumpsys/bugreport operation.
72 */
Chris Craik2af46352012-11-26 18:30:17 -080073void DisplayListLogBuffer::outputCommands(FILE *file)
Chet Haase9c1e23b2011-03-24 10:51:31 -070074{
Chris Craik2af46352012-11-26 18:30:17 -080075 OpLog* tmpBufferPtr = mStart;
Chet Haase9c1e23b2011-03-24 10:51:31 -070076 while (true) {
77 if (tmpBufferPtr == mEnd) {
78 break;
79 }
Chris Craikd4b43b32013-05-09 13:07:52 -070080
81 fprintf(file, "%*s%s\n", 2 * tmpBufferPtr->level, "", tmpBufferPtr->label);
82
Chris Craik2af46352012-11-26 18:30:17 -080083 OpLog* nextOp = tmpBufferPtr++;
Chet Haase9c1e23b2011-03-24 10:51:31 -070084 if (tmpBufferPtr > mBufferLast) {
85 tmpBufferPtr = mBufferFirst;
86 }
Chet Haase9c1e23b2011-03-24 10:51:31 -070087 }
88}
89
Chet Haase9c1e23b2011-03-24 10:51:31 -070090/**
Chris Craik2af46352012-11-26 18:30:17 -080091 * Store the given level and label in the buffer and increment/wrap the mEnd
92 * and mStart values as appropriate. Label should point to static memory.
Chet Haase9c1e23b2011-03-24 10:51:31 -070093 */
Chris Craik2af46352012-11-26 18:30:17 -080094void DisplayListLogBuffer::writeCommand(int level, const char* label) {
95 mEnd->level = level;
96 mEnd->label = label;
97
Chet Haase9c1e23b2011-03-24 10:51:31 -070098 if (mEnd == mBufferLast) {
99 mEnd = mBufferFirst;
100 } else {
101 mEnd++;
102 }
103 if (mEnd == mStart) {
104 mStart++;
105 if (mStart > mBufferLast) {
106 mStart = mBufferFirst;
107 }
108 }
109}
110
111}; // namespace uirenderer
112}; // namespace android