blob: ec5d4c59d1edc18272916b055e146c5ff638b52d [file] [log] [blame]
/*
* 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/systrace_parser.h"
#include "perfetto/ext/base/optional.h"
#include "src/trace_processor/event_tracker.h"
#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/slice_tracker.h"
namespace perfetto {
namespace trace_processor {
SystraceParser::SystraceParser(TraceProcessorContext* ctx)
: context_(ctx), lmk_id_(ctx->storage->InternString("mem.lmk")) {}
void SystraceParser::ParsePrintEvent(int64_t ts,
uint32_t pid,
base::StringView event) {
systrace_utils::SystraceTracePoint point{};
switch (ParseSystraceTracePoint(event, &point)) {
case systrace_utils::SystraceParseResult::kSuccess:
ParseSystracePoint(ts, pid, point);
break;
case systrace_utils::SystraceParseResult::kFailure:
context_->storage->IncrementStats(stats::systrace_parse_failure);
break;
case systrace_utils::SystraceParseResult::kUnsupported:
// Silently ignore unsupported results.
break;
}
}
void SystraceParser::ParseZeroEvent(int64_t ts,
uint32_t pid,
int32_t flag,
base::StringView name,
uint32_t tgid,
int64_t value) {
systrace_utils::SystraceTracePoint point{};
point.name = name;
point.tgid = tgid;
point.value = value;
// The value of these constants can be found in the msm-google kernel.
constexpr int32_t kSystraceEventBegin = 1 << 0;
constexpr int32_t kSystraceEventEnd = 1 << 1;
constexpr int32_t kSystraceEventInt64 = 1 << 2;
if ((flag & kSystraceEventBegin) != 0) {
point.phase = 'B';
} else if ((flag & kSystraceEventEnd) != 0) {
point.phase = 'E';
} else if ((flag & kSystraceEventInt64) != 0) {
point.phase = 'C';
} else {
context_->storage->IncrementStats(stats::systrace_parse_failure);
return;
}
context_->systrace_parser->ParseSystracePoint(ts, pid, point);
}
void SystraceParser::ParseSystracePoint(
int64_t ts,
uint32_t pid,
systrace_utils::SystraceTracePoint point) {
switch (point.phase) {
case 'B': {
StringId name_id = context_->storage->InternString(point.name);
context_->slice_tracker->BeginAndroid(ts, pid, point.tgid, 0 /*cat_id*/,
name_id);
break;
}
case 'E': {
context_->slice_tracker->EndAndroid(ts, pid, point.tgid);
break;
}
case 'S': {
// Currently unsupported.
break;
}
case 'F': {
// Currently unsupported.
break;
}
case 'C': {
// LMK events from userspace are hacked as counter events with the "value"
// of the counter representing the pid of the killed process which is
// reset to 0 once the kill is complete.
// Homogenise this with kernel LMK events as an instant event, ignoring
// the resets to 0.
if (point.name == "kill_one_process") {
auto killed_pid = static_cast<uint32_t>(point.value);
if (killed_pid != 0) {
UniquePid killed_upid =
context_->process_tracker->GetOrCreateProcess(killed_pid);
context_->event_tracker->PushInstant(ts, lmk_id_, 0, killed_upid,
RefType::kRefUpid);
}
// TODO(lalitm): we should not add LMK events to the counters table
// once the UI has support for displaying instants.
}
// This is per upid on purpose. Some counters are pushed from arbitrary
// threads but are really per process.
UniquePid upid =
context_->process_tracker->GetOrCreateProcess(point.tgid);
StringId name_id = context_->storage->InternString(point.name);
context_->event_tracker->PushCounter(ts, point.value, name_id, upid,
RefType::kRefUpid);
}
}
}
} // namespace trace_processor
} // namespace perfetto