Merge "Parse the gfp_flags field based on kernel version"
diff --git a/Android.bp b/Android.bp
index e305328..3cfd830 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4602,6 +4602,7 @@
"src/trace_processor/counter_values_table.cc",
"src/trace_processor/cpu_profile_stack_sample_table.cc",
"src/trace_processor/filtered_row_index.cc",
+ "src/trace_processor/gfp_flags.cc",
"src/trace_processor/heap_profile_allocation_table.cc",
"src/trace_processor/instants_table.cc",
"src/trace_processor/metadata_table.cc",
diff --git a/BUILD b/BUILD
index 08b7942..3da09d1 100644
--- a/BUILD
+++ b/BUILD
@@ -688,6 +688,8 @@
"src/trace_processor/cpu_profile_stack_sample_table.h",
"src/trace_processor/filtered_row_index.cc",
"src/trace_processor/filtered_row_index.h",
+ "src/trace_processor/gfp_flags.cc",
+ "src/trace_processor/gfp_flags.h",
"src/trace_processor/heap_profile_allocation_table.cc",
"src/trace_processor/heap_profile_allocation_table.h",
"src/trace_processor/instants_table.cc",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index a096cd2..0cd6ff5 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -242,6 +242,8 @@
"cpu_profile_stack_sample_table.h",
"filtered_row_index.cc",
"filtered_row_index.h",
+ "gfp_flags.cc",
+ "gfp_flags.h",
"heap_profile_allocation_table.cc",
"heap_profile_allocation_table.h",
"instants_table.cc",
diff --git a/src/trace_processor/gfp_flags.cc b/src/trace_processor/gfp_flags.cc
new file mode 100644
index 0000000..2d5b587
--- /dev/null
+++ b/src/trace_processor/gfp_flags.cc
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+#include "src/trace_processor/gfp_flags.h"
+#include <array>
+
+namespace perfetto {
+namespace trace_processor {
+
+namespace {
+
+struct Flag {
+ uint64_t mask;
+ const char* flag_name;
+};
+
+using FlagArray = std::array<Flag, 37>;
+
+constexpr FlagArray v3_4 = {
+ {{(((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)) |
+ (0x4000u) | (0x10000u) | (0x1000u) | (0x200u) | (0x400000u)),
+ "GFP_TRANSHUGE"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)),
+ "GFP_HIGHUSER_MOVABLE"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u)), "GFP_HIGHUSER"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x20000u)), "GFP_USER"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x80000u)), "GFP_TEMPORARY"},
+ {((0x10u) | (0x40u) | (0x80u)), "GFP_KERNEL"},
+ {((0x10u) | (0x40u)), "GFP_NOFS"},
+ {((0x20u)), "GFP_ATOMIC"},
+ {((0x10u)), "GFP_NOIO"},
+ {(0x20u), "GFP_HIGH"},
+ {(0x10u), "GFP_WAIT"},
+ {(0x40u), "GFP_IO"},
+ {(0x100u), "GFP_COLD"},
+ {(0x200u), "GFP_NOWARN"},
+ {(0x400u), "GFP_REPEAT"},
+ {(0x800u), "GFP_NOFAIL"},
+ {(0x1000u), "GFP_NORETRY"},
+ {(0x4000u), "GFP_COMP"},
+ {(0x8000u), "GFP_ZERO"},
+ {(0x10000u), "GFP_NOMEMALLOC"},
+ {(0x20000u), "GFP_HARDWALL"},
+ {(0x40000u), "GFP_THISNODE"},
+ {(0x80000u), "GFP_RECLAIMABLE"},
+ {(0x08u), "GFP_MOVABLE"},
+ {(0), "GFP_NOTRACK"},
+ {(0x400000u), "GFP_NO_KSWAPD"},
+ {(0x800000u), "GFP_OTHER_NODE"},
+ {0, nullptr}}};
+
+constexpr FlagArray v3_10 = {
+ {{(((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)) |
+ (0x4000u) | (0x10000u) | (0x1000u) | (0x200u) | (0x400000u)),
+ "GFP_TRANSHUGE"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)),
+ "GFP_HIGHUSER_MOVABLE"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u)), "GFP_HIGHUSER"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x20000u)), "GFP_USER"},
+ {((0x10u) | (0x40u) | (0x80u) | (0x80000u)), "GFP_TEMPORARY"},
+ {((0x10u) | (0x40u) | (0x80u)), "GFP_KERNEL"},
+ {((0x10u) | (0x40u)), "GFP_NOFS"},
+ {((0x20u)), "GFP_ATOMIC"},
+ {((0x10u)), "GFP_NOIO"},
+ {(0x20u), "GFP_HIGH"},
+ {(0x10u), "GFP_WAIT"},
+ {(0x40u), "GFP_IO"},
+ {(0x100u), "GFP_COLD"},
+ {(0x200u), "GFP_NOWARN"},
+ {(0x400u), "GFP_REPEAT"},
+ {(0x800u), "GFP_NOFAIL"},
+ {(0x1000u), "GFP_NORETRY"},
+ {(0x4000u), "GFP_COMP"},
+ {(0x8000u), "GFP_ZERO"},
+ {(0x10000u), "GFP_NOMEMALLOC"},
+ {(0x2000u), "GFP_MEMALLOC"},
+ {(0x20000u), "GFP_HARDWALL"},
+ {(0x40000u), "GFP_THISNODE"},
+ {(0x80000u), "GFP_RECLAIMABLE"},
+ {(0x100000u), "GFP_KMEMCG"},
+ {(0x08u), "GFP_MOVABLE"},
+ {(0x200000u), "GFP_NOTRACK"},
+ {(0x400000u), "GFP_NO_KSWAPD"},
+ {(0x800000u), "GFP_OTHER_NODE"},
+ {0, nullptr}}};
+
+constexpr FlagArray v4_4 = {
+ {{(((((((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
+ (0x02u)) |
+ (0x08u)) |
+ (0x4000u) | (0x10000u) | (0x1000u) | (0x200u)) &
+ ~(0x2000000u)),
+ "GFP_TRANSHUGE"},
+ {(((((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
+ (0x02u)) |
+ (0x08u)),
+ "GFP_HIGHUSER_MOVABLE"},
+ {((((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)) | (0x02u)),
+ "GFP_HIGHUSER"},
+ {(((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)),
+ "GFP_USER"},
+ {(((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x10u)),
+ "GFP_TEMPORARY"},
+ {(((0x400000u | 0x2000000u)) | (0x40u) | (0x80u)), "GFP_KERNEL"},
+ {(((0x400000u | 0x2000000u)) | (0x40u)), "GFP_NOFS"},
+ {((0x20u) | (0x80000u) | (0x2000000u)), "GFP_ATOMIC"},
+ {(((0x400000u | 0x2000000u))), "GFP_NOIO"},
+ {(0x20u), "GFP_HIGH"},
+ {(0x80000u), "GFP_ATOMIC"},
+ {(0x40u), "GFP_IO"},
+ {(0x100u), "GFP_COLD"},
+ {(0x200u), "GFP_NOWARN"},
+ {(0x400u), "GFP_REPEAT"},
+ {(0x800u), "GFP_NOFAIL"},
+ {(0x1000u), "GFP_NORETRY"},
+ {(0x4000u), "GFP_COMP"},
+ {(0x8000u), "GFP_ZERO"},
+ {(0x10000u), "GFP_NOMEMALLOC"},
+ {(0x2000u), "GFP_MEMALLOC"},
+ {(0x20000u), "GFP_HARDWALL"},
+ {(0x40000u), "GFP_THISNODE"},
+ {(0x10u), "GFP_RECLAIMABLE"},
+ {(0x08u), "GFP_MOVABLE"},
+ {(0x200000u), "GFP_NOTRACK"},
+ {(0x400000u), "GFP_DIRECT_RECLAIM"},
+ {(0x2000000u), "GFP_KSWAPD_RECLAIM"},
+ {(0x800000u), "GFP_OTHER_NODE"},
+ {0, nullptr}}};
+
+constexpr FlagArray v4_14 = {
+ {{((((((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
+ (0x02u)) |
+ (0x08u)) |
+ (0x4000u) | (0x10000u) | (0x200u)) &
+ ~((0x400000u | 0x1000000u))) |
+ (0x400000u)),
+ "GFP_TRANSHUGE"},
+ {(((((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
+ (0x02u)) |
+ (0x08u)) |
+ (0x4000u) | (0x10000u) | (0x200u)) &
+ ~((0x400000u | 0x1000000u))),
+ "GFP_TRANSHUGE_LIGHT"},
+ {(((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
+ (0x02u)) |
+ (0x08u)),
+ "GFP_HIGHUSER_MOVABLE"},
+ {((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) | (0x02u)),
+ "GFP_HIGHUSER"},
+ {(((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)),
+ "GFP_USER"},
+ {((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u)) | (0x100000u)),
+ "GFP_KERNEL_ACCOUNT"},
+ {(((0x400000u | 0x1000000u)) | (0x40u) | (0x80u)), "GFP_KERNEL"},
+ {(((0x400000u | 0x1000000u)) | (0x40u)), "GFP_NOFS"},
+ {((0x20u) | (0x80000u) | (0x1000000u)), "GFP_ATOMIC"},
+ {(((0x400000u | 0x1000000u))), "GFP_NOIO"},
+ {((0x1000000u)), "GFP_NOWAIT"},
+ {(0x01u), "GFP_DMA"},
+ {(0x02u), "__GFP_HIGHMEM"},
+ {(0x04u), "GFP_DMA32"},
+ {(0x20u), "__GFP_HIGH"},
+ {(0x80000u), "__GFP_ATOMIC"},
+ {(0x40u), "__GFP_IO"},
+ {(0x80u), "__GFP_FS"},
+ {(0x100u), "__GFP_COLD"},
+ {(0x200u), "__GFP_NOWARN"},
+ {(0x400u), "__GFP_RETRY_MAYFAIL"},
+ {(0x800u), "__GFP_NOFAIL"},
+ {(0x1000u), "__GFP_NORETRY"},
+ {(0x4000u), "__GFP_COMP"},
+ {(0x8000u), "__GFP_ZERO"},
+ {(0x10000u), "__GFP_NOMEMALLOC"},
+ {(0x2000u), "__GFP_MEMALLOC"},
+ {(0x20000u), "__GFP_HARDWALL"},
+ {(0x40000u), "__GFP_THISNODE"},
+ {(0x10u), "__GFP_RECLAIMABLE"},
+ {(0x08u), "__GFP_MOVABLE"},
+ {(0x100000u), "__GFP_ACCOUNT"},
+ {(0x800000u), "__GFP_WRITE"},
+ {((0x400000u | 0x1000000u)), "__GFP_RECLAIM"},
+ {(0x400000u), "__GFP_DIRECT_RECLAIM"},
+ {(0x1000000u), "__GFP_KSWAPD_RECLAIM"},
+ {0, nullptr}}};
+
+// Get the bitmask closest to the kernel version. For versions less than 3.4
+// and greater than 4.14 this may end up being inaccurate.
+const FlagArray* GetBitmaskVersion(std::tuple<int32_t, int32_t> version) {
+ if (version < std::make_tuple(3, 10)) {
+ return &v3_4;
+ } else if (version >= std::make_tuple(3, 10) &&
+ version < std::make_tuple(4, 4)) {
+ return &v3_10;
+ } else if (version >= std::make_tuple(4, 4) &&
+ version < std::make_tuple(4, 14)) {
+ return &v4_4;
+ } else { // version >= 4.14
+ // TODO(taylori): Add newer kernel versions once we have access to them.
+ return &v4_14;
+ }
+}
+} // namespace
+
+void WriteGfpFlag(uint64_t value,
+ std::tuple<uint32_t, uint32_t> version,
+ base::StringWriter* writer) {
+ // On all kernel versions if this flag is not set, return GFP_NOWAIT.
+ if (value == 0)
+ writer->AppendString("GFP_NOWAIT");
+
+ std::string result;
+ const FlagArray* bitmasks = GetBitmaskVersion(version);
+
+ // Based on trace_print_flags_seq() in the kernel.
+ size_t i = 0;
+ while (bitmasks->at(i).flag_name != nullptr) {
+ size_t current = i++;
+ uint64_t mask = bitmasks->at(current).mask;
+ const char* str = bitmasks->at(current).flag_name;
+
+ if ((value & mask) != mask)
+ continue;
+ value &= ~mask;
+
+ result += str;
+ result += "|";
+ }
+
+ // Add any leftover flags.
+ if (value) {
+ writer->AppendString(result.c_str(), result.size());
+ writer->AppendString("0x", 2);
+ writer->AppendHexInt(value);
+ } else {
+ writer->AppendString(result.c_str(), result.size() - 1);
+ }
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/gfp_flags.h b/src/trace_processor/gfp_flags.h
new file mode 100644
index 0000000..05e3bdf
--- /dev/null
+++ b/src/trace_processor/gfp_flags.h
@@ -0,0 +1,35 @@
+/*
+ * 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_GFP_FLAGS_H_
+#define SRC_TRACE_PROCESSOR_GFP_FLAGS_H_
+
+#include "perfetto/ext/base/string_writer.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// GFP flags in ftrace events should be parsed and read differently depending
+// the kernel version. This function writes a human readable version of the
+// flag.
+void WriteGfpFlag(uint64_t value,
+ std::tuple<uint32_t, uint32_t> version,
+ base::StringWriter* writer);
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_GFP_FLAGS_H_
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index e93578c..7efcc6e 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -20,6 +20,7 @@
#include "perfetto/ext/traced/sys_stats_counters.h"
#include "perfetto/protozero/proto_decoder.h"
#include "src/trace_processor/event_tracker.h"
+#include "src/trace_processor/metadata.h"
#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/syscall_tracker.h"
#include "src/trace_processor/trace_processor_context.h"
@@ -296,6 +297,24 @@
} else {
PERFETTO_ELOG("Unknown architecture %s", machine.ToStdString().c_str());
}
+
+ StringPool::Id sysname_id =
+ context_->storage->InternString(utsname.sysname());
+ StringPool::Id version_id =
+ context_->storage->InternString(utsname.version());
+ StringPool::Id release_id =
+ context_->storage->InternString(utsname.release());
+ StringPool::Id machine_id =
+ context_->storage->InternString(utsname.machine());
+
+ context_->storage->SetMetadata(metadata::system_name,
+ Variadic::String(sysname_id));
+ context_->storage->SetMetadata(metadata::system_version,
+ Variadic::String(version_id));
+ context_->storage->SetMetadata(metadata::system_release,
+ Variadic::String(release_id));
+ context_->storage->SetMetadata(metadata::system_machine,
+ Variadic::String(machine_id));
}
}
diff --git a/src/trace_processor/metadata.h b/src/trace_processor/metadata.h
index b5bef83..7faa8bc 100644
--- a/src/trace_processor/metadata.h
+++ b/src/trace_processor/metadata.h
@@ -40,7 +40,11 @@
F(benchmark_story_tags, kMulti, Variadic::kString), \
F(android_packages_list, kMulti, Variadic::kInt), \
F(statsd_triggering_subscription_id, kSingle, Variadic::kInt), \
- F(trace_uuid, kSingle, Variadic::kString)
+ F(trace_uuid, kSingle, Variadic::kString), \
+ F(system_name, kSingle, Variadic::kString), \
+ F(system_version, kSingle, Variadic::kString), \
+ F(system_release, kSingle, Variadic::kString), \
+ F(system_machine, kSingle, Variadic::kString)
// clang-format on
enum KeyType {
diff --git a/src/trace_processor/raw_table.cc b/src/trace_processor/raw_table.cc
index b4c2969..2b049f8 100644
--- a/src/trace_processor/raw_table.cc
+++ b/src/trace_processor/raw_table.cc
@@ -19,6 +19,8 @@
#include <inttypes.h>
#include "perfetto/base/compiler.h"
+#include "perfetto/ext/base/string_utils.h"
+#include "src/trace_processor/gfp_flags.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/variadic.h"
@@ -33,6 +35,21 @@
namespace perfetto {
namespace trace_processor {
+namespace {
+std::tuple<uint32_t, uint32_t> ParseKernelReleaseVersion(
+ base::StringView system_release) {
+ size_t first_dot_pos = system_release.find(".");
+ size_t second_dot_pos = system_release.find(".", first_dot_pos + 1);
+ auto major_version = base::StringToUInt32(
+ system_release.substr(0, first_dot_pos).ToStdString());
+ auto minor_version = base::StringToUInt32(
+ system_release
+ .substr(first_dot_pos + 1, second_dot_pos - (first_dot_pos + 1))
+ .ToStdString());
+ return std::make_tuple(major_version.value(), minor_version.value());
+}
+} // namespace
+
RawTable::RawTable(sqlite3* db, const TraceStorage* storage)
: storage_(storage) {
#if PERFETTO_BUILDFLAG(PERFETTO_TP_FTRACE)
@@ -83,6 +100,27 @@
}
#if PERFETTO_BUILDFLAG(PERFETTO_TP_FTRACE)
+bool RawTable::ParseGfpFlags(Variadic value, base::StringWriter* writer) {
+ if (!storage_->metadata().MetadataExists(metadata::KeyIDs::system_name) ||
+ !storage_->metadata().MetadataExists(metadata::KeyIDs::system_release)) {
+ return false;
+ }
+
+ const Variadic& name =
+ storage_->metadata().GetScalarMetadata(metadata::KeyIDs::system_name);
+ base::StringView system_name = storage_->GetString(name.string_value);
+ if (system_name != "Linux")
+ return false;
+
+ const Variadic& release =
+ storage_->metadata().GetScalarMetadata(metadata::KeyIDs::system_release);
+ base::StringView system_release = storage_->GetString(release.string_value);
+ auto version = ParseKernelReleaseVersion(system_release);
+
+ WriteGfpFlag(value.uint_value, version, writer);
+ return true;
+}
+
void RawTable::FormatSystraceArgs(NullTermStringView event_name,
ArgSetId arg_set_id,
base::StringWriter* writer) {
@@ -131,12 +169,17 @@
uint32_t arg_row = start_row + arg_idx;
const auto& args = storage_->args();
const auto& key = storage_->GetString(args.keys()[arg_row]);
- const auto& value = args.arg_values()[arg_row];
writer->AppendChar(' ');
writer->AppendString(key.c_str(), key.size());
writer->AppendChar('=');
- value_fn(value);
+
+ if (key == "gfp_flags" &&
+ ParseGfpFlags(args.arg_values()[arg_row], writer)) {
+ return;
+ }
+
+ value_fn(args.arg_values()[arg_row]);
};
if (event_name == "sched_switch") {
diff --git a/src/trace_processor/raw_table.h b/src/trace_processor/raw_table.h
index 690c0ac..480188c 100644
--- a/src/trace_processor/raw_table.h
+++ b/src/trace_processor/raw_table.h
@@ -41,6 +41,7 @@
ArgSetId arg_set_id,
base::StringWriter* writer);
void ToSystrace(sqlite3_context* ctx, int argc, sqlite3_value** argv);
+ bool ParseGfpFlags(Variadic value, base::StringWriter* writer);
#endif // PERFETTO_BUILDFLAG(PERFETTO_TP_FTRACE)
const TraceStorage* const storage_;
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 2d40985..fbae94b 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -754,6 +754,15 @@
return TraceStorage::CreateRowId(kMetadataTable, index);
}
+ const Variadic& GetScalarMetadata(metadata::KeyIDs key) const {
+ PERFETTO_DCHECK(scalar_indices.count(key) == 1);
+ return values_.at(scalar_indices.at(key));
+ }
+
+ bool MetadataExists(metadata::KeyIDs key) const {
+ return scalar_indices.count(key) >= 1;
+ }
+
void OverwriteMetadata(uint32_t index, Variadic value) {
PERFETTO_DCHECK(index < values_.size());
values_[index] = value;