| 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::kIptTrace = "iptTrace" ; |
| 18 | const char *IntelPTDataKinds::kPerfContextSwitchTrace = |
| 19 | "perfContextSwitchTrace" ; |
| 20 | |
| 21 | bool TraceIntelPTStartRequest::IsPerCpuTracing() const { |
| 22 | return per_cpu_tracing.value_or(u: false); |
| 23 | } |
| 24 | |
| 25 | json::Value toJSON(const JSONUINT64 &uint64, bool hex) { |
| 26 | if (hex) |
| 27 | return json::Value(formatv(Fmt: "{0:x+}" , Vals: uint64.value)); |
| 28 | else |
| 29 | return json::Value(formatv(Fmt: "{0}" , Vals: uint64.value)); |
| 30 | } |
| 31 | |
| 32 | bool fromJSON(const json::Value &value, JSONUINT64 &uint64, Path path) { |
| 33 | if (std::optional<uint64_t> val = value.getAsUINT64()) { |
| 34 | uint64.value = *val; |
| 35 | return true; |
| 36 | } else if (std::optional<StringRef> val = value.getAsString()) { |
| 37 | if (!val->getAsInteger(/*radix=*/Radix: 0, Result&: uint64.value)) |
| 38 | return true; |
| 39 | path.report(Message: "invalid string number" ); |
| 40 | } |
| 41 | path.report(Message: "invalid number or string number" ); |
| 42 | return false; |
| 43 | } |
| 44 | |
| 45 | bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet, |
| 46 | Path path) { |
| 47 | ObjectMapper o(value, path); |
| 48 | if (!(o && fromJSON(value, packet&: (TraceStartRequest &)packet, path) && |
| 49 | o.map(Prop: "enableTsc" , Out&: packet.enable_tsc) && |
| 50 | o.map(Prop: "psbPeriod" , Out&: packet.psb_period) && |
| 51 | o.map(Prop: "iptTraceSize" , Out&: packet.ipt_trace_size))) |
| 52 | return false; |
| 53 | |
| 54 | if (packet.IsProcessTracing()) { |
| 55 | if (!o.map(Prop: "processBufferSizeLimit" , Out&: packet.process_buffer_size_limit) || |
| 56 | !o.map(Prop: "perCpuTracing" , Out&: packet.per_cpu_tracing) || |
| 57 | !o.map(Prop: "disableCgroupTracing" , Out&: packet.disable_cgroup_filtering)) |
| 58 | return false; |
| 59 | } |
| 60 | return true; |
| 61 | } |
| 62 | |
| 63 | json::Value toJSON(const TraceIntelPTStartRequest &packet) { |
| 64 | json::Value base = toJSON(packet: (const TraceStartRequest &)packet); |
| 65 | json::Object &obj = *base.getAsObject(); |
| 66 | obj.try_emplace(K: "iptTraceSize" , Args: packet.ipt_trace_size); |
| 67 | obj.try_emplace(K: "processBufferSizeLimit" , Args: packet.process_buffer_size_limit); |
| 68 | obj.try_emplace(K: "psbPeriod" , Args: packet.psb_period); |
| 69 | obj.try_emplace(K: "enableTsc" , Args: packet.enable_tsc); |
| 70 | obj.try_emplace(K: "perCpuTracing" , Args: packet.per_cpu_tracing); |
| 71 | obj.try_emplace(K: "disableCgroupTracing" , Args: packet.disable_cgroup_filtering); |
| 72 | return base; |
| 73 | } |
| 74 | |
| 75 | uint64_t LinuxPerfZeroTscConversion::ToNanos(uint64_t tsc) const { |
| 76 | uint64_t quot = tsc >> time_shift; |
| 77 | uint64_t rem_flag = (((uint64_t)1 << time_shift) - 1); |
| 78 | uint64_t rem = tsc & rem_flag; |
| 79 | return time_zero.value + quot * time_mult + ((rem * time_mult) >> time_shift); |
| 80 | } |
| 81 | |
| 82 | uint64_t LinuxPerfZeroTscConversion::ToTSC(uint64_t nanos) const { |
| 83 | uint64_t time = nanos - time_zero.value; |
| 84 | uint64_t quot = time / time_mult; |
| 85 | uint64_t rem = time % time_mult; |
| 86 | return (quot << time_shift) + (rem << time_shift) / time_mult; |
| 87 | } |
| 88 | |
| 89 | json::Value toJSON(const LinuxPerfZeroTscConversion &packet) { |
| 90 | return json::Value(json::Object{ |
| 91 | {.K: "timeMult" , .V: packet.time_mult}, |
| 92 | {.K: "timeShift" , .V: packet.time_shift}, |
| 93 | {.K: "timeZero" , .V: toJSON(uint64: packet.time_zero, /*hex=*/false)}, |
| 94 | }); |
| 95 | } |
| 96 | |
| 97 | bool fromJSON(const json::Value &value, LinuxPerfZeroTscConversion &packet, |
| 98 | json::Path path) { |
| 99 | ObjectMapper o(value, path); |
| 100 | uint64_t time_mult, time_shift; |
| 101 | if (!(o && o.map(Prop: "timeMult" , Out&: time_mult) && o.map(Prop: "timeShift" , Out&: time_shift) && |
| 102 | o.map(Prop: "timeZero" , Out&: packet.time_zero))) |
| 103 | return false; |
| 104 | packet.time_mult = time_mult; |
| 105 | packet.time_shift = time_shift; |
| 106 | return true; |
| 107 | } |
| 108 | |
| 109 | bool fromJSON(const json::Value &value, TraceIntelPTGetStateResponse &packet, |
| 110 | json::Path path) { |
| 111 | ObjectMapper o(value, path); |
| 112 | return o && fromJSON(value, packet&: (TraceGetStateResponse &)packet, path) && |
| 113 | o.map(Prop: "tscPerfZeroConversion" , Out&: packet.tsc_perf_zero_conversion) && |
| 114 | o.map(Prop: "usingCgroupFiltering" , Out&: packet.using_cgroup_filtering); |
| 115 | } |
| 116 | |
| 117 | json::Value toJSON(const TraceIntelPTGetStateResponse &packet) { |
| 118 | json::Value base = toJSON(packet: (const TraceGetStateResponse &)packet); |
| 119 | json::Object &obj = *base.getAsObject(); |
| 120 | obj.insert(E: {.K: "tscPerfZeroConversion" , .V: packet.tsc_perf_zero_conversion}); |
| 121 | obj.insert(E: {.K: "usingCgroupFiltering" , .V: packet.using_cgroup_filtering}); |
| 122 | return base; |
| 123 | } |
| 124 | |
| 125 | } // namespace lldb_private |
| 126 | |