6#if defined(DART_HOST_OS_LINUX)
17#include <sys/resource.h>
19#include <sys/syscall.h>
41#if defined(ARCH_IS_64_BIT)
42#define ElfW(Type) Elf64_##Type
44#define ElfW(Type) Elf32_##Type
55 generate_perf_events_symbols,
57 "Generate events symbols for profiling with perf (disables dual "
61 generate_perf_jitdump,
63 "Generate jitdump file to use with perf-inject (disables dual code "
68#if !defined(DART_PRECOMPILED_RUNTIME)
80class PerfCodeObserver :
public CodeObserver {
82 PerfCodeObserver() : out_file_(nullptr) {
84 if (file_open ==
nullptr) {
87 intptr_t pid = getpid();
88 char* filename =
OS::SCreate(
nullptr,
"/tmp/perf-%" Pd ".map", pid);
89 out_file_ = (*file_open)(filename,
true);
95 if ((file_close ==
nullptr) || (out_file_ ==
nullptr)) {
98 (*file_close)(out_file_);
101 virtual bool IsActive()
const {
102 return FLAG_generate_perf_events_symbols && (out_file_ !=
nullptr);
105 virtual void Notify(
const char*
name,
107 uword prologue_offset,
110 const CodeComments* comments) {
112 if ((file_write ==
nullptr) || (out_file_ ==
nullptr)) {
115 const char*
marker = optimized ?
"*" :
"";
143class JitDumpCodeObserver :
public CodeObserver {
145 JitDumpCodeObserver() : pid_(getpid()) {
146 char*
const filename =
OS::SCreate(
nullptr,
"/tmp/jit-%" Pd ".dump", pid_);
147 const int fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0666);
156 const long page_size = sysconf(_SC_PAGESIZE);
157 if (page_size == -1) {
163 mmap(
nullptr, page_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
164 if (mapped_ ==
nullptr) {
168 mapped_size_ = page_size;
170 out_file_ = fdopen(fd,
"w+");
171 if (out_file_ ==
nullptr) {
178 setvbuf(out_file_,
nullptr, _IOFBF, 2 *
MB);
183 FLAG_write_protect_code =
false;
184 FLAG_write_protect_vm_isolate =
false;
186#if !defined(DART_PRECOMPILED_RUNTIME)
188 FLAG_code_comments =
true;
195 ~JitDumpCodeObserver() {
196 if (mapped_ !=
nullptr) {
197 munmap(mapped_, mapped_size_);
201 if (out_file_ !=
nullptr) {
207 virtual bool IsActive()
const {
208 return FLAG_generate_perf_jitdump && (out_file_ !=
nullptr);
211 virtual void Notify(
const char*
name,
213 uword prologue_offset,
216 const CodeComments* comments) {
219 const char*
marker = optimized ?
"*" :
"";
221 const size_t name_length = strlen(
buffer);
223 WriteDebugInfo(
base, comments);
226 ev.event = BaseEvent::kLoad;
227 ev.size =
sizeof(ev) + (name_length + 1) +
size;
229 ev.process_id = getpid();
230 ev.thread_id = syscall(SYS_gettid);
232 ev.code_address =
base;
234 ev.code_id = code_id_++;
236 WriteFully(&ev,
sizeof(ev));
237 WriteFully(
buffer, name_length + 1);
238 WriteFully(
reinterpret_cast<void*
>(
base),
size);
243 const uint32_t
magic = 0x4A695444;
246 uint32_t elf_mach_target;
247 const uint32_t reserved = 0xDEADBEEF;
250 const uint64_t
flags = 0;
267 struct CodeLoadEvent : BaseEvent {
271 uint64_t code_address;
276 struct DebugInfoEvent : BaseEvent {
278 uint64_t entry_count;
282 struct DebugInfoEntry {
289 static uint32_t GetElfMachineArchitecture() {
296#elif TARGET_ARCH_ARM64
298#elif TARGET_ARCH_RISCV32 || TARGET_ARCH_RISCV64
306 void WriteDebugInfo(
uword base,
const CodeComments* comments) {
307 if (comments ==
nullptr || comments->Length() == 0) {
315 char* comments_file_name =
317 const intptr_t filename_length = strlen(comments_file_name);
318 FILE* comments_file = fopen(comments_file_name,
"w");
319 setvbuf(comments_file,
nullptr, _IOFBF, 2 *
MB);
323 intptr_t entry_count = 0;
324 for (uint64_t
i = 0,
len = comments->Length();
i <
len;) {
325 const intptr_t pc_offset = comments->PCOffsetAt(
i);
326 while (i < len && comments->PCOffsetAt(
i) == pc_offset) {
333 info.event = BaseEvent::kDebugInfo;
336 info.entry_count = entry_count;
338 entry_count * (
sizeof(DebugInfoEntry) + filename_length + 1);
340 info.size += padding;
345 intptr_t line_number = 0;
346 for (intptr_t
i = 0,
len = comments->Length();
i <
len;) {
347 const intptr_t pc_offset = comments->PCOffsetAt(
i);
348 while (i < len && comments->PCOffsetAt(
i) == pc_offset) {
349 line_number += WriteLn(comments_file, comments->CommentAt(
i));
352 DebugInfoEntry entry;
353 entry.address =
base + pc_offset +
sizeof(ElfW(Ehdr));
354 entry.line_number = line_number;
356 WriteFully(&entry,
sizeof(entry));
357 WriteFully(comments_file_name, filename_length + 1);
361 const char padding_bytes[8] = {0};
362 WriteFully(padding_bytes, padding);
364 fclose(comments_file);
365 free(comments_file_name);
370 header.elf_mach_target = GetElfMachineArchitecture();
371 header.process_id = getpid();
377 intptr_t WriteLn(FILE*
f,
const char* comment) {
381 intptr_t line_count = 1;
382 while ((comment = strstr(comment,
"\n")) !=
nullptr) {
388 void WriteFully(
const void*
buffer,
size_t size) {
389 const char* ptr =
static_cast<const char*
>(
buffer);
391 const size_t written = fwrite(ptr, 1,
size, out_file_);
403 FILE* out_file_ =
nullptr;
404 void* mapped_ =
nullptr;
405 long mapped_size_ = 0;
407 intptr_t code_id_ = 0;
415 return static_cast<intptr_t
>(getpid());
418static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
419 time_t seconds =
static_cast<time_t
>(seconds_since_epoch);
420 if (seconds != seconds_since_epoch)
return false;
421 struct tm* error_code = localtime_r(&seconds, tm_result);
422 return error_code !=
nullptr;
427 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
429 return (succeeded && (decomposed.tm_zone !=
nullptr)) ? decomposed.tm_zone
435 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
438 return succeeded ?
static_cast<int>(decomposed.tm_gmtoff) : 0;
448 if (gettimeofday(&tv,
nullptr) < 0) {
452 return (
static_cast<int64_t
>(tv.tv_sec) * 1000000) + tv.tv_usec;
457 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
462 int64_t
result = ts.tv_sec;
480 if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) {
484 int64_t
result = ts.tv_sec;
491#if defined(SUPPORT_TIMELINE)
492 if (Timeline::recorder_discards_clock_values())
return -1;
502#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
503 defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_RISCV32) || \
504 defined(TARGET_ARCH_RISCV64)
505 const int kMinimumAlignment = 16;
506#elif defined(TARGET_ARCH_ARM)
507 const int kMinimumAlignment = 8;
509#error Unsupported architecture.
511 intptr_t alignment = kMinimumAlignment;
516 ASSERT(alignment >= kMinimumAlignment);
521 return sysconf(_SC_NPROCESSORS_ONLN);
535 req.tv_sec = seconds;
538 int r = nanosleep(&req, &rem);
555 return reinterpret_cast<uintptr_t
>(
556 __builtin_extract_return_addr(__builtin_return_address(0)));
581 va_list measure_args;
582 va_copy(measure_args,
args);
587 if (zone !=
nullptr) {
596 va_copy(print_args,
args);
603 ASSERT(str !=
nullptr && strlen(str) > 0 &&
value !=
nullptr);
609 }
else if (str[0] ==
'+') {
612 if ((str[
i] ==
'0') && (str[
i + 1] ==
'x' || str[
i + 1] ==
'X') &&
613 (str[
i + 2] !=
'\0')) {
620 *
value =
static_cast<int64_t
>(strtoull(str, &endptr,
base));
624 return ((errno == 0) && (endptr != str) && (*endptr == 0));
629 if (FLAG_generate_perf_events_symbols) {
633 if (FLAG_generate_perf_jitdump) {
664 const Image instructions_image(snapshot_instructions);
665 if (
auto*
const image_build_id = instructions_image.build_id()) {
666 return {instructions_image.build_id_length(), image_build_id};
668 const uint8_t* dso_base =
GetAppDSOBase(snapshot_instructions);
669 const ElfW(Ehdr)& elf_header = *
reinterpret_cast<const ElfW(Ehdr)*
>(dso_base);
670 const ElfW(Phdr)*
const phdr_array =
671 reinterpret_cast<const ElfW(Phdr)*
>(dso_base + elf_header.e_phoff);
672 for (intptr_t
i = 0;
i < elf_header.e_phnum;
i++) {
673 const ElfW(Phdr)&
header = phdr_array[
i];
674 if (
header.p_type != PT_NOTE)
continue;
676 const uint8_t*
const note_addr = dso_base +
header.p_vaddr;
677 const Elf32_Nhdr& note_header =
678 *
reinterpret_cast<const Elf32_Nhdr*
>(note_addr);
679 if (note_header.n_type != NT_GNU_BUILD_ID)
continue;
680 const char*
const note_contents =
681 reinterpret_cast<const char*
>(note_addr +
sizeof(Elf32_Nhdr));
683 if (note_header.n_namesz != strlen(
ELF_NOTE_GNU) + 1)
continue;
684 if (strncmp(
ELF_NOTE_GNU, note_contents, note_header.n_namesz) == 0) {
685 return {
static_cast<intptr_t
>(note_header.n_descsz),
686 reinterpret_cast<const uint8_t*
>(note_contents +
687 note_header.n_namesz)};
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static const char marker[]
@ kClose
SkPath::RawIter returns 0 points.
static void Register(CodeObserver *observer)
static Dart_FileWriteCallback file_write_callback()
static Dart_FileOpenCallback file_open_callback()
static Dart_FileCloseCallback file_close_callback()
static DART_NORETURN void Exit(int code)
static int NumberOfAvailableProcessors()
static const char * GetTimeZoneName(int64_t seconds_since_epoch)
static void SleepMicros(int64_t micros)
static int64_t GetCurrentTimeMillis()
static void RegisterCodeObservers()
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void Sleep(int64_t millis)
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static bool StringToInt64(const char *str, int64_t *value)
static BuildId GetAppBuildId(const uint8_t *snapshot_instructions)
static const uint8_t * GetAppDSOBase(const uint8_t *snapshot_instructions)
static int64_t GetCurrentTimeMicros()
static intptr_t ActivationFrameAlignment()
static void static void static void VFPrint(FILE *stream, const char *format, va_list args)
static DART_NORETURN void Abort()
static char static char * VSCreate(Zone *zone, const char *format, va_list args)
static int64_t GetCurrentThreadCPUMicros()
static uintptr_t GetProgramCounter()
static intptr_t ProcessId()
static void PrepareToAbort()
static int64_t GetCurrentMonotonicFrequency()
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static int64_t GetCurrentMonotonicTicks()
static int64_t GetCurrentMonotonicMicrosForTimeline()
static int GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch)
static Thread * Current()
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
static constexpr bool IsPowerOfTwo(T x)
void(* Dart_FileWriteCallback)(const void *data, intptr_t length, void *stream)
void(* Dart_FileCloseCallback)(void *stream)
void *(* Dart_FileOpenCallback)(const char *name, bool write)
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
static constexpr intptr_t PF_R
static constexpr intptr_t EM_X86_64
static constexpr intptr_t EM_386
static constexpr intptr_t EM_RISCV
static constexpr intptr_t EM_AARCH64
static constexpr const char ELF_NOTE_GNU[]
static constexpr intptr_t EM_ARM
constexpr intptr_t kMicrosecondsPerMillisecond
constexpr intptr_t kMicrosecondsPerSecond
constexpr intptr_t kNanosecondsPerMicrosecond
void * malloc(size_t size)
constexpr intptr_t kNanosecondsPerSecond
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
DECLARE_FLAG(bool, show_invisible_frames)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static const char header[]