1 /* 2 * Copyright (C) 2019 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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_SYSCALLS_SYSCALL_TRACKER_H_ 18 #define SRC_TRACE_PROCESSOR_IMPORTERS_SYSCALLS_SYSCALL_TRACKER_H_ 19 20 #include <limits> 21 #include <tuple> 22 23 #include "perfetto/ext/base/string_view.h" 24 #include "src/kernel_utils/syscall_table.h" 25 #include "src/trace_processor/containers/bit_vector.h" 26 #include "src/trace_processor/importers/common/event_tracker.h" 27 #include "src/trace_processor/importers/common/slice_tracker.h" 28 #include "src/trace_processor/importers/common/track_tracker.h" 29 #include "src/trace_processor/storage/trace_storage.h" 30 #include "src/trace_processor/types/destructible.h" 31 #include "src/trace_processor/types/trace_processor_context.h" 32 33 namespace perfetto::trace_processor { 34 35 class SyscallTracker : public Destructible { 36 public: 37 SyscallTracker(const SyscallTracker&) = delete; 38 SyscallTracker& operator=(const SyscallTracker&) = delete; 39 ~SyscallTracker() override; GetOrCreate(TraceProcessorContext * context)40 static SyscallTracker* GetOrCreate(TraceProcessorContext* context) { 41 if (!context->syscall_tracker) { 42 context->syscall_tracker.reset(new SyscallTracker(context)); 43 } 44 return static_cast<SyscallTracker*>(context->syscall_tracker.get()); 45 } 46 47 void SetArchitecture(Architecture architecture); 48 49 void Enter(int64_t ts, 50 UniqueTid utid, 51 uint32_t syscall_num, 52 EventTracker::SetArgsCallback args_callback = 53 EventTracker::SetArgsCallback()) { 54 StringId name = SyscallNumberToStringId(syscall_num); 55 if (name.is_null()) 56 return; 57 58 TrackId track_id = context_->track_tracker->InternThreadTrack(utid); 59 60 // sys_rt_sigreturn does not return so should be inserted as an instant 61 // event. See https://github.com/google/perfetto/issues/733 for details. 62 if (name == sys_rt_sigreturn_string_id_) { 63 context_->slice_tracker->Scoped(ts, track_id, kNullStringId, name, 0, 64 args_callback); 65 } else { 66 context_->slice_tracker->Begin(ts, track_id, kNullStringId /* cat */, 67 name, args_callback); 68 } 69 70 if (name == sys_write_string_id_) { 71 if (utid >= in_sys_write_.size()) 72 in_sys_write_.Resize(utid + 1); 73 74 in_sys_write_.Set(utid); 75 } 76 } 77 78 void Exit(int64_t ts, 79 UniqueTid utid, 80 uint32_t syscall_num, 81 EventTracker::SetArgsCallback args_callback = 82 EventTracker::SetArgsCallback()) { 83 StringId name = SyscallNumberToStringId(syscall_num); 84 if (name.is_null()) 85 return; 86 87 if (name == sys_write_string_id_) { 88 if (utid >= in_sys_write_.size()) 89 in_sys_write_.Resize(utid + 1); 90 // Either seeing an exit event without the corresponding entry at the 91 // start of the trace, or the slice was closed by 92 // MaybeTruncateOngoingWriteSlice. 93 if (!in_sys_write_.IsSet(utid)) 94 return; 95 in_sys_write_.Clear(utid); 96 } 97 98 TrackId track_id = context_->track_tracker->InternThreadTrack(utid); 99 context_->slice_tracker->End(ts, track_id, kNullStringId /* cat */, name, 100 args_callback); 101 } 102 103 // Resolves slice nesting issues when the sys_write is for an atrace slice on 104 // android. See callsite for details. MaybeTruncateOngoingWriteSlice(int64_t ts,UniqueTid utid)105 void MaybeTruncateOngoingWriteSlice(int64_t ts, UniqueTid utid) { 106 if (utid >= in_sys_write_.size()) 107 in_sys_write_.Resize(utid + 1); 108 109 if (!in_sys_write_.IsSet(utid)) 110 return; 111 in_sys_write_.Clear(utid); 112 context_->storage->IncrementStats(stats::truncated_sys_write_duration); 113 114 TrackId track_id = context_->track_tracker->InternThreadTrack(utid); 115 context_->slice_tracker->End(ts, track_id, kNullStringId /* cat */, 116 sys_write_string_id_); 117 } 118 119 private: 120 explicit SyscallTracker(TraceProcessorContext*); 121 122 TraceProcessorContext* const context_; 123 SyscallNumberToStringId(uint32_t syscall_num)124 inline StringId SyscallNumberToStringId(uint32_t syscall_num) { 125 if (syscall_num > kMaxSyscalls) 126 return kNullStringId; 127 return arch_syscall_to_string_id_[syscall_num]; 128 } 129 130 // This is table from platform specific syscall number directly to 131 // the relevant StringId (this avoids having to always do two conversions). 132 std::array<StringId, kMaxSyscalls> arch_syscall_to_string_id_{}; 133 StringId sys_write_string_id_ = std::numeric_limits<StringId>::max(); 134 StringId sys_rt_sigreturn_string_id_ = std::numeric_limits<StringId>::max(); 135 // UniqueTids currently in a sys_write syscall. 136 BitVector in_sys_write_; 137 }; 138 139 } // namespace perfetto::trace_processor 140 141 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_SYSCALLS_SYSCALL_TRACKER_H_ 142