diff options
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 39 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceTracing.cpp | 246 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceTracing.h | 122 | ||||
| -rw-r--r-- | services/surfaceflinger/layerproto/layerstrace.proto | 4 |
5 files changed, 239 insertions, 174 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7b045afcbc..576f0fd29a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -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 (mVisibleRegionsDirty) { - mVisibleRegionsDirty = false; - if (mTracingEnabled && mAddCompositionStateToTrace) { + if (mTracingEnabled && mTracePostComposition) { + // This may block if SurfaceTracing is running in sync mode. + if (mVisibleRegionsDirty) { 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 diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 5bb5a0de82..9db09f0e73 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -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; diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index d84ce69e56..1d1f0c5cf6 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -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" diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index f208eb8803..576bba72ad 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -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); - - SurfaceFlinger& mFlinger; - status_t mLastErr = NO_ERROR; - std::thread mThread; - std::condition_variable mCanStartTrace; + /* + * 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; + 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 diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto index acf621e16c..990f3cffda 100644 --- a/services/surfaceflinger/layerproto/layerstrace.proto +++ b/services/surfaceflinger/layerproto/layerstrace.proto @@ -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; } |