1 //===-- TraceIntelPTGDBRemotePackets.cpp ------------------------*- C++ -*-===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
10 
11 using namespace llvm;
12 using namespace llvm::json;
13 
14 namespace lldb_private {
15 
16 const char *IntelPTDataKinds::kProcFsCpuInfo = "procfsCpuInfo";
17 const char *IntelPTDataKinds::kThreadTraceBuffer = "threadTraceBuffer";
18 
19 bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
20               Path path) {
21   ObjectMapper o(value, path);
22   if (!o || !fromJSON(value, (TraceStartRequest &)packet, path) ||
23       !o.map("enableTsc", packet.enableTsc) ||
24       !o.map("psbPeriod", packet.psbPeriod) ||
25       !o.map("threadBufferSize", packet.threadBufferSize) ||
26       !o.map("processBufferSizeLimit", packet.processBufferSizeLimit))
27     return false;
28   if (packet.tids && packet.processBufferSizeLimit) {
29     path.report("processBufferSizeLimit must be provided");
30     return false;
31   }
32   if (!packet.tids && !packet.processBufferSizeLimit) {
33     path.report("processBufferSizeLimit must not be provided");
34     return false;
35   }
36   return true;
37 }
38 
39 json::Value toJSON(const TraceIntelPTStartRequest &packet) {
40   json::Value base = toJSON((const TraceStartRequest &)packet);
41   base.getAsObject()->try_emplace("threadBufferSize", packet.threadBufferSize);
42   base.getAsObject()->try_emplace("processBufferSizeLimit",
43                                   packet.processBufferSizeLimit);
44   base.getAsObject()->try_emplace("psbPeriod", packet.psbPeriod);
45   base.getAsObject()->try_emplace("enableTsc", packet.enableTsc);
46   return base;
47 }
48 
49 std::chrono::nanoseconds
50 LinuxPerfZeroTscConversion::Convert(uint64_t raw_counter_value) {
51   uint64_t quot = raw_counter_value >> m_time_shift;
52   uint64_t rem_flag = (((uint64_t)1 << m_time_shift) - 1);
53   uint64_t rem = raw_counter_value & rem_flag;
54   return std::chrono::nanoseconds{m_time_zero + quot * m_time_mult +
55                                   ((rem * m_time_mult) >> m_time_shift)};
56 }
57 
58 json::Value LinuxPerfZeroTscConversion::toJSON() {
59   return json::Value(json::Object{
60       {"kind", "tsc-perf-zero-conversion"},
61       {"time_mult", static_cast<int64_t>(m_time_mult)},
62       {"time_shift", static_cast<int64_t>(m_time_shift)},
63       {"time_zero", static_cast<int64_t>(m_time_zero)},
64   });
65 }
66 
67 bool fromJSON(const json::Value &value, TraceTscConversionUP &tsc_conversion,
68               json::Path path) {
69   ObjectMapper o(value, path);
70 
71   int64_t time_mult, time_shift, time_zero;
72   if (!o || !o.map("time_mult", time_mult) ||
73       !o.map("time_shift", time_shift) || !o.map("time_zero", time_zero))
74     return false;
75 
76   tsc_conversion = std::make_unique<LinuxPerfZeroTscConversion>(
77       static_cast<uint32_t>(time_mult), static_cast<uint16_t>(time_shift),
78       static_cast<uint64_t>(time_zero));
79 
80   return true;
81 }
82 
83 bool fromJSON(const json::Value &value, TraceIntelPTGetStateResponse &packet,
84               json::Path path) {
85   ObjectMapper o(value, path);
86   if (!o || !fromJSON(value, (TraceGetStateResponse &)packet, path))
87     return false;
88 
89   const Object &obj = *(value.getAsObject());
90   if (const json::Value *counters = obj.get("counters")) {
91     json::Path subpath = path.field("counters");
92     ObjectMapper ocounters(*counters, subpath);
93     if (!ocounters || !ocounters.mapOptional("tsc-perf-zero-conversion",
94                                              packet.tsc_conversion))
95       return false;
96   }
97   return true;
98 }
99 
100 json::Value toJSON(const TraceIntelPTGetStateResponse &packet) {
101   json::Value base = toJSON((const TraceGetStateResponse &)packet);
102 
103   if (packet.tsc_conversion) {
104     std::vector<json::Value> counters{};
105     base.getAsObject()->try_emplace(
106         "counters", json::Object{{"tsc-perf-zero-conversion",
107                                   packet.tsc_conversion->toJSON()}});
108   }
109 
110   return base;
111 }
112 
113 } // namespace lldb_private
114