forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			267 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- ProfileTest.cpp - XRay Profile unit tests ----------------*- C++ -*-===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
#include "llvm/XRay/Profile.h"
 | 
						|
#include "gmock/gmock.h"
 | 
						|
#include "gtest/gtest.h"
 | 
						|
 | 
						|
#include <numeric>
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace xray {
 | 
						|
namespace {
 | 
						|
 | 
						|
using ::testing::AllOf;
 | 
						|
using ::testing::ElementsAre;
 | 
						|
using ::testing::Eq;
 | 
						|
using ::testing::Field;
 | 
						|
using ::testing::Not;
 | 
						|
using ::testing::Pair;
 | 
						|
using ::testing::UnorderedElementsAre;
 | 
						|
 | 
						|
TEST(ProfileTest, CreateProfile) { Profile P; }
 | 
						|
 | 
						|
TEST(ProfileTest, InternPath) {
 | 
						|
  Profile P;
 | 
						|
  auto Path0 = P.internPath({3, 2, 1});
 | 
						|
  auto Path1 = P.internPath({3, 2, 1});
 | 
						|
  auto Path2 = P.internPath({2, 1});
 | 
						|
  EXPECT_THAT(Path0, Eq(Path1));
 | 
						|
  EXPECT_THAT(Path0, Not(Eq(Path2)));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, ExpandPath) {
 | 
						|
  Profile P;
 | 
						|
  auto PathID = P.internPath({3, 2, 1});
 | 
						|
  auto PathOrError = P.expandPath(PathID);
 | 
						|
  if (!PathOrError)
 | 
						|
    FAIL() << "Error: " << PathOrError.takeError();
 | 
						|
  EXPECT_THAT(PathOrError.get(), ElementsAre(3, 2, 1));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, AddBlocks) {
 | 
						|
  Profile P;
 | 
						|
  // Expect an error on adding empty blocks.
 | 
						|
  EXPECT_TRUE(errorToBool(P.addBlock({})));
 | 
						|
 | 
						|
  // Thread blocks may not be empty.
 | 
						|
  EXPECT_TRUE(errorToBool(P.addBlock({1, {}})));
 | 
						|
 | 
						|
  // Thread blocks with data must succeed.
 | 
						|
  EXPECT_FALSE(errorToBool(P.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{1},
 | 
						|
                     {
 | 
						|
                         {P.internPath({2, 1}), Profile::Data{1, 1000}},
 | 
						|
                         {P.internPath({3, 2, 1}), Profile::Data{10, 100}},
 | 
						|
                     }})));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, CopyProfile) {
 | 
						|
  Profile P0, P1;
 | 
						|
  EXPECT_FALSE(errorToBool(P0.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{1},
 | 
						|
                     {
 | 
						|
                         {P0.internPath({2, 1}), Profile::Data{1, 1000}},
 | 
						|
                         {P0.internPath({3, 2, 1}), Profile::Data{10, 100}},
 | 
						|
                     }})));
 | 
						|
  P1 = P0;
 | 
						|
  EXPECT_THAT(
 | 
						|
      P1, UnorderedElementsAre(AllOf(
 | 
						|
              Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
 | 
						|
              Field(&Profile::Block::PathData,
 | 
						|
                    UnorderedElementsAre(
 | 
						|
                        Pair(P1.internPath({2, 1}),
 | 
						|
                             AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
 | 
						|
                                   Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                         Eq(1000u)))),
 | 
						|
                        Pair(P1.internPath({3, 2, 1}),
 | 
						|
                             AllOf(Field(&Profile::Data::CallCount, Eq(10u)),
 | 
						|
                                   Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                         Eq(100u)))))))));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, MoveProfile) {
 | 
						|
  Profile P0, P1;
 | 
						|
  EXPECT_FALSE(errorToBool(P0.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{1},
 | 
						|
                     {
 | 
						|
                         {P0.internPath({2, 1}), Profile::Data{1, 1000}},
 | 
						|
                         {P0.internPath({3, 2, 1}), Profile::Data{10, 100}},
 | 
						|
                     }})));
 | 
						|
  P1 = std::move(P0);
 | 
						|
  EXPECT_THAT(
 | 
						|
      P1, UnorderedElementsAre(AllOf(
 | 
						|
              Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
 | 
						|
              Field(&Profile::Block::PathData,
 | 
						|
                    UnorderedElementsAre(
 | 
						|
                        Pair(P1.internPath({2, 1}),
 | 
						|
                             AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
 | 
						|
                                   Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                         Eq(1000u)))),
 | 
						|
                        Pair(P1.internPath({3, 2, 1}),
 | 
						|
                             AllOf(Field(&Profile::Data::CallCount, Eq(10u)),
 | 
						|
                                   Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                         Eq(100u)))))))));
 | 
						|
  EXPECT_THAT(P0, UnorderedElementsAre());
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, MergeProfilesByThread) {
 | 
						|
  Profile P0, P1;
 | 
						|
 | 
						|
  // Set up the blocks for two different threads in P0.
 | 
						|
  EXPECT_FALSE(errorToBool(P0.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{1},
 | 
						|
                     {{P0.internPath({2, 1}), Profile::Data{1, 1000}},
 | 
						|
                      {P0.internPath({4, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  EXPECT_FALSE(errorToBool(P0.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{2},
 | 
						|
                     {{P0.internPath({3, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
 | 
						|
  // Set up the blocks for two different threads in P1.
 | 
						|
  EXPECT_FALSE(errorToBool(P1.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{1},
 | 
						|
                     {{P1.internPath({2, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  EXPECT_FALSE(errorToBool(P1.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{2},
 | 
						|
                     {{P1.internPath({3, 1}), Profile::Data{1, 1000}},
 | 
						|
                      {P1.internPath({4, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
 | 
						|
  Profile Merged = mergeProfilesByThread(P0, P1);
 | 
						|
  EXPECT_THAT(
 | 
						|
      Merged,
 | 
						|
      UnorderedElementsAre(
 | 
						|
          // We want to see two threads after the merge.
 | 
						|
          AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
 | 
						|
                Field(&Profile::Block::PathData,
 | 
						|
                      UnorderedElementsAre(
 | 
						|
                          Pair(Merged.internPath({2, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(2000u)))),
 | 
						|
                          Pair(Merged.internPath({4, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(1000u))))))),
 | 
						|
          AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{2})),
 | 
						|
                Field(&Profile::Block::PathData,
 | 
						|
                      UnorderedElementsAre(
 | 
						|
                          Pair(Merged.internPath({3, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(2000u)))),
 | 
						|
                          Pair(Merged.internPath({4, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(1000u)))))))));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, MergeProfilesByStack) {
 | 
						|
  Profile P0, P1;
 | 
						|
  EXPECT_FALSE(errorToBool(P0.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{1},
 | 
						|
                     {{P0.internPath({2, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  EXPECT_FALSE(errorToBool(P1.addBlock(
 | 
						|
      Profile::Block{Profile::ThreadID{2},
 | 
						|
                     {{P1.internPath({2, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
 | 
						|
  Profile Merged = mergeProfilesByStack(P0, P1);
 | 
						|
  EXPECT_THAT(Merged,
 | 
						|
              ElementsAre(AllOf(
 | 
						|
                  // We expect that we lose the ThreadID dimension in this
 | 
						|
                  // algorithm.
 | 
						|
                  Field(&Profile::Block::Thread, Eq(Profile::ThreadID{0})),
 | 
						|
                  Field(&Profile::Block::PathData,
 | 
						|
                        ElementsAre(Pair(
 | 
						|
                            Merged.internPath({2, 1}),
 | 
						|
                            AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
 | 
						|
                                  Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                        Eq(2000u)))))))));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, MergeProfilesByStackAccumulate) {
 | 
						|
  std::vector<Profile> Profiles(3);
 | 
						|
  EXPECT_FALSE(errorToBool(Profiles[0].addBlock(Profile::Block{
 | 
						|
      Profile::ThreadID{1},
 | 
						|
      {{Profiles[0].internPath({2, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  EXPECT_FALSE(errorToBool(Profiles[1].addBlock(Profile::Block{
 | 
						|
      Profile::ThreadID{2},
 | 
						|
      {{Profiles[1].internPath({2, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  EXPECT_FALSE(errorToBool(Profiles[2].addBlock(Profile::Block{
 | 
						|
      Profile::ThreadID{3},
 | 
						|
      {{Profiles[2].internPath({2, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  Profile Merged = std::accumulate(Profiles.begin(), Profiles.end(), Profile(),
 | 
						|
                                   mergeProfilesByStack);
 | 
						|
  EXPECT_THAT(Merged,
 | 
						|
              ElementsAre(AllOf(
 | 
						|
                  // We expect that we lose the ThreadID dimension in this
 | 
						|
                  // algorithm.
 | 
						|
                  Field(&Profile::Block::Thread, Eq(Profile::ThreadID{0})),
 | 
						|
                  Field(&Profile::Block::PathData,
 | 
						|
                        ElementsAre(Pair(
 | 
						|
                            Merged.internPath({2, 1}),
 | 
						|
                            AllOf(Field(&Profile::Data::CallCount, Eq(3u)),
 | 
						|
                                  Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                        Eq(3000u)))))))));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ProfileTest, MergeProfilesByThreadAccumulate) {
 | 
						|
  std::vector<Profile> Profiles(2);
 | 
						|
 | 
						|
  // Set up the blocks for two different threads in Profiles[0].
 | 
						|
  EXPECT_FALSE(errorToBool(Profiles[0].addBlock(Profile::Block{
 | 
						|
      Profile::ThreadID{1},
 | 
						|
      {{Profiles[0].internPath({2, 1}), Profile::Data{1, 1000}},
 | 
						|
       {Profiles[0].internPath({4, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  EXPECT_FALSE(errorToBool(Profiles[0].addBlock(Profile::Block{
 | 
						|
      Profile::ThreadID{2},
 | 
						|
      {{Profiles[0].internPath({3, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
 | 
						|
  // Set up the blocks for two different threads in Profiles[1].
 | 
						|
  EXPECT_FALSE(errorToBool(Profiles[1].addBlock(Profile::Block{
 | 
						|
      Profile::ThreadID{1},
 | 
						|
      {{Profiles[1].internPath({2, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
  EXPECT_FALSE(errorToBool(Profiles[1].addBlock(Profile::Block{
 | 
						|
      Profile::ThreadID{2},
 | 
						|
      {{Profiles[1].internPath({3, 1}), Profile::Data{1, 1000}},
 | 
						|
       {Profiles[1].internPath({4, 1}), Profile::Data{1, 1000}}}})));
 | 
						|
 | 
						|
  Profile Merged = std::accumulate(Profiles.begin(), Profiles.end(), Profile(),
 | 
						|
                                   mergeProfilesByThread);
 | 
						|
  EXPECT_THAT(
 | 
						|
      Merged,
 | 
						|
      UnorderedElementsAre(
 | 
						|
          // We want to see two threads after the merge.
 | 
						|
          AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
 | 
						|
                Field(&Profile::Block::PathData,
 | 
						|
                      UnorderedElementsAre(
 | 
						|
                          Pair(Merged.internPath({2, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(2000u)))),
 | 
						|
                          Pair(Merged.internPath({4, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(1000u))))))),
 | 
						|
          AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{2})),
 | 
						|
                Field(&Profile::Block::PathData,
 | 
						|
                      UnorderedElementsAre(
 | 
						|
                          Pair(Merged.internPath({3, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(2000u)))),
 | 
						|
                          Pair(Merged.internPath({4, 1}),
 | 
						|
                               AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
 | 
						|
                                     Field(&Profile::Data::CumulativeLocalTime,
 | 
						|
                                           Eq(1000u)))))))));
 | 
						|
}
 | 
						|
// FIXME: Add a test creating a Trace and generating a Profile
 | 
						|
// FIXME: Add tests for ranking/sorting profile blocks by dimension
 | 
						|
 | 
						|
} // namespace
 | 
						|
} // namespace xray
 | 
						|
} // namespace llvm
 |