1 /*
2 * Copyright (C) 2020 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/profiling/perf/event_config.h"
18
19 #include <linux/perf_event.h>
20 #include <time.h>
21
22 #include <unwindstack/Regs.h>
23 #include <vector>
24
25 #include "perfetto/base/flat_set.h"
26 #include "perfetto/ext/base/optional.h"
27 #include "perfetto/ext/base/utils.h"
28 #include "src/profiling/perf/regs_parsing.h"
29
30 #include "protos/perfetto/common/perf_events.gen.h"
31 #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
32
33 namespace perfetto {
34 namespace profiling {
35
36 namespace {
37 constexpr uint64_t kDefaultSamplingFrequencyHz = 10;
38 constexpr uint32_t kDefaultDataPagesPerRingBuffer = 256; // 1 MB: 256x 4k pages
39 constexpr uint32_t kDefaultReadTickPeriodMs = 100;
40 constexpr uint32_t kDefaultRemoteDescriptorTimeoutMs = 100;
41
42 // Acceptable forms: "sched/sched_switch" or "sched:sched_switch".
SplitTracepointString(const std::string & input)43 std::pair<std::string, std::string> SplitTracepointString(
44 const std::string& input) {
45 auto slash_pos = input.find("/");
46 if (slash_pos != std::string::npos)
47 return std::make_pair(input.substr(0, slash_pos),
48 input.substr(slash_pos + 1));
49
50 auto colon_pos = input.find(":");
51 if (colon_pos != std::string::npos)
52 return std::make_pair(input.substr(0, colon_pos),
53 input.substr(colon_pos + 1));
54
55 return std::make_pair("", input);
56 }
57
58 // If set, the returned id is guaranteed to be non-zero.
ParseTracepointAndResolveId(const protos::gen::PerfEvents::Tracepoint & tracepoint,EventConfig::tracepoint_id_fn_t tracepoint_id_lookup)59 base::Optional<uint32_t> ParseTracepointAndResolveId(
60 const protos::gen::PerfEvents::Tracepoint& tracepoint,
61 EventConfig::tracepoint_id_fn_t tracepoint_id_lookup) {
62 std::string full_name = tracepoint.name();
63 std::string tp_group;
64 std::string tp_name;
65 std::tie(tp_group, tp_name) = SplitTracepointString(full_name);
66 if (tp_group.empty() || tp_name.empty()) {
67 PERFETTO_ELOG(
68 "Invalid tracepoint format: %s. Should be a full path like "
69 "sched:sched_switch or sched/sched_switch.",
70 full_name.c_str());
71 return base::nullopt;
72 }
73
74 uint32_t tracepoint_id = tracepoint_id_lookup(tp_group, tp_name);
75 if (!tracepoint_id) {
76 PERFETTO_ELOG(
77 "Failed to resolve tracepoint %s to its id. Check that tracefs is "
78 "accessible and the event exists.",
79 full_name.c_str());
80 return base::nullopt;
81 }
82 return base::make_optional(tracepoint_id);
83 }
84
85 // |T| is either gen::PerfEventConfig or gen::PerfEventConfig::Scope.
86 // Note: the semantics of target_cmdline and exclude_cmdline were changed since
87 // their original introduction. They used to be put through a canonicalization
88 // function that simplified them to the binary name alone. We no longer do this,
89 // regardless of whether we're parsing an old-style config. The overall outcome
90 // shouldn't change for almost all existing uses.
91 template <typename T>
ParseTargetFilter(const T & cfg)92 TargetFilter ParseTargetFilter(const T& cfg) {
93 TargetFilter filter;
94 for (const auto& str : cfg.target_cmdline()) {
95 filter.cmdlines.push_back(str);
96 }
97 for (const auto& str : cfg.exclude_cmdline()) {
98 filter.exclude_cmdlines.push_back(str);
99 }
100 for (const int32_t pid : cfg.target_pid()) {
101 filter.pids.insert(pid);
102 }
103 for (const int32_t pid : cfg.exclude_pid()) {
104 filter.exclude_pids.insert(pid);
105 }
106 filter.additional_cmdline_count = cfg.additional_cmdline_count();
107 return filter;
108 }
109
IsPowerOfTwo(size_t v)110 constexpr bool IsPowerOfTwo(size_t v) {
111 return (v != 0 && ((v & (v - 1)) == 0));
112 }
113
114 // returns |base::nullopt| if the input is invalid.
ChooseActualRingBufferPages(uint32_t config_value)115 base::Optional<uint32_t> ChooseActualRingBufferPages(uint32_t config_value) {
116 if (!config_value) {
117 static_assert(IsPowerOfTwo(kDefaultDataPagesPerRingBuffer), "");
118 return base::make_optional(kDefaultDataPagesPerRingBuffer);
119 }
120
121 if (!IsPowerOfTwo(config_value)) {
122 PERFETTO_ELOG("kernel buffer size must be a power of two pages");
123 return base::nullopt;
124 }
125
126 return base::make_optional(config_value);
127 }
128
ToPerfCounter(std::string name,protos::gen::PerfEvents::Counter pb_enum)129 base::Optional<PerfCounter> ToPerfCounter(
130 std::string name,
131 protos::gen::PerfEvents::Counter pb_enum) {
132 using protos::gen::PerfEvents;
133 switch (static_cast<int>(pb_enum)) { // cast to pacify -Wswitch-enum
134 case PerfEvents::SW_CPU_CLOCK:
135 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_CPU_CLOCK,
136 PERF_TYPE_SOFTWARE,
137 PERF_COUNT_SW_CPU_CLOCK);
138 case PerfEvents::SW_PAGE_FAULTS:
139 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_PAGE_FAULTS,
140 PERF_TYPE_SOFTWARE,
141 PERF_COUNT_SW_PAGE_FAULTS);
142 case PerfEvents::SW_TASK_CLOCK:
143 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_TASK_CLOCK,
144 PERF_TYPE_SOFTWARE,
145 PERF_COUNT_SW_TASK_CLOCK);
146 case PerfEvents::SW_CONTEXT_SWITCHES:
147 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_CONTEXT_SWITCHES,
148 PERF_TYPE_SOFTWARE,
149 PERF_COUNT_SW_CONTEXT_SWITCHES);
150 case PerfEvents::SW_CPU_MIGRATIONS:
151 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_CPU_MIGRATIONS,
152 PERF_TYPE_SOFTWARE,
153 PERF_COUNT_SW_CPU_MIGRATIONS);
154 case PerfEvents::SW_PAGE_FAULTS_MIN:
155 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_PAGE_FAULTS_MIN,
156 PERF_TYPE_SOFTWARE,
157 PERF_COUNT_SW_PAGE_FAULTS_MIN);
158 case PerfEvents::SW_PAGE_FAULTS_MAJ:
159 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_PAGE_FAULTS_MAJ,
160 PERF_TYPE_SOFTWARE,
161 PERF_COUNT_SW_PAGE_FAULTS_MAJ);
162 case PerfEvents::SW_ALIGNMENT_FAULTS:
163 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_ALIGNMENT_FAULTS,
164 PERF_TYPE_SOFTWARE,
165 PERF_COUNT_SW_ALIGNMENT_FAULTS);
166 case PerfEvents::SW_EMULATION_FAULTS:
167 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_EMULATION_FAULTS,
168 PERF_TYPE_SOFTWARE,
169 PERF_COUNT_SW_EMULATION_FAULTS);
170 case PerfEvents::SW_DUMMY:
171 return PerfCounter::BuiltinCounter(
172 name, PerfEvents::SW_DUMMY, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY);
173
174 case PerfEvents::HW_CPU_CYCLES:
175 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_CPU_CYCLES,
176 PERF_TYPE_HARDWARE,
177 PERF_COUNT_HW_CPU_CYCLES);
178 case PerfEvents::HW_INSTRUCTIONS:
179 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_INSTRUCTIONS,
180 PERF_TYPE_HARDWARE,
181 PERF_COUNT_HW_INSTRUCTIONS);
182 case PerfEvents::HW_CACHE_REFERENCES:
183 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_CACHE_REFERENCES,
184 PERF_TYPE_HARDWARE,
185 PERF_COUNT_HW_CACHE_REFERENCES);
186 case PerfEvents::HW_CACHE_MISSES:
187 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_CACHE_MISSES,
188 PERF_TYPE_HARDWARE,
189 PERF_COUNT_HW_CACHE_MISSES);
190 case PerfEvents::HW_BRANCH_INSTRUCTIONS:
191 return PerfCounter::BuiltinCounter(
192 name, PerfEvents::HW_BRANCH_INSTRUCTIONS, PERF_TYPE_HARDWARE,
193 PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
194 case PerfEvents::HW_BRANCH_MISSES:
195 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_BRANCH_MISSES,
196 PERF_TYPE_HARDWARE,
197 PERF_COUNT_HW_BRANCH_MISSES);
198 case PerfEvents::HW_BUS_CYCLES:
199 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_BUS_CYCLES,
200 PERF_TYPE_HARDWARE,
201 PERF_COUNT_HW_BUS_CYCLES);
202 case PerfEvents::HW_STALLED_CYCLES_FRONTEND:
203 return PerfCounter::BuiltinCounter(
204 name, PerfEvents::HW_STALLED_CYCLES_FRONTEND, PERF_TYPE_HARDWARE,
205 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND);
206 case PerfEvents::HW_STALLED_CYCLES_BACKEND:
207 return PerfCounter::BuiltinCounter(
208 name, PerfEvents::HW_STALLED_CYCLES_BACKEND, PERF_TYPE_HARDWARE,
209 PERF_COUNT_HW_STALLED_CYCLES_BACKEND);
210 case PerfEvents::HW_REF_CPU_CYCLES:
211 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_REF_CPU_CYCLES,
212 PERF_TYPE_HARDWARE,
213 PERF_COUNT_HW_REF_CPU_CYCLES);
214
215 default:
216 PERFETTO_ELOG("Unrecognised PerfEvents::Counter enum value: %zu",
217 static_cast<size_t>(pb_enum));
218 return base::nullopt;
219 }
220 }
221
ToClockId(protos::gen::PerfEvents::PerfClock pb_enum)222 int32_t ToClockId(protos::gen::PerfEvents::PerfClock pb_enum) {
223 using protos::gen::PerfEvents;
224 switch (static_cast<int>(pb_enum)) { // cast to pacify -Wswitch-enum
225 case PerfEvents::PERF_CLOCK_REALTIME:
226 return CLOCK_REALTIME;
227 case PerfEvents::PERF_CLOCK_MONOTONIC:
228 return CLOCK_MONOTONIC;
229 case PerfEvents::PERF_CLOCK_MONOTONIC_RAW:
230 return CLOCK_MONOTONIC_RAW;
231 case PerfEvents::PERF_CLOCK_BOOTTIME:
232 return CLOCK_BOOTTIME;
233 // Default to a monotonic clock since it should be compatible with all types
234 // of events. Whereas boottime cannot be used with hardware events due to
235 // potential access within non-maskable interrupts.
236 default:
237 return CLOCK_MONOTONIC_RAW;
238 }
239 }
240
241 } // namespace
242
243 // static
BuiltinCounter(std::string name,protos::gen::PerfEvents::Counter counter,uint32_t type,uint64_t config)244 PerfCounter PerfCounter::BuiltinCounter(
245 std::string name,
246 protos::gen::PerfEvents::Counter counter,
247 uint32_t type,
248 uint64_t config) {
249 PerfCounter ret;
250 ret.type = PerfCounter::Type::kBuiltinCounter;
251 ret.counter = counter;
252 ret.name = std::move(name);
253
254 ret.attr_type = type;
255 ret.attr_config = config;
256 // none of the builtin counters require config1 and config2 at the moment
257 return ret;
258 }
259
260 // static
Tracepoint(std::string name,std::string tracepoint_name,std::string tracepoint_filter,uint64_t id)261 PerfCounter PerfCounter::Tracepoint(std::string name,
262 std::string tracepoint_name,
263 std::string tracepoint_filter,
264 uint64_t id) {
265 PerfCounter ret;
266 ret.type = PerfCounter::Type::kTracepoint;
267 ret.tracepoint_name = std::move(tracepoint_name);
268 ret.tracepoint_filter = std::move(tracepoint_filter);
269 ret.name = std::move(name);
270
271 ret.attr_type = PERF_TYPE_TRACEPOINT;
272 ret.attr_config = id;
273 return ret;
274 }
275
276 // static
RawEvent(std::string name,uint32_t type,uint64_t config,uint64_t config1,uint64_t config2)277 PerfCounter PerfCounter::RawEvent(std::string name,
278 uint32_t type,
279 uint64_t config,
280 uint64_t config1,
281 uint64_t config2) {
282 PerfCounter ret;
283 ret.type = PerfCounter::Type::kRawEvent;
284 ret.name = std::move(name);
285
286 ret.attr_type = type;
287 ret.attr_config = config;
288 ret.attr_config1 = config1;
289 ret.attr_config2 = config2;
290 return ret;
291 }
292
293 // static
Create(const DataSourceConfig & ds_config,tracepoint_id_fn_t tracepoint_id_lookup)294 base::Optional<EventConfig> EventConfig::Create(
295 const DataSourceConfig& ds_config,
296 tracepoint_id_fn_t tracepoint_id_lookup) {
297 protos::gen::PerfEventConfig pb_config;
298 if (!pb_config.ParseFromString(ds_config.perf_event_config_raw()))
299 return base::nullopt;
300
301 return EventConfig::Create(pb_config, ds_config, tracepoint_id_lookup);
302 }
303
304 // static
Create(const protos::gen::PerfEventConfig & pb_config,const DataSourceConfig & raw_ds_config,tracepoint_id_fn_t tracepoint_id_lookup)305 base::Optional<EventConfig> EventConfig::Create(
306 const protos::gen::PerfEventConfig& pb_config,
307 const DataSourceConfig& raw_ds_config,
308 tracepoint_id_fn_t tracepoint_id_lookup) {
309 // Timebase: sampling interval.
310 uint64_t sampling_frequency = 0;
311 uint64_t sampling_period = 0;
312 if (pb_config.timebase().period()) {
313 sampling_period = pb_config.timebase().period();
314 } else if (pb_config.timebase().frequency()) {
315 sampling_frequency = pb_config.timebase().frequency();
316 } else if (pb_config.sampling_frequency()) { // backwards compatibility
317 sampling_frequency = pb_config.sampling_frequency();
318 } else {
319 sampling_frequency = kDefaultSamplingFrequencyHz;
320 }
321 PERFETTO_DCHECK(sampling_period && !sampling_frequency ||
322 !sampling_period && sampling_frequency);
323
324 // Timebase event. Default: CPU timer.
325 PerfCounter timebase_event;
326 std::string timebase_name = pb_config.timebase().name();
327 if (pb_config.timebase().has_counter()) {
328 auto maybe_counter =
329 ToPerfCounter(timebase_name, pb_config.timebase().counter());
330 if (!maybe_counter)
331 return base::nullopt;
332 timebase_event = *maybe_counter;
333
334 } else if (pb_config.timebase().has_tracepoint()) {
335 const auto& tracepoint_pb = pb_config.timebase().tracepoint();
336 base::Optional<uint32_t> maybe_id =
337 ParseTracepointAndResolveId(tracepoint_pb, tracepoint_id_lookup);
338 if (!maybe_id)
339 return base::nullopt;
340 timebase_event = PerfCounter::Tracepoint(
341 timebase_name, tracepoint_pb.name(), tracepoint_pb.filter(), *maybe_id);
342
343 } else if (pb_config.timebase().has_raw_event()) {
344 const auto& raw = pb_config.timebase().raw_event();
345 timebase_event = PerfCounter::RawEvent(
346 timebase_name, raw.type(), raw.config(), raw.config1(), raw.config2());
347
348 } else {
349 timebase_event = PerfCounter::BuiltinCounter(
350 timebase_name, protos::gen::PerfEvents::PerfEvents::SW_CPU_CLOCK,
351 PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
352 }
353
354 // Callstack sampling.
355 bool sample_callstacks = false;
356 bool kernel_frames = false;
357 TargetFilter target_filter;
358 bool legacy_config = pb_config.all_cpus(); // all_cpus was mandatory before
359 if (pb_config.has_callstack_sampling() || legacy_config) {
360 sample_callstacks = true;
361
362 // Process scoping.
363 target_filter =
364 pb_config.callstack_sampling().has_scope()
365 ? ParseTargetFilter(pb_config.callstack_sampling().scope())
366 : ParseTargetFilter(pb_config); // backwards compatibility
367
368 // Inclusion of kernel callchains.
369 kernel_frames = pb_config.callstack_sampling().kernel_frames() ||
370 pb_config.kernel_frames();
371 }
372
373 // Ring buffer options.
374 base::Optional<uint32_t> ring_buffer_pages =
375 ChooseActualRingBufferPages(pb_config.ring_buffer_pages());
376 if (!ring_buffer_pages.has_value())
377 return base::nullopt;
378
379 uint32_t read_tick_period_ms = pb_config.ring_buffer_read_period_ms()
380 ? pb_config.ring_buffer_read_period_ms()
381 : kDefaultReadTickPeriodMs;
382
383 // Calculate a rough upper limit for the amount of samples the producer
384 // should read per read tick, as a safeguard against getting stuck chasing the
385 // ring buffer head indefinitely.
386 uint64_t samples_per_tick_limit = 0;
387 if (sampling_frequency) {
388 // expected = rate * period, with a conversion of period from ms to s:
389 uint64_t expected_samples_per_tick =
390 1 + (sampling_frequency * read_tick_period_ms) / 1000;
391 // Double the limit to account of actual sample rate uncertainties, as
392 // well as any other factors:
393 samples_per_tick_limit = 2 * expected_samples_per_tick;
394 } else { // sampling_period
395 // We don't know the sample rate that a fixed period would cause, but we can
396 // still estimate how many samples will fit in one pass of the ring buffer
397 // (with the assumption that we don't want to read more than one buffer's
398 // capacity within a tick).
399 // TODO(rsavitski): for now, make an extremely conservative guess of an 8
400 // byte sample (stack sampling samples can be up to 64KB). This is most
401 // likely as good as no limit in practice.
402 samples_per_tick_limit = *ring_buffer_pages * (base::kPageSize / 8);
403 }
404 PERFETTO_DLOG("Capping samples (not records) per tick to [%" PRIu64 "]",
405 samples_per_tick_limit);
406 if (samples_per_tick_limit == 0)
407 return base::nullopt;
408
409 // Optional footprint controls.
410 uint64_t max_enqueued_footprint_bytes =
411 pb_config.max_enqueued_footprint_kb() * 1024;
412
413 // Android-specific options.
414 uint32_t remote_descriptor_timeout_ms =
415 pb_config.remote_descriptor_timeout_ms()
416 ? pb_config.remote_descriptor_timeout_ms()
417 : kDefaultRemoteDescriptorTimeoutMs;
418
419 // Build the underlying syscall config struct.
420 perf_event_attr pe = {};
421 pe.size = sizeof(perf_event_attr);
422 pe.disabled = 1; // will be activated via ioctl
423
424 // Sampling timebase.
425 pe.type = timebase_event.attr_type;
426 pe.config = timebase_event.attr_config;
427 pe.config1 = timebase_event.attr_config1;
428 pe.config2 = timebase_event.attr_config2;
429 if (sampling_frequency) {
430 pe.freq = true;
431 pe.sample_freq = sampling_frequency;
432 } else {
433 pe.sample_period = sampling_period;
434 }
435
436 // What the samples will contain.
437 pe.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_READ;
438 // PERF_SAMPLE_TIME:
439 pe.clockid = ToClockId(pb_config.timebase().timestamp_clock());
440 pe.use_clockid = true;
441
442 if (sample_callstacks) {
443 pe.sample_type |= PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER;
444 // PERF_SAMPLE_STACK_USER:
445 // Needs to be < ((u16)(~0u)), and have bottom 8 bits clear.
446 // Note that the kernel still needs to make space for the other parts of the
447 // sample (up to the max record size of 64k), so the effective maximum
448 // can be lower than this.
449 pe.sample_stack_user = (1u << 16) - 256;
450 // PERF_SAMPLE_REGS_USER:
451 pe.sample_regs_user =
452 PerfUserRegsMaskForArch(unwindstack::Regs::CurrentArch());
453
454 // Optional kernel callchains:
455 if (kernel_frames) {
456 pe.sample_type |= PERF_SAMPLE_CALLCHAIN;
457 pe.exclude_callchain_user = true;
458 }
459 }
460
461 return EventConfig(
462 raw_ds_config, pe, timebase_event, sample_callstacks,
463 std::move(target_filter), kernel_frames, ring_buffer_pages.value(),
464 read_tick_period_ms, samples_per_tick_limit, remote_descriptor_timeout_ms,
465 pb_config.unwind_state_clear_period_ms(), max_enqueued_footprint_bytes,
466 pb_config.target_installed_by());
467 }
468
EventConfig(const DataSourceConfig & raw_ds_config,const perf_event_attr & pe,const PerfCounter & timebase_event,bool sample_callstacks,TargetFilter target_filter,bool kernel_frames,uint32_t ring_buffer_pages,uint32_t read_tick_period_ms,uint64_t samples_per_tick_limit,uint32_t remote_descriptor_timeout_ms,uint32_t unwind_state_clear_period_ms,uint64_t max_enqueued_footprint_bytes,std::vector<std::string> target_installed_by)469 EventConfig::EventConfig(const DataSourceConfig& raw_ds_config,
470 const perf_event_attr& pe,
471 const PerfCounter& timebase_event,
472 bool sample_callstacks,
473 TargetFilter target_filter,
474 bool kernel_frames,
475 uint32_t ring_buffer_pages,
476 uint32_t read_tick_period_ms,
477 uint64_t samples_per_tick_limit,
478 uint32_t remote_descriptor_timeout_ms,
479 uint32_t unwind_state_clear_period_ms,
480 uint64_t max_enqueued_footprint_bytes,
481 std::vector<std::string> target_installed_by)
482 : perf_event_attr_(pe),
483 timebase_event_(timebase_event),
484 sample_callstacks_(sample_callstacks),
485 target_filter_(std::move(target_filter)),
486 kernel_frames_(kernel_frames),
487 ring_buffer_pages_(ring_buffer_pages),
488 read_tick_period_ms_(read_tick_period_ms),
489 samples_per_tick_limit_(samples_per_tick_limit),
490 remote_descriptor_timeout_ms_(remote_descriptor_timeout_ms),
491 unwind_state_clear_period_ms_(unwind_state_clear_period_ms),
492 max_enqueued_footprint_bytes_(max_enqueued_footprint_bytes),
493 target_installed_by_(std::move(target_installed_by)),
494 raw_ds_config_(raw_ds_config) /* full copy */ {}
495
496 } // namespace profiling
497 } // namespace perfetto
498