1// Copyright (c) 2017, 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(HOST_OS_LINUX) && defined(SUPPORT_TIMELINE)
7
8#include <errno.h>
9#include <fcntl.h>
10#include <cstdlib>
11
12#include "platform/atomic.h"
13#include "platform/signal_blocker.h"
14#include "vm/isolate.h"
15#include "vm/json_stream.h"
16#include "vm/lockers.h"
17#include "vm/log.h"
18#include "vm/object.h"
19#include "vm/service_event.h"
20#include "vm/thread.h"
21#include "vm/timeline.h"
22
23namespace dart {
24
25DECLARE_FLAG(bool, trace_timeline);
26
27static int OpenTraceFD() {
28 const char* kSystraceDebugPath = "/sys/kernel/debug/tracing/trace_marker";
29 const char* kSystracePath = "/sys/kernel/tracing/trace_marker";
30
31 int fd = TEMP_FAILURE_RETRY(::open(kSystracePath, O_WRONLY));
32 if (fd < 0) {
33 fd = TEMP_FAILURE_RETRY(::open(kSystraceDebugPath, O_WRONLY));
34 }
35
36 if (fd < 0 && FLAG_trace_timeline) {
37 OS::PrintErr("TimelineEventSystraceRecorder: Could not open `%s` or `%s`\n",
38 kSystraceDebugPath, kSystracePath);
39 }
40 return fd;
41}
42
43TimelineEventSystraceRecorder::TimelineEventSystraceRecorder()
44 : TimelineEventPlatformRecorder(), systrace_fd_(OpenTraceFD()) {}
45
46TimelineEventSystraceRecorder::~TimelineEventSystraceRecorder() {
47 if (systrace_fd_ >= 0) {
48 close(systrace_fd_);
49 }
50}
51
52intptr_t TimelineEventSystraceRecorder::PrintSystrace(TimelineEvent* event,
53 char* buffer,
54 intptr_t buffer_size) {
55 ASSERT(buffer != NULL);
56 ASSERT(buffer_size > 0);
57 buffer[0] = '\0';
58 intptr_t length = 0;
59 int64_t pid = OS::ProcessId();
60 switch (event->event_type()) {
61 case TimelineEvent::kBegin: {
62 length = Utils::SNPrint(buffer, buffer_size, "B|%" Pd64 "|%s", pid,
63 event->label());
64 break;
65 }
66 case TimelineEvent::kEnd: {
67 length = Utils::SNPrint(buffer, buffer_size, "E");
68 break;
69 }
70 case TimelineEvent::kCounter: {
71 if (event->arguments_length() > 0) {
72 // We only report the first counter value.
73 length = Utils::SNPrint(buffer, buffer_size, "C|%" Pd64 "|%s|%s", pid,
74 event->label(), event->arguments()[0].value);
75 }
76 break;
77 }
78 case TimelineEvent::kAsyncBegin: {
79 length = Utils::SNPrint(buffer, buffer_size, "S|%" Pd64 "|%s|%" Pd64 "",
80 pid, event->label(), event->AsyncId());
81 break;
82 }
83 case TimelineEvent::kAsyncEnd: {
84 length = Utils::SNPrint(buffer, buffer_size, "F|%" Pd64 "|%s|%" Pd64 "",
85 pid, event->label(), event->AsyncId());
86 break;
87 }
88 default:
89 // Ignore event types that we cannot serialize to the Systrace format.
90 break;
91 }
92 return length;
93}
94
95void TimelineEventSystraceRecorder::OnEvent(TimelineEvent* event) {
96 if (event == NULL) {
97 return;
98 }
99 if (systrace_fd_ < 0) {
100 return;
101 }
102
103 // Serialize to the systrace format.
104 const intptr_t kBufferLength = 1024;
105 char buffer[kBufferLength];
106 const intptr_t event_length = PrintSystrace(event, &buffer[0], kBufferLength);
107 if (event_length > 0) {
108 ssize_t result;
109 // Repeatedly attempt the write while we are being interrupted.
110 do {
111 result = write(systrace_fd_, buffer, event_length);
112 } while ((result == -1L) && (errno == EINTR));
113 }
114}
115
116} // namespace dart
117
118#endif // defined(HOST_OS_LINUX) && !defined(PRODUCT)
119