Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2017 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 "src/tracing/core/shared_memory_arbiter_impl.h"
     18 
     19 #include "gmock/gmock.h"
     20 #include "gtest/gtest.h"
     21 #include "perfetto/base/utils.h"
     22 #include "perfetto/tracing/core/basic_types.h"
     23 #include "perfetto/tracing/core/commit_data_request.h"
     24 #include "perfetto/tracing/core/shared_memory_abi.h"
     25 #include "perfetto/tracing/core/trace_writer.h"
     26 #include "src/base/test/gtest_test_suite.h"
     27 #include "src/base/test/test_task_runner.h"
     28 #include "src/tracing/core/patch_list.h"
     29 #include "src/tracing/test/aligned_buffer_test.h"
     30 
     31 namespace perfetto {
     32 namespace {
     33 
     34 using testing::Invoke;
     35 using testing::_;
     36 
     37 class MockProducerEndpoint : public TracingService::ProducerEndpoint {
     38  public:
     39   void RegisterDataSource(const DataSourceDescriptor&) override {}
     40   void UnregisterDataSource(const std::string&) override {}
     41   void NotifyFlushComplete(FlushRequestID) override {}
     42   void NotifyDataSourceStarted(DataSourceInstanceID) override {}
     43   void NotifyDataSourceStopped(DataSourceInstanceID) override {}
     44   void ActivateTriggers(const std::vector<std::string>&) {}
     45   SharedMemory* shared_memory() const override { return nullptr; }
     46   size_t shared_buffer_page_size_kb() const override { return 0; }
     47   std::unique_ptr<TraceWriter> CreateTraceWriter(BufferID) override {
     48     return nullptr;
     49   }
     50   SharedMemoryArbiter* GetInProcessShmemArbiter() override { return nullptr; }
     51 
     52   MOCK_METHOD2(CommitData, void(const CommitDataRequest&, CommitDataCallback));
     53   MOCK_METHOD2(RegisterTraceWriter, void(uint32_t, uint32_t));
     54   MOCK_METHOD1(UnregisterTraceWriter, void(uint32_t));
     55 };
     56 
     57 class SharedMemoryArbiterImplTest : public AlignedBufferTest {
     58  public:
     59   void SetUp() override {
     60     AlignedBufferTest::SetUp();
     61     task_runner_.reset(new base::TestTaskRunner());
     62     arbiter_.reset(new SharedMemoryArbiterImpl(buf(), buf_size(), page_size(),
     63                                                &mock_producer_endpoint_,
     64                                                task_runner_.get()));
     65   }
     66 
     67   void TearDown() override {
     68     arbiter_.reset();
     69     task_runner_.reset();
     70   }
     71 
     72   std::unique_ptr<base::TestTaskRunner> task_runner_;
     73   std::unique_ptr<SharedMemoryArbiterImpl> arbiter_;
     74   MockProducerEndpoint mock_producer_endpoint_;
     75   std::function<void(const std::vector<uint32_t>&)> on_pages_complete_;
     76 };
     77 
     78 size_t const kPageSizes[] = {4096, 65536};
     79 INSTANTIATE_TEST_SUITE_P(PageSize,
     80                          SharedMemoryArbiterImplTest,
     81                          ::testing::ValuesIn(kPageSizes));
     82 
     83 // The buffer has 14 pages (kNumPages), each will be partitioned in 14 chunks.
     84 // The test requests 30 chunks (2 full pages + 2 chunks from a 3rd page) and
     85 // releases them in different batches. It tests the consistency of the batches
     86 // and the releasing order.
     87 TEST_P(SharedMemoryArbiterImplTest, GetAndReturnChunks) {
     88   SharedMemoryArbiterImpl::set_default_layout_for_testing(
     89       SharedMemoryABI::PageLayout::kPageDiv14);
     90   static constexpr size_t kTotChunks = kNumPages * 14;
     91   SharedMemoryABI::Chunk chunks[kTotChunks];
     92   for (size_t i = 0; i < 14 * 2 + 2; i++) {
     93     chunks[i] = arbiter_->GetNewChunk({}, 0 /*size_hint*/);
     94     ASSERT_TRUE(chunks[i].is_valid());
     95   }
     96 
     97   // Finally return the first 28 chunks (full 2 pages) and only the 2nd chunk of
     98   // the 2rd page. Chunks are release in interleaved order: 1,0,3,2,5,4,7,6.
     99   // Check that the notification callback is posted and order is consistent.
    100   auto on_commit_1 = task_runner_->CreateCheckpoint("on_commit_1");
    101   EXPECT_CALL(mock_producer_endpoint_, CommitData(_, _))
    102       .WillOnce(Invoke([on_commit_1](const CommitDataRequest& req,
    103                                      MockProducerEndpoint::CommitDataCallback) {
    104         ASSERT_EQ(14 * 2 + 1, req.chunks_to_move_size());
    105         for (size_t i = 0; i < 14 * 2; i++) {
    106           ASSERT_EQ(i / 14, req.chunks_to_move()[i].page());
    107           ASSERT_EQ((i % 14) ^ 1, req.chunks_to_move()[i].chunk());
    108           ASSERT_EQ(i % 5, req.chunks_to_move()[i].target_buffer());
    109         }
    110         ASSERT_EQ(2u, req.chunks_to_move()[28].page());
    111         ASSERT_EQ(1u, req.chunks_to_move()[28].chunk());
    112         ASSERT_EQ(42u, req.chunks_to_move()[28].target_buffer());
    113         on_commit_1();
    114       }));
    115   PatchList ignored;
    116   for (size_t i = 0; i < 14 * 2; i++)
    117     arbiter_->ReturnCompletedChunk(std::move(chunks[i ^ 1]), i % 5, &ignored);
    118   arbiter_->ReturnCompletedChunk(std::move(chunks[29]), 42, &ignored);
    119   task_runner_->RunUntilCheckpoint("on_commit_1");
    120 
    121   // Then release the 1st chunk of the 3rd page, and check that we get a
    122   // notification for that as well.
    123   auto on_commit_2 = task_runner_->CreateCheckpoint("on_commit_2");
    124   EXPECT_CALL(mock_producer_endpoint_, CommitData(_, _))
    125       .WillOnce(Invoke([on_commit_2](const CommitDataRequest& req,
    126                                      MockProducerEndpoint::CommitDataCallback) {
    127         ASSERT_EQ(1, req.chunks_to_move_size());
    128         ASSERT_EQ(2u, req.chunks_to_move()[0].page());
    129         ASSERT_EQ(0u, req.chunks_to_move()[0].chunk());
    130         ASSERT_EQ(43u, req.chunks_to_move()[0].target_buffer());
    131         on_commit_2();
    132       }));
    133   arbiter_->ReturnCompletedChunk(std::move(chunks[28]), 43, &ignored);
    134   task_runner_->RunUntilCheckpoint("on_commit_2");
    135 }
    136 
    137 // Check that we can actually create up to kMaxWriterID TraceWriter(s).
    138 TEST_P(SharedMemoryArbiterImplTest, WriterIDsAllocation) {
    139   auto checkpoint = task_runner_->CreateCheckpoint("last_unregistered");
    140   int num_unregistered = 0;
    141   {
    142     std::map<WriterID, std::unique_ptr<TraceWriter>> writers;
    143     for (size_t i = 0; i < kMaxWriterID; i++) {
    144       EXPECT_CALL(mock_producer_endpoint_,
    145                   RegisterTraceWriter(static_cast<uint32_t>(i + 1), 0));
    146       EXPECT_CALL(mock_producer_endpoint_,
    147                   UnregisterTraceWriter(static_cast<uint32_t>(i + 1)))
    148           .WillOnce(Invoke([checkpoint, &num_unregistered](uint32_t) {
    149             num_unregistered++;
    150             if (num_unregistered == kMaxWriterID)
    151               checkpoint();
    152           }));
    153 
    154       std::unique_ptr<TraceWriter> writer = arbiter_->CreateTraceWriter(0);
    155       ASSERT_TRUE(writer);
    156       WriterID writer_id = writer->writer_id();
    157       ASSERT_TRUE(writers.emplace(writer_id, std::move(writer)).second);
    158     }
    159 
    160     // A further call should return a null impl of trace writer as we exhausted
    161     // writer IDs.
    162     ASSERT_EQ(arbiter_->CreateTraceWriter(0)->writer_id(), 0);
    163   }
    164 
    165   // This should run the Register/UnregisterTraceWriter calls expected above.
    166   task_runner_->RunUntilCheckpoint("last_unregistered", 15000);
    167 }
    168 
    169 // TODO(primiano): add multi-threaded tests.
    170 
    171 }  // namespace
    172 }  // namespace perfetto
    173