blob: a27ab10819c1f8c9722992cbd45ec8d4828c17b6 [file] [log] [blame]
/*
* 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/types/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(VersionNumber version = VersionNumber{4,
4}) {
if (version < VersionNumber{3, 10}) {
return &v3_4;
} else if (version >= VersionNumber{3, 10} && version < VersionNumber{4, 4}) {
return &v3_10;
} else if (version >= VersionNumber{4, 4} && version < VersionNumber{4, 14}) {
return &v4_4;
} else { // version >= 4.14
// TODO(hjd): Add newer kernel versions once we have access to them.
return &v4_14;
}
}
} // namespace
void WriteGfpFlag(uint64_t value,
std::optional<VersionNumber> version,
base::StringWriter* writer) {
// On all kernel versions if this flag is not set, return GFP_NOWAIT.
if (value == 0) {
writer->AppendString("GFP_NOWAIT");
return;
}
std::string result;
const FlagArray* bitmasks = version.has_value()
? GetBitmaskVersion(version.value())
: GetBitmaskVersion();
// 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