19c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase/*
29c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * Copyright (C) 2011 The Android Open Source Project
39c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase *
49c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
59c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * you may not use this file except in compliance with the License.
69c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * You may obtain a copy of the License at
79c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase *
89c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
99c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase *
109c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * Unless required by applicable law or agreed to in writing, software
119c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
129c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * See the License for the specific language governing permissions and
149c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * limitations under the License.
159c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase */
169c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
179c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase#include "DisplayListLogBuffer.h"
189c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
199c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase// BUFFER_SIZE size must be one more than a multiple of COMMAND_SIZE to ensure
209c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase// that mStart always points at the next command, not just the next item
219c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase#define NUM_COMMANDS 50
222af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik#define BUFFER_SIZE ((NUM_COMMANDS) + 1)
239c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
249c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase/**
259c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * DisplayListLogBuffer is a utility class which logs the most recent display
269c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * list operations in a circular buffer. The log is process-wide, because we
279c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * only care about the most recent operations, not the operations on a per-window
289c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * basis for a given activity. The purpose of the log is to provide more debugging
299c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * information in a bug report, by telling us not just where a process hung (which
309c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * generally is just reported as a stack trace at the Java level) or crashed, but
319c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * also what happened immediately before that hang or crash. This may help track down
329c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * problems in the native rendering code or driver interaction related to the display
339c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * list operations that led up to the hang or crash.
349c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase *
359c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * The log is implemented as a circular buffer for both space and performance
369c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * reasons - we only care about the last several operations to give us context
379c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * leading up to the problem, and we don't want to constantly copy data around or do
389c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * additional mallocs to keep the most recent operations logged. Only numbers are
399c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * logged to make the operation fast. If and when the log is output, we process this
409c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * data into meaningful strings.
419c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase *
429c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * There is an assumption about the format of the command (currently 2 ints: the
439c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * opcode and the nesting level). If the type of information logged changes (for example,
449c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * we may want to save a timestamp), then the size of the buffer and the way the
459c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * information is recorded in writeCommand() should change to suit.
469c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase */
479c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
489c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haasenamespace android {
499c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
509c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase#ifdef USE_OPENGL_RENDERER
519c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haaseusing namespace uirenderer;
529c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet HaaseANDROID_SINGLETON_STATIC_INSTANCE(DisplayListLogBuffer);
539c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase#endif
549c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
559c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haasenamespace uirenderer {
569c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
579c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
589c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet HaaseDisplayListLogBuffer::DisplayListLogBuffer() {
592af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    mBufferFirst = (OpLog*) malloc(BUFFER_SIZE * sizeof(OpLog));
609c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    mStart = mBufferFirst;
619c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    mBufferLast = mBufferFirst + BUFFER_SIZE - 1;
629c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    mEnd = mStart;
639c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase}
649c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
659c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet HaaseDisplayListLogBuffer::~DisplayListLogBuffer() {
669c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    free(mBufferFirst);
679c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase}
689c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
699c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase/**
709c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * Called from DisplayListRenderer to output the current buffer into the
719c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase * specified FILE. This only happens in a dumpsys/bugreport operation.
729c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase */
732af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craikvoid DisplayListLogBuffer::outputCommands(FILE *file)
749c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase{
752af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    OpLog* tmpBufferPtr = mStart;
769c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    while (true) {
779c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        if (tmpBufferPtr == mEnd) {
789c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase            break;
799c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        }
80d4b43b3cf3ee109a5251228dcc1d9bc3c25ff150Chris Craik
81d4b43b3cf3ee109a5251228dcc1d9bc3c25ff150Chris Craik        fprintf(file, "%*s%s\n", 2 * tmpBufferPtr->level, "", tmpBufferPtr->label);
82d4b43b3cf3ee109a5251228dcc1d9bc3c25ff150Chris Craik
832af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik        OpLog* nextOp = tmpBufferPtr++;
849c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        if (tmpBufferPtr > mBufferLast) {
859c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase            tmpBufferPtr = mBufferFirst;
869c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        }
872af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    }
889c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase}
899c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
909c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase/**
912af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik * Store the given level and label in the buffer and increment/wrap the mEnd
922af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik * and mStart values as appropriate. Label should point to static memory.
939c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase */
942af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craikvoid DisplayListLogBuffer::writeCommand(int level, const char* label) {
952af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    mEnd->level = level;
962af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    mEnd->label = label;
972af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik
989c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    if (mEnd == mBufferLast) {
999c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        mEnd = mBufferFirst;
1009c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    } else {
1019c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        mEnd++;
1029c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    }
1039c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    if (mEnd == mStart) {
1049c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        mStart++;
1059c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        if (mStart > mBufferLast) {
1069c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase            mStart = mBufferFirst;
1079c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase        }
1089c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase    }
1099c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase}
1109c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase
1119c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase}; // namespace uirenderer
1129c1e23baf5bfbebd1aebbd6d9a18c225325567ceChet Haase}; // namespace android
113