Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
os_linux.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/globals.h"
6#if defined(DART_HOST_OS_LINUX)
7
8#include "vm/os.h"
9
10#include <dlfcn.h> // NOLINT
11#include <elf.h> // NOLINT
12#include <errno.h> // NOLINT
13#include <fcntl.h> // NOLINT
14#include <limits.h> // NOLINT
15#include <malloc.h> // NOLINT
16#include <sys/mman.h> // NOLINT
17#include <sys/resource.h> // NOLINT
18#include <sys/stat.h> // NOLINT
19#include <sys/syscall.h> // NOLINT
20#include <sys/time.h> // NOLINT
21#include <sys/types.h> // NOLINT
22#include <time.h> // NOLINT
23#include <unistd.h> // NOLINT
24
26#include "platform/utils.h"
27#include "vm/code_comments.h"
28#include "vm/code_observers.h"
29#include "vm/dart.h"
30#include "vm/flags.h"
31#include "vm/image_snapshot.h"
32#include "vm/isolate.h"
33#include "vm/lockers.h"
34#include "vm/os_thread.h"
35#include "vm/timeline.h"
36#include "vm/zone.h"
37
38namespace dart {
39
40// Used to choose between Elf32/Elf64 types based on host archotecture bitsize.
41#if defined(ARCH_IS_64_BIT)
42#define ElfW(Type) Elf64_##Type
43#else
44#define ElfW(Type) Elf32_##Type
45#endif
46
47// Missing from older versions of <elf.h>.
48#if !defined(EM_RISCV)
49#define EM_RISCV 243
50#endif
51
52#ifndef PRODUCT
53
54DEFINE_FLAG(bool,
55 generate_perf_events_symbols,
56 false,
57 "Generate events symbols for profiling with perf (disables dual "
58 "code mapping)");
59
60DEFINE_FLAG(bool,
61 generate_perf_jitdump,
62 false,
63 "Generate jitdump file to use with perf-inject (disables dual code "
64 "mapping)");
65
66DECLARE_FLAG(bool, write_protect_code);
67DECLARE_FLAG(bool, write_protect_vm_isolate);
68#if !defined(DART_PRECOMPILED_RUNTIME)
69DECLARE_FLAG(bool, code_comments);
70#endif
71
72// Linux CodeObservers.
73
74// Simple perf support: generate /tmp/perf-<pid>.map file that maps
75// memory ranges to symbol names for JIT generated code. This allows
76// perf-report to resolve addresses falling into JIT generated code.
77// However perf-annotate does not work in this mode because JIT code
78// is transient and does not exist anymore at the moment when you
79// invoke perf-report.
80class PerfCodeObserver : public CodeObserver {
81 public:
82 PerfCodeObserver() : out_file_(nullptr) {
83 Dart_FileOpenCallback file_open = Dart::file_open_callback();
84 if (file_open == nullptr) {
85 return;
86 }
87 intptr_t pid = getpid();
88 char* filename = OS::SCreate(nullptr, "/tmp/perf-%" Pd ".map", pid);
89 out_file_ = (*file_open)(filename, true);
90 free(filename);
91 }
92
93 ~PerfCodeObserver() {
94 Dart_FileCloseCallback file_close = Dart::file_close_callback();
95 if ((file_close == nullptr) || (out_file_ == nullptr)) {
96 return;
97 }
98 (*file_close)(out_file_);
99 }
100
101 virtual bool IsActive() const {
102 return FLAG_generate_perf_events_symbols && (out_file_ != nullptr);
103 }
104
105 virtual void Notify(const char* name,
106 uword base,
107 uword prologue_offset,
108 uword size,
109 bool optimized,
110 const CodeComments* comments) {
111 Dart_FileWriteCallback file_write = Dart::file_write_callback();
112 if ((file_write == nullptr) || (out_file_ == nullptr)) {
113 return;
114 }
115 const char* marker = optimized ? "*" : "";
116 char* buffer =
117 OS::SCreate(Thread::Current()->zone(), "%" Px " %" Px " %s%s\n", base,
118 size, marker, name);
119 {
120 MutexLocker ml(CodeObservers::mutex());
121 (*file_write)(buffer, strlen(buffer), out_file_);
122 }
123 }
124
125 private:
126 void* out_file_;
127
128 DISALLOW_COPY_AND_ASSIGN(PerfCodeObserver);
129};
130
131// Code observer that generates a JITDUMP[1] file that can be interpreted by
132// perf-inject to generate ELF images for JIT generated code objects, which
133// allows both perf-report and perf-annotate to recognize them.
134//
135// Usage:
136//
137// $ perf record -k mono dart --generate-perf-jitdump benchmark.dart
138// $ perf inject -j -i perf.data -o perf.data.jitted
139// $ perf report -i perf.data.jitted
140//
141// [1] see linux/tools/perf/Documentation/jitdump-specification.txt for
142// JITDUMP binary format.
143class JitDumpCodeObserver : public CodeObserver {
144 public:
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);
148 free(filename);
149
150 if (fd == -1) {
151 return;
152 }
153
154 // Map JITDUMP file, this mapping will be recorded by perf. This allows
155 // perf-inject to find this file later.
156 const long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int)
157 if (page_size == -1) {
158 close(fd);
159 return;
160 }
161
162 mapped_ =
163 mmap(nullptr, page_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
164 if (mapped_ == nullptr) {
165 close(fd);
166 return;
167 }
168 mapped_size_ = page_size;
169
170 out_file_ = fdopen(fd, "w+");
171 if (out_file_ == nullptr) {
172 close(fd);
173 return;
174 }
175
176 // Buffer the output to avoid high IO overheads - we are going to be
177 // writing all JIT generated code out.
178 setvbuf(out_file_, nullptr, _IOFBF, 2 * MB);
179
180 // Disable code write protection and vm isolate write protection, because
181 // calling mprotect on the pages filled with JIT generated code objects
182 // confuses perf.
183 FLAG_write_protect_code = false;
184 FLAG_write_protect_vm_isolate = false;
185
186#if !defined(DART_PRECOMPILED_RUNTIME)
187 // Enable code comments.
188 FLAG_code_comments = true;
189#endif
190
191 // Write JITDUMP header.
192 WriteHeader();
193 }
194
195 ~JitDumpCodeObserver() {
196 if (mapped_ != nullptr) {
197 munmap(mapped_, mapped_size_);
198 mapped_ = nullptr;
199 }
200
201 if (out_file_ != nullptr) {
202 fclose(out_file_);
203 out_file_ = nullptr;
204 }
205 }
206
207 virtual bool IsActive() const {
208 return FLAG_generate_perf_jitdump && (out_file_ != nullptr);
209 }
210
211 virtual void Notify(const char* name,
212 uword base,
213 uword prologue_offset,
214 uword size,
215 bool optimized,
216 const CodeComments* comments) {
217 MutexLocker ml(CodeObservers::mutex());
218
219 const char* marker = optimized ? "*" : "";
220 char* buffer = OS::SCreate(Thread::Current()->zone(), "%s%s", marker, name);
221 const size_t name_length = strlen(buffer);
222
223 WriteDebugInfo(base, comments);
224
225 CodeLoadEvent ev;
226 ev.event = BaseEvent::kLoad;
227 ev.size = sizeof(ev) + (name_length + 1) + size;
228 ev.time_stamp = OS::GetCurrentMonotonicTicks();
229 ev.process_id = getpid();
230 ev.thread_id = syscall(SYS_gettid);
231 ev.vma = base;
232 ev.code_address = base;
233 ev.code_size = size;
234 ev.code_id = code_id_++;
235
236 WriteFully(&ev, sizeof(ev));
237 WriteFully(buffer, name_length + 1);
238 WriteFully(reinterpret_cast<void*>(base), size);
239 }
240
241 private:
242 struct Header {
243 const uint32_t magic = 0x4A695444;
244 const uint32_t version = 1;
245 const uint32_t size = sizeof(Header);
246 uint32_t elf_mach_target;
247 const uint32_t reserved = 0xDEADBEEF;
248 uint32_t process_id;
249 uint64_t time_stamp;
250 const uint64_t flags = 0;
251 };
252
253 struct BaseEvent {
254 enum Event {
255 kLoad = 0,
256 kMove = 1,
257 kDebugInfo = 2,
258 kClose = 3,
259 kUnwindingInfo = 4
260 };
261
262 uint32_t event;
263 uint32_t size;
264 uint64_t time_stamp;
265 };
266
267 struct CodeLoadEvent : BaseEvent {
268 uint32_t process_id;
269 uint32_t thread_id;
270 uint64_t vma;
271 uint64_t code_address;
272 uint64_t code_size;
273 uint64_t code_id;
274 };
275
276 struct DebugInfoEvent : BaseEvent {
277 uint64_t address;
278 uint64_t entry_count;
279 // DebugInfoEntry entries[entry_count_];
280 };
281
282 struct DebugInfoEntry {
283 uint64_t address;
284 int32_t line_number;
285 int32_t column;
286 // Followed by nul-terminated name.
287 };
288
289 static uint32_t GetElfMachineArchitecture() {
290#if TARGET_ARCH_IA32
291 return EM_386;
292#elif TARGET_ARCH_X64
293 return EM_X86_64;
294#elif TARGET_ARCH_ARM
295 return EM_ARM;
296#elif TARGET_ARCH_ARM64
297 return EM_AARCH64;
298#elif TARGET_ARCH_RISCV32 || TARGET_ARCH_RISCV64
299 return EM_RISCV;
300#else
301 UNREACHABLE();
302 return 0;
303#endif
304 }
305
306 void WriteDebugInfo(uword base, const CodeComments* comments) {
307 if (comments == nullptr || comments->Length() == 0) {
308 return;
309 }
310
311 // Open the comments file for the given code object.
312 // Note: for some reason we can't emit all comments into a single file
313 // the mapping between PCs and lines goes out of sync (might be
314 // perf-annotate bug).
315 char* comments_file_name =
316 OS::SCreate(nullptr, "/tmp/jit-%" Pd "-%" Pd ".cmts", pid_, code_id_);
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);
320
321 // Count the number of DebugInfoEntry we are going to emit: one
322 // per PC.
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) {
327 i++;
328 }
329 entry_count++;
330 }
331
332 DebugInfoEvent info;
333 info.event = BaseEvent::kDebugInfo;
334 info.time_stamp = OS::GetCurrentMonotonicTicks();
335 info.address = base;
336 info.entry_count = entry_count;
337 info.size = sizeof(info) +
338 entry_count * (sizeof(DebugInfoEntry) + filename_length + 1);
339 const int32_t padding = Utils::RoundUp(info.size, 8) - info.size;
340 info.size += padding;
341
342 // Write out DebugInfoEvent record followed by entry_count DebugInfoEntry
343 // records.
344 WriteFully(&info, sizeof(info));
345 intptr_t line_number = 0; // Line number within comments_file.
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));
350 i++;
351 }
352 DebugInfoEntry entry;
353 entry.address = base + pc_offset + sizeof(ElfW(Ehdr));
354 entry.line_number = line_number;
355 entry.column = 0;
356 WriteFully(&entry, sizeof(entry));
357 WriteFully(comments_file_name, filename_length + 1);
358 }
359
360 // Write out the padding.
361 const char padding_bytes[8] = {0};
362 WriteFully(padding_bytes, padding);
363
364 fclose(comments_file);
365 free(comments_file_name);
366 }
367
368 void WriteHeader() {
370 header.elf_mach_target = GetElfMachineArchitecture();
371 header.process_id = getpid();
372 header.time_stamp = OS::GetCurrentTimeMicros();
373 WriteFully(&header, sizeof(header));
374 }
375
376 // Returns number of new-lines written.
377 intptr_t WriteLn(FILE* f, const char* comment) {
378 fputs(comment, f);
379 fputc('\n', f);
380
381 intptr_t line_count = 1;
382 while ((comment = strstr(comment, "\n")) != nullptr) {
383 line_count++;
384 }
385 return line_count;
386 }
387
388 void WriteFully(const void* buffer, size_t size) {
389 const char* ptr = static_cast<const char*>(buffer);
390 while (size > 0) {
391 const size_t written = fwrite(ptr, 1, size, out_file_);
392 if (written == 0) {
393 UNREACHABLE();
394 break;
395 }
396 size -= written;
397 ptr += written;
398 }
399 }
400
401 const intptr_t pid_;
402
403 FILE* out_file_ = nullptr;
404 void* mapped_ = nullptr;
405 long mapped_size_ = 0; // NOLINT(runtime/int)
406
407 intptr_t code_id_ = 0;
408
409 DISALLOW_COPY_AND_ASSIGN(JitDumpCodeObserver);
410};
411
412#endif // !PRODUCT
413
414intptr_t OS::ProcessId() {
415 return static_cast<intptr_t>(getpid());
416}
417
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;
423}
424
425const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
426 tm decomposed;
427 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
428 // If unsuccessful, return an empty string like V8 does.
429 return (succeeded && (decomposed.tm_zone != nullptr)) ? decomposed.tm_zone
430 : "";
431}
432
433int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
434 tm decomposed;
435 bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
436 // Even if the offset was 24 hours it would still easily fit into 32 bits.
437 // If unsuccessful, return zero like V8 does.
438 return succeeded ? static_cast<int>(decomposed.tm_gmtoff) : 0;
439}
440
441int64_t OS::GetCurrentTimeMillis() {
442 return GetCurrentTimeMicros() / 1000;
443}
444
445int64_t OS::GetCurrentTimeMicros() {
446 // gettimeofday has microsecond resolution.
447 struct timeval tv;
448 if (gettimeofday(&tv, nullptr) < 0) {
449 UNREACHABLE();
450 return 0;
451 }
452 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
453}
454
456 struct timespec ts;
457 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
458 UNREACHABLE();
459 return 0;
460 }
461 // Convert to nanoseconds.
462 int64_t result = ts.tv_sec;
464 result += ts.tv_nsec;
465 return result;
466}
467
470}
471
473 int64_t ticks = GetCurrentMonotonicTicks();
475 return ticks / kNanosecondsPerMicrosecond;
476}
477
479 struct timespec ts;
480 if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) {
481 UNREACHABLE();
482 return -1;
483 }
484 int64_t result = ts.tv_sec;
486 result += (ts.tv_nsec / kNanosecondsPerMicrosecond);
487 return result;
488}
489
491#if defined(SUPPORT_TIMELINE)
492 if (Timeline::recorder_discards_clock_values()) return -1;
494#else
495 return -1;
496#endif
497}
498
499// TODO(5411554): May need to hoist these architecture dependent code
500// into a architecture specific file e.g: os_ia32_linux.cc
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;
508#else
509#error Unsupported architecture.
510#endif
511 intptr_t alignment = kMinimumAlignment;
512 // TODO(5411554): Allow overriding default stack alignment for
513 // testing purposes.
514 // Flags::DebugIsInt("stackalign", &alignment);
515 ASSERT(Utils::IsPowerOfTwo(alignment));
516 ASSERT(alignment >= kMinimumAlignment);
517 return alignment;
518}
519
521 return sysconf(_SC_NPROCESSORS_ONLN);
522}
523
524void OS::Sleep(int64_t millis) {
525 int64_t micros = millis * kMicrosecondsPerMillisecond;
526 SleepMicros(micros);
527}
528
529void OS::SleepMicros(int64_t micros) {
530 struct timespec req; // requested.
531 struct timespec rem; // remainder.
532 int64_t seconds = micros / kMicrosecondsPerSecond;
533 micros = micros - seconds * kMicrosecondsPerSecond;
534 int64_t nanos = micros * kNanosecondsPerMicrosecond;
535 req.tv_sec = seconds;
536 req.tv_nsec = nanos;
537 while (true) {
538 int r = nanosleep(&req, &rem);
539 if (r == 0) {
540 break;
541 }
542 // We should only ever see an interrupt error.
543 ASSERT(errno == EINTR);
544 // Copy remainder into requested and repeat.
545 req = rem;
546 }
547}
548
549// TODO(regis): Function called only from the simulator.
550void OS::DebugBreak() {
551 __builtin_trap();
552}
553
554DART_NOINLINE uintptr_t OS::GetProgramCounter() {
555 return reinterpret_cast<uintptr_t>(
556 __builtin_extract_return_addr(__builtin_return_address(0)));
557}
558
559void OS::Print(const char* format, ...) {
560 va_list args;
562 VFPrint(stdout, format, args);
563 va_end(args);
564}
565
566void OS::VFPrint(FILE* stream, const char* format, va_list args) {
567 vfprintf(stream, format, args);
568 fflush(stream);
569}
570
571char* OS::SCreate(Zone* zone, const char* format, ...) {
572 va_list args;
574 char* buffer = VSCreate(zone, format, args);
575 va_end(args);
576 return buffer;
577}
578
579char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
580 // Measure.
581 va_list measure_args;
582 va_copy(measure_args, args);
583 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
584 va_end(measure_args);
585
586 char* buffer;
587 if (zone != nullptr) {
588 buffer = zone->Alloc<char>(len + 1);
589 } else {
590 buffer = reinterpret_cast<char*>(malloc(len + 1));
591 }
592 ASSERT(buffer != nullptr);
593
594 // Print.
595 va_list print_args;
596 va_copy(print_args, args);
597 Utils::VSNPrint(buffer, len + 1, format, print_args);
598 va_end(print_args);
599 return buffer;
600}
601
602bool OS::StringToInt64(const char* str, int64_t* value) {
603 ASSERT(str != nullptr && strlen(str) > 0 && value != nullptr);
604 int32_t base = 10;
605 char* endptr;
606 int i = 0;
607 if (str[0] == '-') {
608 i = 1;
609 } else if (str[0] == '+') {
610 i = 1;
611 }
612 if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
613 (str[i + 2] != '\0')) {
614 base = 16;
615 }
616 errno = 0;
617 if (base == 16) {
618 // Unsigned 64-bit hexadecimal integer literals are allowed but
619 // immediately interpreted as signed 64-bit integers.
620 *value = static_cast<int64_t>(strtoull(str, &endptr, base));
621 } else {
622 *value = strtoll(str, &endptr, base);
623 }
624 return ((errno == 0) && (endptr != str) && (*endptr == 0));
625}
626
628#ifndef PRODUCT
629 if (FLAG_generate_perf_events_symbols) {
630 CodeObservers::Register(new PerfCodeObserver);
631 }
632
633 if (FLAG_generate_perf_jitdump) {
634 CodeObservers::Register(new JitDumpCodeObserver);
635 }
636#endif // !PRODUCT
637}
638
639void OS::PrintErr(const char* format, ...) {
640 va_list args;
642 VFPrint(stderr, format, args);
643 va_end(args);
644}
645
646void OS::Init() {}
647
648void OS::Cleanup() {}
649
650void OS::PrepareToAbort() {}
651
652void OS::Abort() {
654 abort();
655}
656
657void OS::Exit(int code) {
658 exit(code);
659}
660
661OS::BuildId OS::GetAppBuildId(const uint8_t* snapshot_instructions) {
662 // First return the build ID information from the instructions image if
663 // available.
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};
667 }
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;
675 if ((header.p_flags & PF_R) != PF_R) 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));
682 // The note name contains the null terminator as well.
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)};
688 }
689 }
690 return {0, nullptr};
691}
692
693} // namespace dart
694
695#endif // defined(DART_HOST_OS_LINUX)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
static constexpr SkScalar kClose
static const char marker[]
#define UNREACHABLE()
Definition assert.h:248
static void Register(CodeObserver *observer)
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)
Definition os.cc:13
static void Init()
static int64_t GetCurrentTimeMicros()
static intptr_t ActivationFrameAlignment()
static void static void static void VFPrint(FILE *stream, const char *format, va_list args)
static void Cleanup()
static void DebugBreak()
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 int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
static constexpr bool IsPowerOfTwo(T x)
Definition utils.h:61
void(* Dart_FileWriteCallback)(const void *data, intptr_t length, void *stream)
Definition dart_api.h:806
void(* Dart_FileCloseCallback)(void *stream)
Definition dart_api.h:819
void *(* Dart_FileOpenCallback)(const char *name, bool write)
Definition dart_api.h:775
@ kMove
Definition embedder.h:983
#define ASSERT(E)
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent * event
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
#define DECLARE_FLAG(type, name)
Definition flags.h:14
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
const char * name
Definition fuchsia.cc:50
va_start(args, format)
exit(kErrorExitCode)
va_end(args)
constexpr intptr_t kMicrosecondsPerMillisecond
Definition globals.h:561
constexpr intptr_t kMicrosecondsPerSecond
Definition globals.h:562
constexpr intptr_t kNanosecondsPerMicrosecond
Definition globals.h:564
void * malloc(size_t size)
Definition allocation.cc:19
constexpr intptr_t kNanosecondsPerSecond
Definition globals.h:567
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
Definition switches.h:259
CanvasImage Image
Definition dart_ui.cc:55
#define Px
Definition globals.h:410
#define Pd
Definition globals.h:408
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
static const char header[]
Definition skpbench.cpp:88