Home | History | Annotate | Download | only in ftrace
      1 /*
      2  * Copyright (C) 2018 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/traced/probes/ftrace/page_pool.h"
     18 
     19 #include <array>
     20 #include <mutex>
     21 #include <random>
     22 #include <thread>
     23 #include <vector>
     24 
     25 #include "gtest/gtest.h"
     26 
     27 namespace perfetto {
     28 namespace {
     29 
     30 TEST(PagePoolTest, SingleThreaded) {
     31   PagePool pool;
     32   for (int i = 0; i < 2; i++)
     33     ASSERT_TRUE(pool.BeginRead().empty());
     34 
     35   for (int repeat = 0; repeat < 3; repeat++) {
     36     for (uint32_t seed = 0; seed < 6; seed++) {
     37       uint8_t* page = pool.BeginWrite();
     38       std::minstd_rand0 rnd_engine(seed);
     39       std::generate(page, page + base::kPageSize, rnd_engine);
     40       // Deliberately make it so pages 3 is overwritten, so we should see only
     41       // pages 0, 1, 2, 4, 5.
     42       if (seed != 3)
     43         pool.EndWrite();
     44     }
     45 
     46     // No write should be visible until the CommitWrittenPages() call.
     47     ASSERT_TRUE(pool.BeginRead().empty());
     48 
     49     pool.CommitWrittenPages();
     50 
     51     auto blocks = pool.BeginRead();
     52     ASSERT_EQ(blocks.size(), 1);
     53     ASSERT_EQ(blocks[0].size(), 5);
     54     for (uint32_t i = 0; i < blocks[0].size(); i++) {
     55       auto seed = std::array<uint32_t, 5>{{0, 1, 2, 4, 5}}[i];
     56       const char* page = reinterpret_cast<const char*>(blocks[0].At(i));
     57       char expected[base::kPageSize];
     58       std::minstd_rand0 rnd_engine(seed);
     59       std::generate(expected, expected + base::kPageSize, rnd_engine);
     60       EXPECT_STREQ(page, expected);
     61     }
     62 
     63     pool.EndRead(std::move(blocks));
     64     ASSERT_EQ(pool.freelist_size_for_testing(), 1);
     65   }
     66 }
     67 
     68 TEST(PagePoolTest, MultiThreaded) {
     69   PagePool pool;
     70 
     71   // Generate some random content.
     72   std::vector<std::string> expected_pages;
     73   std::minstd_rand0 rnd_engine(0);
     74   for (int i = 0; i < 1000; i++) {
     75     expected_pages.emplace_back();
     76     std::string& page = expected_pages.back();
     77     page.resize(base::kPageSize);
     78     std::generate(page.begin(), page.end(), rnd_engine);
     79   }
     80 
     81   auto writer_fn = [&pool, &expected_pages] {
     82     std::minstd_rand0 rnd(0);
     83     for (const std::string& expected_page : expected_pages) {
     84       uint8_t* dst = pool.BeginWrite();
     85       memcpy(dst, expected_page.data(), base::kPageSize);
     86       pool.EndWrite();
     87       if (rnd() % 16 == 0)
     88         pool.CommitWrittenPages();
     89     }
     90     pool.CommitWrittenPages();
     91   };
     92 
     93   auto reader_fn = [&pool, &expected_pages] {
     94     for (size_t page_idx = 0; page_idx < expected_pages.size();) {
     95       auto blocks = pool.BeginRead();
     96       for (const auto& block : blocks) {
     97         for (size_t i = 0; i < block.size(); i++) {
     98           const char* page = reinterpret_cast<const char*>(block.At(i));
     99           EXPECT_EQ(expected_pages[page_idx],
    100                     std::string(page, base::kPageSize));
    101           page_idx++;
    102         }
    103       }
    104       pool.EndRead(std::move(blocks));
    105     }
    106   };
    107 
    108   std::thread writer(writer_fn);
    109   std::thread reader(reader_fn);
    110   writer.join();
    111   reader.join();
    112 }
    113 
    114 }  // namespace
    115 }  // namespace perfetto
    116