Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31a8dbc0 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

Add synchronous SurfaceFlinger tracing

We want to collect traces without impacting composition so by default
we collect traces in another thread while holding a tracing lock when
current state is copied over to drawing state. But this has some
issues. If the tracing thread is not scheduled before the next frame
is composed, we may miss a state. If we need to collect composition
state then we may access states that are currently being modified by
the drawing thread.

To counter this the caller can pass in a TRACE_SYNC flag which will
force the trace to be collected in the drawing thread after
composition. This can be used by tests which don't care about the perf
impact caused by the sync tracing.

This change also fixes threading bugs highlighted in b/154155922

Finally we add a flag TRACE_BUFFERS to capture buffer latches as
well. This is used for Blast buffer tests.

Bug: 169849887, 153739621
Fixes: 154155922
Test: enable tracing with flags, on hwasan builds
Change-Id: I58512cdc98745398b460fa8e7798eb809bd2b0ae
parent 4283d657
Loading
Loading
Loading
Loading
+22 −17
Original line number Diff line number Diff line
@@ -1850,16 +1850,18 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT

    bool refreshNeeded;
    {
        ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
        mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
                mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
                mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS);
        const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
        ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);

        mFrameTimeline->setSfWakeUp(vsyncId, frameStart);

        refreshNeeded = handleMessageTransaction();
        refreshNeeded |= handleMessageInvalidate();
        if (mTracingEnabled) {
            mAddCompositionStateToTrace =
                    mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
            if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
        if (tracePreComposition) {
            if (mVisibleRegionsDirty) {
                mTracing.notifyLocked("visibleRegionsDirty");
            }
        }
@@ -2009,12 +2011,15 @@ void SurfaceFlinger::onMessageRefresh() {
    modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);

    mLayersWithQueuedFrames.clear();
    if (mTracingEnabled && mTracePostComposition) {
        // This may block if SurfaceTracing is running in sync mode.
        if (mVisibleRegionsDirty) {
        mVisibleRegionsDirty = false;
        if (mTracingEnabled && mAddCompositionStateToTrace) {
            mTracing.notify("visibleRegionsDirty");
        } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) {
            mTracing.notify("bufferLatched");
        }
    }
    mVisibleRegionsDirty = false;

    if (mCompositionEngine->needsAnotherUpdate()) {
        signalLayerUpdate();
@@ -4279,7 +4284,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) {

status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
    if (asProto && mTracing.isEnabled()) {
        mTracing.writeToFileAsync();
        mTracing.writeToFile();
    }

    return doDump(fd, DumpArgs(), asProto);
@@ -5103,19 +5108,19 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
            }
            case 1025: { // Set layer tracing
                n = data.readInt32();
                bool tracingEnabledChanged;
                if (n) {
                    ALOGD("LayerTracing enabled");
                    mTracingEnabledChanged = mTracing.enable();
                    reply->writeInt32(NO_ERROR);
                    tracingEnabledChanged = mTracing.enable();
                    if (tracingEnabledChanged) {
                        schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait();
                    }
                } else {
                    ALOGD("LayerTracing disabled");
                    mTracingEnabledChanged = mTracing.disable();
                    if (mTracingEnabledChanged) {
                        reply->writeInt32(mTracing.writeToFile());
                    } else {
                        reply->writeInt32(NO_ERROR);
                    }
                    tracingEnabledChanged = mTracing.disable();
                }
                mTracingEnabledChanged = tracingEnabledChanged;
                reply->writeInt32(NO_ERROR);
                return NO_ERROR;
            }
            case 1026: { // Get layer tracing status
+1 −1
Original line number Diff line number Diff line
@@ -1134,7 +1134,7 @@ private:
    SurfaceTracing mTracing{*this};
    std::mutex mTracingLock;
    bool mTracingEnabled = false;
    bool mAddCompositionStateToTrace = false;
    bool mTracePostComposition = false;
    std::atomic<bool> mTracingEnabledChanged = false;

    const std::shared_ptr<TimeStats> mTimeStats;
+130 −116
Original line number Diff line number Diff line
@@ -14,9 +14,6 @@
 * limitations under the License.
 */

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#undef LOG_TAG
#define LOG_TAG "SurfaceTracing"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -32,65 +29,65 @@

namespace android {

SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
      : mFlinger(flinger), mSfLock(flinger.mTracingLock) {}
SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {}

void SurfaceTracing::mainLoop() {
    bool enabled = addFirstEntry();
    while (enabled) {
        LayersTraceProto entry = traceWhenNotified();
        enabled = addTraceToBuffer(entry);
bool SurfaceTracing::enable() {
    std::scoped_lock lock(mTraceLock);
    if (mEnabled) {
        return false;
    }

    if (flagIsSet(TRACE_SYNC)) {
        runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig);
    } else {
        runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig,
                                                               mFlinger.mTracingLock);
    }
    mEnabled = true;
    return true;
}

bool SurfaceTracing::addFirstEntry() {
    LayersTraceProto entry;
    {
        std::scoped_lock lock(mSfLock);
        entry = traceLayersLocked("tracing.enable");
bool SurfaceTracing::disable() {
    std::scoped_lock lock(mTraceLock);
    if (!mEnabled) {
        return false;
    }
    return addTraceToBuffer(entry);
    mEnabled = false;
    runner->stop();
    return true;
}

LayersTraceProto SurfaceTracing::traceWhenNotified() {
    std::unique_lock<std::mutex> lock(mSfLock);
    mCanStartTrace.wait(lock);
    android::base::ScopedLockAssertion assumeLock(mSfLock);
    LayersTraceProto entry = traceLayersLocked(mWhere);
    mTracingInProgress = false;
    mMissedTraceEntries = 0;
    lock.unlock();
    return entry;
bool SurfaceTracing::isEnabled() const {
    std::scoped_lock lock(mTraceLock);
    return mEnabled;
}

bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
status_t SurfaceTracing::writeToFile() {
    std::scoped_lock lock(mTraceLock);
    mBuffer.emplace(std::move(entry));
    if (mWriteToFile) {
        writeProtoFileLocked();
        mWriteToFile = false;
    if (!mEnabled) {
        return STATUS_OK;
    }
    return mEnabled;
    return runner->writeToFile();
}

void SurfaceTracing::notify(const char* where) {
    std::scoped_lock lock(mSfLock);
    notifyLocked(where);
    if (mEnabled) {
        runner->notify(where);
    }
}

void SurfaceTracing::notifyLocked(const char* where) {
    mWhere = where;
    if (mTracingInProgress) {
        mMissedTraceEntries++;
    if (mEnabled) {
        runner->notifyLocked(where);
    }
    mTracingInProgress = true;
    mCanStartTrace.notify_one();
}

void SurfaceTracing::writeToFileAsync() {
void SurfaceTracing::dump(std::string& result) const {
    std::scoped_lock lock(mTraceLock);
    mWriteToFile = true;
    mCanStartTrace.notify_one();
    base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
    if (mEnabled) {
        runner->dump(result);
    }
}

void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
@@ -101,12 +98,12 @@ void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
}

void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
    auto protoSize = proto.ByteSize();
    size_t protoSize = static_cast<size_t>(proto.ByteSize());
    while (mUsedInBytes + protoSize > mSizeInBytes) {
        if (mStorage.empty()) {
            return;
        }
        mUsedInBytes -= mStorage.front().ByteSize();
        mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
        mStorage.pop();
    }
    mUsedInBytes += protoSize;
@@ -115,7 +112,7 @@ void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
}

void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
    fileProto->mutable_entry()->Reserve(mStorage.size());
    fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size()));

    while (!mStorage.empty()) {
        auto entry = fileProto->add_entry();
@@ -124,77 +121,66 @@ void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
    }
}

bool SurfaceTracing::enable() {
    std::scoped_lock lock(mTraceLock);

    if (mEnabled) {
        return false;
SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config)
      : mFlinger(flinger), mConfig(config) {
    mBuffer.setSize(mConfig.bufferSize);
}

    mBuffer.reset(mBufferSize);
    mEnabled = true;
    mThread = std::thread(&SurfaceTracing::mainLoop, this);
    return true;
void SurfaceTracing::Runner::notify(const char* where) {
    LayersTraceProto entry = traceLayers(where);
    mBuffer.emplace(std::move(entry));
}

status_t SurfaceTracing::writeToFile() {
    std::thread thread;
    {
        std::scoped_lock lock(mTraceLock);
        thread = std::move(mThread);
    }
    thread.join();
    return mLastErr;
status_t SurfaceTracing::Runner::stop() {
    return writeToFile();
}

bool SurfaceTracing::disable() {
    std::scoped_lock lock(mTraceLock);
status_t SurfaceTracing::Runner::writeToFile() {
    ATRACE_CALL();

    if (!mEnabled) {
        return false;
    }
    LayersTraceFileProto fileProto;
    std::string output;

    mEnabled = false;
    mWriteToFile = true;
    mCanStartTrace.notify_all();
    return true;
}
    fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
                               LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
    mBuffer.flush(&fileProto);
    mBuffer.reset(mConfig.bufferSize);

bool SurfaceTracing::isEnabled() const {
    std::scoped_lock lock(mTraceLock);
    return mEnabled;
    if (!fileProto.SerializeToString(&output)) {
        ALOGE("Could not save the proto file! Permission denied");
        return PERMISSION_DENIED;
    }

void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
    std::scoped_lock lock(mTraceLock);
    mBufferSize = bufferSizeInByte;
    mBuffer.setSize(bufferSizeInByte);
    // -rw-r--r--
    const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(),
                                          true)) {
        ALOGE("Could not save the proto file! There are missing fields");
        return PERMISSION_DENIED;
    }

void SurfaceTracing::setTraceFlags(uint32_t flags) {
    std::scoped_lock lock(mSfLock);
    mTraceFlags = flags;
    return NO_ERROR;
}

LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) {
    ATRACE_CALL();

    LayersTraceProto entry;
    entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
    entry.set_where(where);
    LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
    LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags));

    if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) {
    if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) {
        mFlinger.dumpOffscreenLayersProto(layers);
    }
    entry.mutable_layers()->Swap(&layers);

    if (mTraceFlags & SurfaceTracing::TRACE_HWC) {
    if (flagIsSet(SurfaceTracing::TRACE_HWC)) {
        std::string hwcDump;
        mFlinger.dumpHwc(hwcDump);
        entry.set_hwc_blob(hwcDump);
    }
    if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) {
    if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) {
        entry.set_excludes_composition_state(true);
    }
    entry.set_missed_entries(mMissedTraceEntries);
@@ -202,42 +188,70 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
    return entry;
}

void SurfaceTracing::writeProtoFileLocked() {
    ATRACE_CALL();
void SurfaceTracing::Runner::dump(std::string& result) const {
    base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
                        mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
                        float(mBuffer.size()) / float(1_MB));
}

    LayersTraceFileProto fileProto;
    std::string output;
SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config,
                                         std::mutex& sfLock)
      : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) {
    mEnabled = true;
    mThread = std::thread(&AsyncRunner::loop, this);
}

    fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
                               LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
    mBuffer.flush(&fileProto);
    mBuffer.reset(mBufferSize);
void SurfaceTracing::AsyncRunner::loop() {
    while (mEnabled) {
        LayersTraceProto entry;
        bool entryAdded = traceWhenNotified(&entry);
        if (entryAdded) {
            mBuffer.emplace(std::move(entry));
        }
        if (mWriteToFile) {
            Runner::writeToFile();
            mWriteToFile = false;
        }
    }
}

    if (!fileProto.SerializeToString(&output)) {
        ALOGE("Could not save the proto file! Permission denied");
        mLastErr = PERMISSION_DENIED;
bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) {
    std::unique_lock<std::mutex> lock(mSfLock);
    mCanStartTrace.wait(lock);
    if (!mAddEntry) {
        return false;
    }
    *outProto = traceLayers(mWhere);
    mAddEntry = false;
    mMissedTraceEntries = 0;
    return true;
}

    // -rw-r--r--
    const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    if (!android::base::WriteStringToFile(output, kDefaultFileName, mode, getuid(), getgid(),
                                          true)) {
        ALOGE("Could not save the proto file! There are missing fields");
        mLastErr = PERMISSION_DENIED;
void SurfaceTracing::AsyncRunner::notify(const char* where) {
    std::scoped_lock lock(mSfLock);
    notifyLocked(where);
}

void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) {
    mWhere = where;
    if (mAddEntry) {
        mMissedTraceEntries++;
    }
    mAddEntry = true;
    mCanStartTrace.notify_one();
}

    mLastErr = NO_ERROR;
status_t SurfaceTracing::AsyncRunner::writeToFile() {
    mWriteToFile = true;
    mCanStartTrace.notify_one();
    return STATUS_OK;
}

void SurfaceTracing::dump(std::string& result) const {
    std::scoped_lock lock(mTraceLock);
    base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
    base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
                        mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
                        float(mBuffer.size()) / float(1_MB));
status_t SurfaceTracing::AsyncRunner::stop() {
    mEnabled = false;
    mCanStartTrace.notify_one();
    mThread.join();
    return Runner::writeToFile();
}

} // namespace android

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
+84 −38
Original line number Diff line number Diff line
@@ -32,25 +32,31 @@ using namespace android::surfaceflinger;
namespace android {

class SurfaceFlinger;

constexpr auto operator""_MB(unsigned long long const num) {
    return num * 1024 * 1024;
}
/*
 * SurfaceTracing records layer states during surface flinging.
 * SurfaceTracing records layer states during surface flinging. Manages tracing state and
 * configuration.
 */
class SurfaceTracing {
public:
    explicit SurfaceTracing(SurfaceFlinger& flinger);
    SurfaceTracing(SurfaceFlinger& flinger);
    bool enable();
    bool disable();
    status_t writeToFile();
    bool isEnabled() const;
    /*
     * Adds a trace entry, must be called from the drawing thread or while holding the
     * SurfaceFlinger tracing lock.
     */
    void notify(const char* where);
    void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */;
    /*
     * Adds a trace entry, called while holding the SurfaceFlinger tracing lock.
     */
    void notifyLocked(const char* where) /* REQUIRES(mSfLock) */;

    void setBufferSize(size_t bufferSizeInByte);
    void writeToFileAsync();
    void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; }
    void dump(std::string& result) const;

    enum : uint32_t {
@@ -59,18 +65,34 @@ public:
        TRACE_COMPOSITION = 1 << 2,
        TRACE_EXTRA = 1 << 3,
        TRACE_HWC = 1 << 4,
        TRACE_ALL = 0xffffffff
        // Add non-geometry composition changes to the trace.
        TRACE_BUFFERS = 1 << 5,
        // Add entries from the drawing thread post composition.
        TRACE_SYNC = 1 << 6,
        TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA,
    };
    void setTraceFlags(uint32_t flags);
    bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ {
        return (mTraceFlags & flags) == flags;
    }
    void setTraceFlags(uint32_t flags) { mConfig.flags = flags; }
    bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }

private:
    static constexpr auto kDefaultBufferCapInByte = 5_MB;
    static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
    class Runner;
    static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB;
    static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb";

    class LayersTraceBuffer { // ring buffer
    SurfaceFlinger& mFlinger;
    mutable std::mutex mTraceLock;
    bool mEnabled = false;
    std::unique_ptr<Runner> runner;

    struct Config {
        uint32_t flags = TRACE_CRITICAL | TRACE_INPUT;
        size_t bufferSize = DEFAULT_BUFFER_SIZE;
    } mConfig;

    /*
     * ring buffer.
     */
    class LayersTraceBuffer {
    public:
        size_t size() const { return mSizeInBytes; }
        size_t used() const { return mUsedInBytes; }
@@ -83,35 +105,59 @@ private:

    private:
        size_t mUsedInBytes = 0U;
        size_t mSizeInBytes = 0U;
        size_t mSizeInBytes = DEFAULT_BUFFER_SIZE;
        std::queue<LayersTraceProto> mStorage;
    };

    void mainLoop();
    bool addFirstEntry();
    LayersTraceProto traceWhenNotified();
    LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);

    // Returns true if trace is enabled.
    bool addTraceToBuffer(LayersTraceProto& entry);
    void writeProtoFileLocked() REQUIRES(mTraceLock);
    /*
     * Implements a synchronous way of adding trace entries. This must be called
     * from the drawing thread.
     */
    class Runner {
    public:
        Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config);
        virtual ~Runner() = default;
        virtual status_t stop();
        virtual status_t writeToFile();
        virtual void notify(const char* where);
        /* Cannot be called with a synchronous runner. */
        virtual void notifyLocked(const char* /* where */) {}
        void dump(std::string& result) const;

    protected:
        bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
        SurfaceFlinger& mFlinger;
    status_t mLastErr = NO_ERROR;
    std::thread mThread;
    std::condition_variable mCanStartTrace;
        SurfaceTracing::Config mConfig;
        SurfaceTracing::LayersTraceBuffer mBuffer;
        uint32_t mMissedTraceEntries = 0;
        LayersTraceProto traceLayers(const char* where);
    };

    std::mutex& mSfLock;
    uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT;
    const char* mWhere GUARDED_BY(mSfLock) = "";
    uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0;
    bool mTracingInProgress GUARDED_BY(mSfLock) = false;
    /*
     * Implements asynchronous way to add trace entries called from a separate thread while holding
     * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not
     * scheduled in time.
     */
    class AsyncRunner : public Runner {
    public:
        AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock);
        virtual ~AsyncRunner() = default;
        status_t stop() override;
        status_t writeToFile() override;
        void notify(const char* where) override;
        void notifyLocked(const char* where);

    mutable std::mutex mTraceLock;
    LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
    size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte;
    bool mEnabled GUARDED_BY(mTraceLock) = false;
    bool mWriteToFile GUARDED_BY(mTraceLock) = false;
    private:
        std::mutex& mSfLock;
        std::condition_variable mCanStartTrace;
        std::thread mThread;
        const char* mWhere = "";
        bool mWriteToFile = false;
        bool mEnabled = false;
        bool mAddEntry = false;
        void loop();
        bool traceWhenNotified(LayersTraceProto* outProto);
    };
};

} // namespace android
+2 −2
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ message LayersTraceFileProto {
/* one window manager trace entry. */
message LayersTraceProto {
    /* required: elapsed realtime in nanos since boot of when this entry was logged */
    optional fixed64 elapsed_realtime_nanos = 1;
    optional sfixed64 elapsed_realtime_nanos = 1;

    /* where the trace originated */
    optional string where = 2;
@@ -56,5 +56,5 @@ message LayersTraceProto {
    optional bool excludes_composition_state = 5;

    /* Number of missed entries since the last entry was recorded. */
    optional int32 missed_entries = 6;
    optional uint32 missed_entries = 6;
}