1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "trace-test-utils/compare_records.h"
6
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 #include <zircon/assert.h>
12 #include <zircon/syscalls.h>
13
14 #include <fbl/string.h>
15 #include <fbl/string_buffer.h>
16 #include <trace-reader/reader.h>
17 #include <trace-reader/reader_internal.h>
18
19 #include "trace-test-utils/read_records.h"
20 #include "trace-test-utils/squelch.h"
21
22 namespace trace_testing {
23
CompareRecords(const fbl::Vector<trace::Record> & records,size_t start_record,size_t max_num_records,const char * expected)24 bool CompareRecords(const fbl::Vector<trace::Record>& records,
25 size_t start_record, size_t max_num_records,
26 const char* expected) {
27 // Strip out timestamps and other varying data that is not controlled by
28 // the tests.
29 std::unique_ptr<Squelcher> squelcher =
30 Squelcher::Create("([0-9]+/[0-9]+)"
31 "|koid\\(([0-9]+)\\)"
32 "|koid: ([0-9]+)"
33 "|ts: ([0-9]+)"
34 "|(0x[0-9a-f]+)");
35 ZX_DEBUG_ASSERT(squelcher);
36
37 fbl::StringBuffer<16384u> buf;
38 size_t num_recs = 0;
39 for (size_t i = start_record; i < records.size(); ++i) {
40 if (num_recs == max_num_records)
41 break;
42 const auto& record = records[i];
43 fbl::String str = record.ToString();
44 buf.Append(squelcher->Squelch(str.c_str()));
45 buf.Append('\n');
46 ++num_recs;
47 }
48 if (strcmp(buf.c_str(), expected) != 0) {
49 fprintf(stderr, "Records do not match expected contents:\n");
50 fprintf(stderr, "Buffer:\n%s\n", buf.c_str());
51 fprintf(stderr, "Expected:\n%s\n", expected);
52 return false;
53 }
54
55 return true;
56 }
57
ComparePartialBuffer(const fbl::Vector<trace::Record> & records,size_t max_num_records,const char * expected,size_t * out_leading_to_skip)58 bool ComparePartialBuffer(const fbl::Vector<trace::Record>& records,
59 size_t max_num_records, const char* expected,
60 size_t* out_leading_to_skip) {
61 // A valid buffer should at least have the initialization record.
62 if (records.size() == 0) {
63 fprintf(stderr, "expected an initialization record\n");
64 return false;
65 }
66 if (records[0].type() != trace::RecordType::kInitialization) {
67 fprintf(stderr, "expected initialization record\n");
68 return false;
69 }
70 // Sanity check the recorded ticks/seconds.
71 if (records[0].GetInitialization().ticks_per_second != zx_ticks_per_second()) {
72 fprintf(stderr, "Bad ticks/second field in initialization record\n");
73 return false;
74 }
75 // Done with this record, skip it in further analysis.
76 size_t skip_count = 1;
77
78 if (!CompareRecords(records, skip_count, max_num_records, expected)) {
79 // Diagnostic messages already printed.
80 return false;
81 }
82
83 if (out_leading_to_skip) {
84 *out_leading_to_skip = skip_count;
85 }
86
87 return true;
88 }
89
CompareBuffer(const fbl::Vector<trace::Record> & records,const char * expected)90 bool CompareBuffer(const fbl::Vector<trace::Record>& records,
91 const char* expected) {
92 return ComparePartialBuffer(records, SIZE_MAX, expected, nullptr);
93 }
94
95 } // namespace trace_testing
96