| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef SRC_TRACE_PROCESSOR_SYSCALL_TRACKER_H_ |
| #define SRC_TRACE_PROCESSOR_SYSCALL_TRACKER_H_ |
| |
| #include <limits> |
| #include <tuple> |
| |
| #include "perfetto/ext/base/string_view.h" |
| #include "src/trace_processor/destructible.h" |
| #include "src/trace_processor/slice_tracker.h" |
| #include "src/trace_processor/trace_processor_context.h" |
| #include "src/trace_processor/trace_storage.h" |
| #include "src/trace_processor/track_tracker.h" |
| |
| namespace perfetto { |
| namespace trace_processor { |
| |
| static constexpr size_t kMaxSyscalls = 550; |
| |
| enum Architecture { |
| kUnknown = 0, |
| kArmEabi, // 32-bit kernel running a 32-bit process (most old devices). |
| kAarch32, // 64-bit kernel running a 32-bit process (should be rare). |
| kAarch64, // 64-bit kernel running a 64-bit process (most new devices). |
| kX86_64, |
| }; |
| |
| class SyscallTracker : public Destructible { |
| public: |
| explicit SyscallTracker(TraceProcessorContext*); |
| SyscallTracker(const SyscallTracker&) = delete; |
| SyscallTracker& operator=(const SyscallTracker&) = delete; |
| virtual ~SyscallTracker(); |
| static SyscallTracker* GetOrCreate(TraceProcessorContext* context) { |
| if (!context->syscall_tracker) { |
| context->syscall_tracker.reset(new SyscallTracker(context)); |
| } |
| return static_cast<SyscallTracker*>(context->syscall_tracker.get()); |
| } |
| |
| void SetArchitecture(Architecture architecture); |
| |
| void Enter(int64_t ts, UniqueTid utid, uint32_t syscall_num) { |
| StringId name = SyscallNumberToStringId(syscall_num); |
| if (!name.is_null()) { |
| TrackId track_id = context_->track_tracker->InternThreadTrack(utid); |
| context_->slice_tracker->Begin(ts, track_id, 0 /* cat */, name); |
| } |
| } |
| |
| void Exit(int64_t ts, UniqueTid utid, uint32_t syscall_num) { |
| StringId name = SyscallNumberToStringId(syscall_num); |
| if (!name.is_null()) { |
| TrackId track_id = context_->track_tracker->InternThreadTrack(utid); |
| context_->slice_tracker->End(ts, track_id, 0 /* cat */, name); |
| } |
| } |
| |
| private: |
| TraceProcessorContext* const context_; |
| |
| inline StringId SyscallNumberToStringId(uint32_t syscall_num) { |
| if (syscall_num > kMaxSyscalls) |
| return 0; |
| // We see two write sys calls around each userspace slice that is going via |
| // trace_marker, this violates the assumption that userspace slices are |
| // perfectly nested. For the moment ignore all write sys calls. |
| // TODO(hjd): Remove this limitation. |
| StringId id = arch_syscall_to_string_id_[syscall_num]; |
| if (id == sys_write_string_id_) |
| return 0; |
| return id; |
| } |
| |
| // This is table from platform specific syscall number directly to |
| // the relevant StringId (this avoids having to always do two conversions). |
| std::array<StringId, kMaxSyscalls> arch_syscall_to_string_id_{}; |
| StringId sys_write_string_id_ = std::numeric_limits<StringId>::max(); |
| }; |
| |
| } // namespace trace_processor |
| } // namespace perfetto |
| |
| #endif // SRC_TRACE_PROCESSOR_SYSCALL_TRACKER_H_ |