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