brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 0283388 Raw
207 lines · cpp
1//===-- sanitizer_stackdepot_test.cpp -------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of ThreadSanitizer/AddressSanitizer runtime.10//11//===----------------------------------------------------------------------===//12#include "sanitizer_common/sanitizer_stackdepot.h"13 14#include <algorithm>15#include <atomic>16#include <numeric>17#include <regex>18#include <sstream>19#include <string>20#include <thread>21 22#include "gtest/gtest.h"23#include "sanitizer_common/sanitizer_internal_defs.h"24#include "sanitizer_common/sanitizer_libc.h"25 26namespace __sanitizer {27 28class StackDepotTest : public testing::Test {29 protected:30  void SetUp() override { StackDepotTestOnlyUnmap(); }31  void TearDown() override {32    StackDepotStats stack_depot_stats = StackDepotGetStats();33    Printf("StackDepot: %zd ids; %zdM allocated\n",34           stack_depot_stats.n_uniq_ids, stack_depot_stats.allocated >> 20);35    StackDepotTestOnlyUnmap();36  }37};38 39TEST_F(StackDepotTest, Basic) {40  uptr array[] = {1, 2, 3, 4, 5};41  StackTrace s1(array, ARRAY_SIZE(array));42  u32 i1 = StackDepotPut(s1);43  StackTrace stack = StackDepotGet(i1);44  EXPECT_NE(stack.trace, (uptr*)0);45  EXPECT_EQ(ARRAY_SIZE(array), stack.size);46  EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));47}48 49TEST_F(StackDepotTest, Absent) {50  StackTrace stack = StackDepotGet((1 << 30) - 1);51  EXPECT_EQ((uptr*)0, stack.trace);52}53 54TEST_F(StackDepotTest, EmptyStack) {55  u32 i1 = StackDepotPut(StackTrace());56  StackTrace stack = StackDepotGet(i1);57  EXPECT_EQ((uptr*)0, stack.trace);58}59 60TEST_F(StackDepotTest, ZeroId) {61  StackTrace stack = StackDepotGet(0);62  EXPECT_EQ((uptr*)0, stack.trace);63}64 65TEST_F(StackDepotTest, Same) {66  uptr array[] = {1, 2, 3, 4, 6};67  StackTrace s1(array, ARRAY_SIZE(array));68  u32 i1 = StackDepotPut(s1);69  u32 i2 = StackDepotPut(s1);70  EXPECT_EQ(i1, i2);71  StackTrace stack = StackDepotGet(i1);72  EXPECT_NE(stack.trace, (uptr*)0);73  EXPECT_EQ(ARRAY_SIZE(array), stack.size);74  EXPECT_EQ(0, internal_memcmp(stack.trace, array, sizeof(array)));75}76 77TEST_F(StackDepotTest, Several) {78  uptr array1[] = {1, 2, 3, 4, 7};79  StackTrace s1(array1, ARRAY_SIZE(array1));80  u32 i1 = StackDepotPut(s1);81  uptr array2[] = {1, 2, 3, 4, 8, 9};82  StackTrace s2(array2, ARRAY_SIZE(array2));83  u32 i2 = StackDepotPut(s2);84  EXPECT_NE(i1, i2);85}86 87TEST_F(StackDepotTest, Print) {88  uptr array1[] = {0x111, 0x222, 0x333, 0x444, 0x777};89  StackTrace s1(array1, ARRAY_SIZE(array1));90  u32 i1 = StackDepotPut(s1);91  uptr array2[] = {0x1111, 0x2222, 0x3333, 0x4444, 0x8888, 0x9999};92  StackTrace s2(array2, ARRAY_SIZE(array2));93  u32 i2 = StackDepotPut(s2);94  EXPECT_NE(i1, i2);95 96  auto fix_regex = [](const std::string& s) -> std::string {97    if (!SANITIZER_WINDOWS)98      return s;99    return std::regex_replace(s, std::regex("\\.\\*"), ".*\\n.*");100  };101  EXPECT_EXIT(102      (StackDepotPrintAll(), exit(0)), ::testing::ExitedWithCode(0),103      fix_regex(104          "Stack for id .*#0 0x0*1.*#1 0x0*2.*#2 0x0*3.*#3 0x0*4.*#4 0x0*7.*"));105  EXPECT_EXIT((StackDepotPrintAll(), exit(0)), ::testing::ExitedWithCode(0),106              fix_regex("Stack for id .*#0 0x0*1.*#1 0x0*2.*#2 0x0*3.*#3 "107                        "0x0*4.*#4 0x0*8.*#5 0x0*9.*"));108}109 110TEST_F(StackDepotTest, PrintNoLock) {111  u32 n = 2000;112  std::vector<u32> idx2id(n);113  for (u32 i = 0; i < n; ++i) {114    uptr array[] = {0x111, 0x222, i, 0x444, 0x777};115    StackTrace s(array, ARRAY_SIZE(array));116    idx2id[i] = StackDepotPut(s);117  }118  StackDepotPrintAll();119  for (u32 i = 0; i < n; ++i) {120    uptr array[] = {0x111, 0x222, i, 0x444, 0x777};121    StackTrace s(array, ARRAY_SIZE(array));122    CHECK_EQ(idx2id[i], StackDepotPut(s));123  }124}125 126static struct StackDepotBenchmarkParams {127  int UniqueStacksPerThread;128  int RepeatPerThread;129  int Threads;130  bool UniqueThreads;131  bool UseCount;132} params[] = {133    // All traces are unique, very unusual.134    {10000000, 1, 1, false, false},135    {8000000, 1, 4, false, false},136    {8000000, 1, 16, false, false},137    // Probably most realistic sets.138    {3000000, 10, 1, false, false},139    {3000000, 10, 4, false, false},140    {3000000, 10, 16, false, false},141    // Update use count as msan/dfsan.142    {3000000, 10, 1, false, true},143    {3000000, 10, 4, false, true},144    {3000000, 10, 16, false, true},145    // Unrealistic, as above, but traces are unique inside of thread.146    {4000000, 1, 4, true, false},147    {2000000, 1, 16, true, false},148    {2000000, 10, 4, true, false},149    {500000, 10, 16, true, false},150    {1500000, 10, 4, true, true},151    {800000, 10, 16, true, true},152    // Go crazy, and create too many unique stacks, such that StackStore runs153    // out of space.154    {1000000, 1, 128, true, true},155    {100000000, 1, 1, true, true},156};157 158static std::string PrintStackDepotBenchmarkParams(159    const testing::TestParamInfo<StackDepotBenchmarkParams>& info) {160  std::stringstream name;161  name << info.param.UniqueStacksPerThread << "_" << info.param.RepeatPerThread162       << "_" << info.param.Threads << (info.param.UseCount ? "_UseCount" : "")163       << (info.param.UniqueThreads ? "_UniqueThreads" : "");164  return name.str();165}166 167class StackDepotBenchmark168    : public StackDepotTest,169      public testing::WithParamInterface<StackDepotBenchmarkParams> {};170 171// Test which can be used as a simple benchmark. It's disabled to avoid slowing172// down check-sanitizer.173// Usage: Sanitizer-<ARCH>-Test --gtest_also_run_disabled_tests \174//   '--gtest_filter=*Benchmark*'175TEST_P(StackDepotBenchmark, DISABLED_Benchmark) {176  auto Param = GetParam();177  std::atomic<unsigned int> here = {};178 179  auto thread = [&](int idx) {180    here++;181    while (here < Param.UniqueThreads) std::this_thread::yield();182 183    std::vector<uptr> frames(64);184    for (int r = 0; r < Param.RepeatPerThread; ++r) {185      std::iota(frames.begin(), frames.end(), idx + 1);186      for (int i = 0; i < Param.UniqueStacksPerThread; ++i) {187        StackTrace s(frames.data(), frames.size());188        auto h = StackDepotPut_WithHandle(s);189        if (Param.UseCount)190          h.inc_use_count_unsafe();191        std::next_permutation(frames.begin(), frames.end());192      };193    }194  };195 196  std::vector<std::thread> threads;197  for (int i = 0; i < Param.Threads; ++i)198    threads.emplace_back(thread, Param.UniqueThreads * i);199  for (auto& t : threads) t.join();200}201 202INSTANTIATE_TEST_SUITE_P(StackDepotBenchmarkSuite, StackDepotBenchmark,203                         testing::ValuesIn(params),204                         PrintStackDepotBenchmarkParams);205 206}  // namespace __sanitizer207