1/*
2 * Copyright (C) 2015 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 <gtest/gtest.h>
18
19#include <string.h>
20
21#include <memory>
22
23#include <android-base/test_utils.h>
24
25#include "environment.h"
26#include "event_attr.h"
27#include "event_type.h"
28#include "record.h"
29#include "record_file.h"
30
31#include "record_equal_test.h"
32
33using namespace PerfFileFormat;
34
35class RecordFileTest : public ::testing::Test {
36 protected:
37  void AddEventType(const std::string& event_type_str) {
38    std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_str);
39    ASSERT_TRUE(event_type_modifier != nullptr);
40    perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
41    attr.sample_id_all = 1;
42    attrs_.push_back(std::unique_ptr<perf_event_attr>(new perf_event_attr(attr)));
43    EventAttrWithId attr_id;
44    attr_id.attr = attrs_.back().get();
45    attr_id.ids.push_back(attrs_.size());  // Fake id.
46    attr_ids_.push_back(attr_id);
47  }
48
49  TemporaryFile tmpfile_;
50  std::vector<std::unique_ptr<perf_event_attr>> attrs_;
51  std::vector<EventAttrWithId> attr_ids_;
52};
53
54TEST_F(RecordFileTest, smoke) {
55  // Write to a record file.
56  std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
57  ASSERT_TRUE(writer != nullptr);
58
59  // Write attr section.
60  AddEventType("cpu-cycles");
61  ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
62
63  // Write data section.
64  MmapRecord mmap_record(*(attr_ids_[0].attr), true, 1, 1, 0x1000, 0x2000,
65                         0x3000, "mmap_record_example", attr_ids_[0].ids[0]);
66  ASSERT_TRUE(writer->WriteRecord(mmap_record));
67
68  // Write feature section.
69  ASSERT_TRUE(writer->BeginWriteFeatures(1));
70  char p[BuildId::Size()];
71  for (size_t i = 0; i < BuildId::Size(); ++i) {
72    p[i] = i;
73  }
74  BuildId build_id(p);
75  std::vector<BuildIdRecord> build_id_records;
76  build_id_records.push_back(BuildIdRecord(false, getpid(), build_id, "init"));
77  ASSERT_TRUE(writer->WriteBuildIdFeature(build_id_records));
78  ASSERT_TRUE(writer->EndWriteFeatures());
79  ASSERT_TRUE(writer->Close());
80
81  // Read from a record file.
82  std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
83  ASSERT_TRUE(reader != nullptr);
84  std::vector<EventAttrWithId> attrs = reader->AttrSection();
85  ASSERT_EQ(1u, attrs.size());
86  ASSERT_EQ(0, memcmp(attrs[0].attr, attr_ids_[0].attr, sizeof(perf_event_attr)));
87  ASSERT_EQ(attrs[0].ids, attr_ids_[0].ids);
88
89  // Read and check data section.
90  std::vector<std::unique_ptr<Record>> records = reader->DataSection();
91  ASSERT_EQ(1u, records.size());
92  CheckRecordEqual(mmap_record, *records[0]);
93
94  // Read and check feature section.
95  std::vector<BuildIdRecord> read_build_id_records = reader->ReadBuildIdFeature();
96  ASSERT_EQ(1u, read_build_id_records.size());
97  CheckRecordEqual(read_build_id_records[0], build_id_records[0]);
98
99  ASSERT_TRUE(reader->Close());
100}
101
102TEST_F(RecordFileTest, records_sorted_by_time) {
103  // Write to a record file.
104  std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
105  ASSERT_TRUE(writer != nullptr);
106
107  // Write attr section.
108  AddEventType("cpu-cycles");
109  attrs_[0]->sample_id_all = 1;
110  attrs_[0]->sample_type |= PERF_SAMPLE_TIME;
111  ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
112
113  // Write data section.
114  MmapRecord r1(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1",
115                attr_ids_[0].ids[0], 2);
116  MmapRecord r2(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1",
117                attr_ids_[0].ids[0], 1);
118  MmapRecord r3(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1",
119                attr_ids_[0].ids[0], 3);
120  ASSERT_TRUE(writer->WriteRecord(r1));
121  ASSERT_TRUE(writer->WriteRecord(r2));
122  ASSERT_TRUE(writer->WriteRecord(r3));
123  ASSERT_TRUE(writer->Close());
124
125  // Read from a record file.
126  std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
127  ASSERT_TRUE(reader != nullptr);
128  std::vector<std::unique_ptr<Record>> records = reader->DataSection();
129  ASSERT_EQ(3u, records.size());
130  CheckRecordEqual(r2, *records[0]);
131  CheckRecordEqual(r1, *records[1]);
132  CheckRecordEqual(r3, *records[2]);
133
134  ASSERT_TRUE(reader->Close());
135}
136
137TEST_F(RecordFileTest, record_more_than_one_attr) {
138  // Write to a record file.
139  std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
140  ASSERT_TRUE(writer != nullptr);
141
142  // Write attr section.
143  AddEventType("cpu-cycles");
144  AddEventType("cpu-clock");
145  AddEventType("task-clock");
146  ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
147
148  ASSERT_TRUE(writer->Close());
149
150  // Read from a record file.
151  std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
152  ASSERT_TRUE(reader != nullptr);
153  std::vector<EventAttrWithId> attrs = reader->AttrSection();
154  ASSERT_EQ(3u, attrs.size());
155  for (size_t i = 0; i < attrs.size(); ++i) {
156    ASSERT_EQ(0, memcmp(attrs[i].attr, attr_ids_[i].attr, sizeof(perf_event_attr)));
157    ASSERT_EQ(attrs[i].ids, attr_ids_[i].ids);
158  }
159}
160
161TEST_F(RecordFileTest, write_meta_info_feature_section) {
162  // Write to a record file.
163  std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
164  ASSERT_TRUE(writer != nullptr);
165  AddEventType("cpu-cycles");
166  ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
167
168  // Write meta_info feature section.
169  ASSERT_TRUE(writer->BeginWriteFeatures(1));
170  std::unordered_map<std::string, std::string> info_map;
171  for (int i = 0; i < 100; ++i) {
172    std::string s = std::to_string(i);
173    info_map[s] = s + s;
174  }
175  ASSERT_TRUE(writer->WriteMetaInfoFeature(info_map));
176  ASSERT_TRUE(writer->EndWriteFeatures());
177  ASSERT_TRUE(writer->Close());
178
179  // Read from a record file.
180  std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
181  ASSERT_TRUE(reader != nullptr);
182  std::unordered_map<std::string, std::string> read_info_map;
183  ASSERT_TRUE(reader->ReadMetaInfoFeature(&read_info_map));
184  ASSERT_EQ(read_info_map, info_map);
185}
186