| /* |
| * Copyright (C) 2018 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. |
| */ |
| |
| #include "src/trace_processor/trace_storage.h" |
| |
| #include <string.h> |
| #include <algorithm> |
| #include <limits> |
| |
| #include "perfetto/ext/base/no_destructor.h" |
| |
| namespace perfetto { |
| namespace trace_processor { |
| |
| namespace { |
| |
| template <typename T> |
| void MaybeUpdateMinMax(T begin_it, |
| T end_it, |
| int64_t* min_value, |
| int64_t* max_value) { |
| if (begin_it == end_it) { |
| return; |
| } |
| std::pair<T, T> minmax = std::minmax_element(begin_it, end_it); |
| *min_value = std::min(*min_value, *minmax.first); |
| *max_value = std::max(*max_value, *minmax.second); |
| } |
| |
| std::vector<const char*> CreateRefTypeStringMap() { |
| std::vector<const char*> map(static_cast<size_t>(RefType::kRefMax)); |
| map[static_cast<size_t>(RefType::kRefNoRef)] = nullptr; |
| map[static_cast<size_t>(RefType::kRefUtid)] = "utid"; |
| map[static_cast<size_t>(RefType::kRefCpuId)] = "cpu"; |
| map[static_cast<size_t>(RefType::kRefGpuId)] = "gpu"; |
| map[static_cast<size_t>(RefType::kRefIrq)] = "irq"; |
| map[static_cast<size_t>(RefType::kRefSoftIrq)] = "softirq"; |
| map[static_cast<size_t>(RefType::kRefUpid)] = "upid"; |
| map[static_cast<size_t>(RefType::kRefTrack)] = "track"; |
| return map; |
| } |
| |
| } // namespace |
| |
| const std::vector<const char*>& GetRefTypeStringMap() { |
| static const base::NoDestructor<std::vector<const char*>> map( |
| CreateRefTypeStringMap()); |
| return map.ref(); |
| } |
| |
| TraceStorage::TraceStorage() { |
| // Upid/utid 0 is reserved for idle processes/threads. |
| unique_processes_.emplace_back(0); |
| unique_threads_.emplace_back(0); |
| } |
| |
| TraceStorage::~TraceStorage() {} |
| |
| uint32_t TraceStorage::SqlStats::RecordQueryBegin(const std::string& query, |
| int64_t time_queued, |
| int64_t time_started) { |
| if (queries_.size() >= kMaxLogEntries) { |
| queries_.pop_front(); |
| times_queued_.pop_front(); |
| times_started_.pop_front(); |
| times_first_next_.pop_front(); |
| times_ended_.pop_front(); |
| popped_queries_++; |
| } |
| queries_.push_back(query); |
| times_queued_.push_back(time_queued); |
| times_started_.push_back(time_started); |
| times_first_next_.push_back(0); |
| times_ended_.push_back(0); |
| return static_cast<uint32_t>(popped_queries_ + queries_.size() - 1); |
| } |
| |
| void TraceStorage::SqlStats::RecordQueryFirstNext(uint32_t row, |
| int64_t time_first_next) { |
| // This means we've popped this query off the queue of queries before it had |
| // a chance to finish. Just silently drop this number. |
| if (popped_queries_ > row) |
| return; |
| uint32_t queue_row = row - popped_queries_; |
| PERFETTO_DCHECK(queue_row < queries_.size()); |
| times_first_next_[queue_row] = time_first_next; |
| } |
| |
| void TraceStorage::SqlStats::RecordQueryEnd(uint32_t row, int64_t time_ended) { |
| // This means we've popped this query off the queue of queries before it had |
| // a chance to finish. Just silently drop this number. |
| if (popped_queries_ > row) |
| return; |
| uint32_t queue_row = row - popped_queries_; |
| PERFETTO_DCHECK(queue_row < queries_.size()); |
| times_ended_[queue_row] = time_ended; |
| } |
| |
| std::pair<int64_t, int64_t> TraceStorage::GetTraceTimestampBoundsNs() const { |
| int64_t start_ns = std::numeric_limits<int64_t>::max(); |
| int64_t end_ns = std::numeric_limits<int64_t>::min(); |
| MaybeUpdateMinMax(slices_.start_ns().begin(), slices_.start_ns().end(), |
| &start_ns, &end_ns); |
| MaybeUpdateMinMax(counter_values_.timestamps().begin(), |
| counter_values_.timestamps().end(), &start_ns, &end_ns); |
| MaybeUpdateMinMax(instants_.timestamps().begin(), |
| instants_.timestamps().end(), &start_ns, &end_ns); |
| MaybeUpdateMinMax(nestable_slices_.start_ns().begin(), |
| nestable_slices_.start_ns().end(), &start_ns, &end_ns); |
| MaybeUpdateMinMax(android_log_.timestamps().begin(), |
| android_log_.timestamps().end(), &start_ns, &end_ns); |
| MaybeUpdateMinMax(raw_events_.timestamps().begin(), |
| raw_events_.timestamps().end(), &start_ns, &end_ns); |
| MaybeUpdateMinMax(heap_profile_allocations_.timestamps().begin(), |
| heap_profile_allocations_.timestamps().end(), &start_ns, |
| &end_ns); |
| |
| if (start_ns == std::numeric_limits<int64_t>::max()) { |
| return std::make_pair(0, 0); |
| } |
| if (start_ns == end_ns) { |
| end_ns += 1; |
| } |
| return std::make_pair(start_ns, end_ns); |
| } |
| |
| } // namespace trace_processor |
| } // namespace perfetto |