1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/types/gfp_flags.h"
18
19 #include <array>
20
21 namespace perfetto {
22 namespace trace_processor {
23
24 namespace {
25
26 struct Flag {
27 uint64_t mask;
28 const char* flag_name;
29 };
30
31 using FlagArray = std::array<Flag, 37>;
32
33 constexpr FlagArray v3_4 = {
34 {{(((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)) |
35 (0x4000u) | (0x10000u) | (0x1000u) | (0x200u) | (0x400000u)),
36 "GFP_TRANSHUGE"},
37 {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)),
38 "GFP_HIGHUSER_MOVABLE"},
39 {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u)), "GFP_HIGHUSER"},
40 {((0x10u) | (0x40u) | (0x80u) | (0x20000u)), "GFP_USER"},
41 {((0x10u) | (0x40u) | (0x80u) | (0x80000u)), "GFP_TEMPORARY"},
42 {((0x10u) | (0x40u) | (0x80u)), "GFP_KERNEL"},
43 {((0x10u) | (0x40u)), "GFP_NOFS"},
44 {((0x20u)), "GFP_ATOMIC"},
45 {((0x10u)), "GFP_NOIO"},
46 {(0x20u), "GFP_HIGH"},
47 {(0x10u), "GFP_WAIT"},
48 {(0x40u), "GFP_IO"},
49 {(0x100u), "GFP_COLD"},
50 {(0x200u), "GFP_NOWARN"},
51 {(0x400u), "GFP_REPEAT"},
52 {(0x800u), "GFP_NOFAIL"},
53 {(0x1000u), "GFP_NORETRY"},
54 {(0x4000u), "GFP_COMP"},
55 {(0x8000u), "GFP_ZERO"},
56 {(0x10000u), "GFP_NOMEMALLOC"},
57 {(0x20000u), "GFP_HARDWALL"},
58 {(0x40000u), "GFP_THISNODE"},
59 {(0x80000u), "GFP_RECLAIMABLE"},
60 {(0x08u), "GFP_MOVABLE"},
61 {(0), "GFP_NOTRACK"},
62 {(0x400000u), "GFP_NO_KSWAPD"},
63 {(0x800000u), "GFP_OTHER_NODE"},
64 {0, nullptr}}};
65
66 constexpr FlagArray v3_10 = {
67 {{(((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)) |
68 (0x4000u) | (0x10000u) | (0x1000u) | (0x200u) | (0x400000u)),
69 "GFP_TRANSHUGE"},
70 {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u) | (0x08u)),
71 "GFP_HIGHUSER_MOVABLE"},
72 {((0x10u) | (0x40u) | (0x80u) | (0x20000u) | (0x02u)), "GFP_HIGHUSER"},
73 {((0x10u) | (0x40u) | (0x80u) | (0x20000u)), "GFP_USER"},
74 {((0x10u) | (0x40u) | (0x80u) | (0x80000u)), "GFP_TEMPORARY"},
75 {((0x10u) | (0x40u) | (0x80u)), "GFP_KERNEL"},
76 {((0x10u) | (0x40u)), "GFP_NOFS"},
77 {((0x20u)), "GFP_ATOMIC"},
78 {((0x10u)), "GFP_NOIO"},
79 {(0x20u), "GFP_HIGH"},
80 {(0x10u), "GFP_WAIT"},
81 {(0x40u), "GFP_IO"},
82 {(0x100u), "GFP_COLD"},
83 {(0x200u), "GFP_NOWARN"},
84 {(0x400u), "GFP_REPEAT"},
85 {(0x800u), "GFP_NOFAIL"},
86 {(0x1000u), "GFP_NORETRY"},
87 {(0x4000u), "GFP_COMP"},
88 {(0x8000u), "GFP_ZERO"},
89 {(0x10000u), "GFP_NOMEMALLOC"},
90 {(0x2000u), "GFP_MEMALLOC"},
91 {(0x20000u), "GFP_HARDWALL"},
92 {(0x40000u), "GFP_THISNODE"},
93 {(0x80000u), "GFP_RECLAIMABLE"},
94 {(0x100000u), "GFP_KMEMCG"},
95 {(0x08u), "GFP_MOVABLE"},
96 {(0x200000u), "GFP_NOTRACK"},
97 {(0x400000u), "GFP_NO_KSWAPD"},
98 {(0x800000u), "GFP_OTHER_NODE"},
99 {0, nullptr}}};
100
101 constexpr FlagArray v4_4 = {
102 {{(((((((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
103 (0x02u)) |
104 (0x08u)) |
105 (0x4000u) | (0x10000u) | (0x1000u) | (0x200u)) &
106 ~(0x2000000u)),
107 "GFP_TRANSHUGE"},
108 {(((((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
109 (0x02u)) |
110 (0x08u)),
111 "GFP_HIGHUSER_MOVABLE"},
112 {((((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)) | (0x02u)),
113 "GFP_HIGHUSER"},
114 {(((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x20000u)),
115 "GFP_USER"},
116 {(((0x400000u | 0x2000000u)) | (0x40u) | (0x80u) | (0x10u)),
117 "GFP_TEMPORARY"},
118 {(((0x400000u | 0x2000000u)) | (0x40u) | (0x80u)), "GFP_KERNEL"},
119 {(((0x400000u | 0x2000000u)) | (0x40u)), "GFP_NOFS"},
120 {((0x20u) | (0x80000u) | (0x2000000u)), "GFP_ATOMIC"},
121 {(((0x400000u | 0x2000000u))), "GFP_NOIO"},
122 {(0x20u), "GFP_HIGH"},
123 {(0x80000u), "GFP_ATOMIC"},
124 {(0x40u), "GFP_IO"},
125 {(0x100u), "GFP_COLD"},
126 {(0x200u), "GFP_NOWARN"},
127 {(0x400u), "GFP_REPEAT"},
128 {(0x800u), "GFP_NOFAIL"},
129 {(0x1000u), "GFP_NORETRY"},
130 {(0x4000u), "GFP_COMP"},
131 {(0x8000u), "GFP_ZERO"},
132 {(0x10000u), "GFP_NOMEMALLOC"},
133 {(0x2000u), "GFP_MEMALLOC"},
134 {(0x20000u), "GFP_HARDWALL"},
135 {(0x40000u), "GFP_THISNODE"},
136 {(0x10u), "GFP_RECLAIMABLE"},
137 {(0x08u), "GFP_MOVABLE"},
138 {(0x200000u), "GFP_NOTRACK"},
139 {(0x400000u), "GFP_DIRECT_RECLAIM"},
140 {(0x2000000u), "GFP_KSWAPD_RECLAIM"},
141 {(0x800000u), "GFP_OTHER_NODE"},
142 {0, nullptr}}};
143
144 constexpr FlagArray v4_14 = {
145 {{((((((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
146 (0x02u)) |
147 (0x08u)) |
148 (0x4000u) | (0x10000u) | (0x200u)) &
149 ~((0x400000u | 0x1000000u))) |
150 (0x400000u)),
151 "GFP_TRANSHUGE"},
152 {(((((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
153 (0x02u)) |
154 (0x08u)) |
155 (0x4000u) | (0x10000u) | (0x200u)) &
156 ~((0x400000u | 0x1000000u))),
157 "GFP_TRANSHUGE_LIGHT"},
158 {(((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) |
159 (0x02u)) |
160 (0x08u)),
161 "GFP_HIGHUSER_MOVABLE"},
162 {((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)) | (0x02u)),
163 "GFP_HIGHUSER"},
164 {(((0x400000u | 0x1000000u)) | (0x40u) | (0x80u) | (0x20000u)),
165 "GFP_USER"},
166 {((((0x400000u | 0x1000000u)) | (0x40u) | (0x80u)) | (0x100000u)),
167 "GFP_KERNEL_ACCOUNT"},
168 {(((0x400000u | 0x1000000u)) | (0x40u) | (0x80u)), "GFP_KERNEL"},
169 {(((0x400000u | 0x1000000u)) | (0x40u)), "GFP_NOFS"},
170 {((0x20u) | (0x80000u) | (0x1000000u)), "GFP_ATOMIC"},
171 {(((0x400000u | 0x1000000u))), "GFP_NOIO"},
172 {((0x1000000u)), "GFP_NOWAIT"},
173 {(0x01u), "GFP_DMA"},
174 {(0x02u), "__GFP_HIGHMEM"},
175 {(0x04u), "GFP_DMA32"},
176 {(0x20u), "__GFP_HIGH"},
177 {(0x80000u), "__GFP_ATOMIC"},
178 {(0x40u), "__GFP_IO"},
179 {(0x80u), "__GFP_FS"},
180 {(0x100u), "__GFP_COLD"},
181 {(0x200u), "__GFP_NOWARN"},
182 {(0x400u), "__GFP_RETRY_MAYFAIL"},
183 {(0x800u), "__GFP_NOFAIL"},
184 {(0x1000u), "__GFP_NORETRY"},
185 {(0x4000u), "__GFP_COMP"},
186 {(0x8000u), "__GFP_ZERO"},
187 {(0x10000u), "__GFP_NOMEMALLOC"},
188 {(0x2000u), "__GFP_MEMALLOC"},
189 {(0x20000u), "__GFP_HARDWALL"},
190 {(0x40000u), "__GFP_THISNODE"},
191 {(0x10u), "__GFP_RECLAIMABLE"},
192 {(0x08u), "__GFP_MOVABLE"},
193 {(0x100000u), "__GFP_ACCOUNT"},
194 {(0x800000u), "__GFP_WRITE"},
195 {((0x400000u | 0x1000000u)), "__GFP_RECLAIM"},
196 {(0x400000u), "__GFP_DIRECT_RECLAIM"},
197 {(0x1000000u), "__GFP_KSWAPD_RECLAIM"},
198 {0, nullptr}}};
199
200 // Get the bitmask closest to the kernel version. For versions less than 3.4
201 // and greater than 4.14 this may end up being inaccurate.
GetBitmaskVersion(VersionNumber version=VersionNumber{4, 4})202 const FlagArray* GetBitmaskVersion(VersionNumber version = VersionNumber{4,
203 4}) {
204 if (version < VersionNumber{3, 10}) {
205 return &v3_4;
206 } else if (version >= VersionNumber{3, 10} && version < VersionNumber{4, 4}) {
207 return &v3_10;
208 } else if (version >= VersionNumber{4, 4} && version < VersionNumber{4, 14}) {
209 return &v4_4;
210 } else { // version >= 4.14
211 // TODO(hjd): Add newer kernel versions once we have access to them.
212 return &v4_14;
213 }
214 }
215 } // namespace
216
WriteGfpFlag(uint64_t value,std::optional<VersionNumber> version,base::StringWriter * writer)217 void WriteGfpFlag(uint64_t value,
218 std::optional<VersionNumber> version,
219 base::StringWriter* writer) {
220 // On all kernel versions if this flag is not set, return GFP_NOWAIT.
221 if (value == 0) {
222 writer->AppendString("GFP_NOWAIT");
223 return;
224 }
225
226 std::string result;
227 const FlagArray* bitmasks = version.has_value()
228 ? GetBitmaskVersion(version.value())
229 : GetBitmaskVersion();
230
231 // Based on trace_print_flags_seq() in the kernel.
232 size_t i = 0;
233 while (bitmasks->at(i).flag_name != nullptr) {
234 size_t current = i++;
235 uint64_t mask = bitmasks->at(current).mask;
236 const char* str = bitmasks->at(current).flag_name;
237
238 if ((value & mask) != mask)
239 continue;
240 value &= ~mask;
241
242 result += str;
243 result += "|";
244 }
245
246 // Add any leftover flags.
247 if (value) {
248 writer->AppendString(result.c_str(), result.size());
249 writer->AppendString("0x", 2);
250 writer->AppendHexInt(value);
251 } else {
252 writer->AppendString(result.c_str(), result.size() - 1);
253 }
254 }
255
256 } // namespace trace_processor
257 } // namespace perfetto
258