// Copyright 2020 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #define PW_TRACE_MODULE_NAME "TST" #include "pw_trace_tokenized/trace_buffer.h" #include "gtest/gtest.h" #include "pw_trace/trace.h" TEST(TokenizedTrace, Simple) { PW_TRACE_SET_ENABLED(true); pw::trace::ClearBuffer(); PW_TRACE_INSTANT("Test"); // Check results pw::ring_buffer::PrefixedEntryRingBuffer* buf = pw::trace::GetBuffer(); EXPECT_EQ(buf->EntryCount(), 1u); const size_t expected_min_bytes_used = 1 /*varint size */ + 4 /*token*/ + 1 /* min varint time */; const size_t expected_max_bytes_used = 1 /*varint size */ + 4 /*token*/ + sizeof(PW_TRACE_TIME_TYPE) + 1 /* max varint time */; EXPECT_GE(buf->TotalUsedBytes(), expected_min_bytes_used); EXPECT_LE(buf->TotalUsedBytes(), expected_max_bytes_used); } TEST(TokenizedTrace, TraceId) { PW_TRACE_SET_ENABLED(true); pw::trace::ClearBuffer(); uint32_t trace_id = 256; PW_TRACE_INSTANT("Test", "group", trace_id); // Check results pw::ring_buffer::PrefixedEntryRingBuffer* buf = pw::trace::GetBuffer(); EXPECT_EQ(buf->EntryCount(), 1u); const size_t expected_min_bytes_used = 1 /*varint size */ + 4 /*token*/ + 1 /* min varint time */ + 2 /*varint trace id*/; const size_t expected_max_bytes_used = 1 /*varint size */ + 4 /*token*/ + sizeof(PW_TRACE_TIME_TYPE) + 1 /* max varint time */ + 2 /*varint trace id*/; EXPECT_GE(buf->TotalUsedBytes(), expected_min_bytes_used); EXPECT_LE(buf->TotalUsedBytes(), expected_max_bytes_used); } TEST(TokenizedTrace, Data) { PW_TRACE_SET_ENABLED(true); pw::trace::ClearBuffer(); char data[] = "some test data"; PW_TRACE_INSTANT_DATA("Test", "test_data", data, sizeof(data)); // Check results pw::ring_buffer::PrefixedEntryRingBuffer* buf = pw::trace::GetBuffer(); EXPECT_EQ(buf->EntryCount(), 1u); const size_t expected_min_bytes_used = 1 /*varint size */ + 4 /*token*/ + 1 /* min varint time */ + sizeof(data); const size_t expected_max_bytes_used = 1 /*varint size */ + 4 /*token*/ + sizeof(PW_TRACE_TIME_TYPE) + 1 /* max varint time */ + sizeof(data); EXPECT_GE(buf->TotalUsedBytes(), expected_min_bytes_used); EXPECT_LE(buf->TotalUsedBytes(), expected_max_bytes_used); std::byte value[expected_max_bytes_used]; size_t bytes_read = 0; EXPECT_EQ(buf->PeekFront(std::span(value), &bytes_read), pw::OkStatus()); // read size is minus 1, since doesn't include varint size EXPECT_GE(bytes_read, expected_min_bytes_used - 1); EXPECT_LE(bytes_read, expected_max_bytes_used - 1); EXPECT_STREQ(data, reinterpret_cast(&value[bytes_read - sizeof(data)])); } TEST(TokenizedTrace, Clear) { PW_TRACE_SET_ENABLED(true); pw::trace::ClearBuffer(); pw::ring_buffer::PrefixedEntryRingBuffer* buf = pw::trace::GetBuffer(); PW_TRACE_INSTANT("Test"); EXPECT_EQ(buf->EntryCount(), 1u); pw::trace::ClearBuffer(); EXPECT_EQ(buf->EntryCount(), 0u); } TEST(TokenizedTrace, Overflow) { PW_TRACE_SET_ENABLED(true); pw::trace::ClearBuffer(); pw::ring_buffer::PrefixedEntryRingBuffer* buf = pw::trace::GetBuffer(); // Add samples until entry count stops increasing. uint32_t last_entry_count = 0; size_t count = 0; while (buf->EntryCount() == 0 || buf->EntryCount() > last_entry_count) { last_entry_count = buf->EntryCount(); PW_TRACE_INSTANT_DATA("Test", "count", &count, sizeof(count)); count++; } // CHECK size_t expected_count = 1; // skip first (since it was lost) while (buf->EntryCount() > 0) { std::byte value[PW_TRACE_BUFFER_MAX_BLOCK_SIZE_BYTES]; size_t bytes_read = 0; EXPECT_EQ(buf->PeekFront(std::span(value), &bytes_read), pw::OkStatus()); EXPECT_EQ(buf->PopFront(), pw::OkStatus()); EXPECT_EQ(*reinterpret_cast(&value[bytes_read - sizeof(size_t)]), expected_count); expected_count++; } EXPECT_EQ(count, expected_count); } TEST(TokenizedTrace, BlockTooLarge) { PW_TRACE_SET_ENABLED(true); pw::trace::ClearBuffer(); pw::ring_buffer::PrefixedEntryRingBuffer* buf = pw::trace::GetBuffer(); uint8_t data[PW_TRACE_BUFFER_MAX_BLOCK_SIZE_BYTES]; PW_TRACE_INSTANT_DATA("Test", "data", data, sizeof(data)); EXPECT_EQ(buf->EntryCount(), 0u); } TEST(TokenizedTrace, DeringAndViewRawBuffer) { PW_TRACE_SET_ENABLED(true); pw::trace::ClearBuffer(); // Should be empty span pw::ConstByteSpan buf = pw::trace::DeringAndViewRawBuffer(); EXPECT_EQ(buf.size(), 0u); // Should now have data PW_TRACE_INSTANT("Test"); buf = pw::trace::DeringAndViewRawBuffer(); EXPECT_GT(buf.size(), 0u); // Should now have more data PW_TRACE_INSTANT("Test"); size_t size_start = buf.size(); buf = pw::trace::DeringAndViewRawBuffer(); EXPECT_GT(buf.size(), size_start); }