Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(650)

Side by Side Diff: runtime/bin/vmstats.cc

Issue 12221022: Initial prototype of vmstats support, based on Dart VM Stats draft design doc. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
siva 2013/02/09 01:00:57 2013
Tom Ball 2013/02/14 23:45:16 Done.
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 "bin/vmstats.h"
6
7 #include "bin/fdutils.h"
8 #include "bin/file.h"
9 #include "bin/platform.h"
10 #include "bin/socket.h"
11 #include "platform/json.h"
12 #include "platform/thread.h"
13
14 namespace dart {
15
16 #define BUFSIZE 8192
17
18 // Global static pointer used to ensure a single instance of the class.
19 VmStats* VmStats::instance_ = NULL;
20
21
22 void VmStats::Start(int port) {
23 if (instance_ != NULL) {
24 FATAL("VmStats already started.");
25 }
26 VmStats* vmstats = new VmStats;
27 Socket::Initialize();
28
29 // TODO(tball): replace $HOME with SDK-specific path to web server's
30 // root directory.
31 intptr_t num_vars;
32 char** env = Platform::Environment(&num_vars);
siva 2013/02/09 01:00:57 Are you going to switch this to be a command line
Tom Ball 2013/02/14 23:45:16 Done. I added a flag that optionally sets root dir
33 for (int i = 0; i < num_vars; i++) {
34 char* var = env[i];
35 if (strncmp(var, "HOME=", 5) == 0) {
36 char* home = var + 5;
37 ASSERT(strlen(home) > 0);
38 vmstats->root_directory_ = home;
39 vmstats->root_directory_.append("/vmstats");
40 break;
41 }
42 }
43 Platform::FreeEnvironment(env, num_vars);
44 ASSERT(vmstats->root_directory_.length() > 0);
45
46 const intptr_t BACKLOG = 128; // Default value from HttpServer.dart
47 intptr_t bind_address =
48 ServerSocket::CreateBindListen("127.0.0.1", port, BACKLOG);
siva 2013/02/09 01:00:57 fine for now but we may want to make 127.0.0.1 a p
Tom Ball 2013/02/14 23:45:16 Sounds great -- any security issues with making th
49 if (bind_address < 0) {
50 fprintf(stderr, "Failed binding VmStats socket: 127.0.0.1:%d\n", port);
51 return;
52 }
53 int errno = Thread::Start(WebServer, bind_address);
54 if (errno != 0) {
55 fprintf(stderr, "Failed starting VmStats thread: %d\n", errno);
56 return;
57 }
58 instance_ = vmstats;
59 }
60
61
62 void VmStats::Stop() {
63 if (instance_ != NULL) {
64 delete instance_;
65 instance_ = NULL;
66 }
67 }
68
69
70
71 void VmStats::AddIsolate(IsolateData* isolate_data,
72 Dart_Isolate isolate) {
siva 2013/02/09 01:00:57 .... indentation.
Tom Ball 2013/02/14 23:45:16 Done.
73 if (instance_ != NULL) {
74 instance_->isolate_table_[isolate_data] = isolate;
siva 2013/02/11 19:14:55 This method needs to be thread safe right as we ca
Tom Ball 2013/02/14 23:45:16 Done.
75 }
76 }
77
78
79 void VmStats::RemoveIsolate(IsolateData* isolate_data) {
siva 2013/02/11 19:14:55 Ditto comment about this method being thread safe.
Tom Ball 2013/02/14 23:45:16 Done.
80 if (instance_ != NULL) {
81 instance_->isolate_table_.erase(isolate_data);
82 }
83 }
84
85
86 static bool endsWith(const std::string s, const char* ending) {
87 size_t ending_len = strlen(ending);
88 if (s.length() > ending_len) {
89 return s.compare(s.length() - ending_len, ending_len, ending) == 0;
90 } else {
91 return false;
92 }
93 }
94
95
96 static const char* ContentType(const char* url) {
97 // TODO(tball): replace with static map?
98 std::string path(url);
99 if (endsWith(path, ".html")) {
100 return "text/html; charset=UTF-8";
101 }
102 if (endsWith(path, ".dart")) {
103 return "application/dart; charset=UTF-8";
104 }
105 if (endsWith(path, ".js")) {
106 return "application/javascript; charset=UTF-8";
107 }
108 if (endsWith(path, ".css")) {
109 return "text/css; charset=UTF-8";
110 }
111 if (endsWith(path, ".gif")) {
112 return "image/gif";
113 }
114 if (endsWith(path, ".png")) {
115 return "image/png";
116 }
117 if (endsWith(path, ".jpg") || endsWith(path, ".jpeg")) {
118 return "image/jpeg";
119 }
120 return "text/plain";
121 }
122
123
124 void VmStats::WebServer(uword bind_address) {
125 while (true) {
126 intptr_t socket = ServerSocket::Accept(bind_address);
127 if (socket == ServerSocket::kTemporaryFailure) {
128 // Not a real failure, woke up but no connection available.
129 sleep(1);
130 continue;
131 }
132 if (socket < 0) {
133 FATAL("Accepting new web server connection failed.\n");
134 }
135 FDUtils::SetBlocking(socket);
136
137 // Read request.
138 static char buffer[BUFSIZE + 1];
139 int len = read(socket, buffer, BUFSIZE);
siva 2013/02/09 01:00:57 How do you deal with partial reads here (e.g: the
140 if (len <= 0) {
141 // Invalid HTTP request, ignore.
142 continue;
143 }
144 buffer[len] = '\0';
145
146 // Verify it's a GET request.
147 if (strncmp("GET ", buffer, 4) != 0 && strncmp("get ", buffer, 4) != 0) {
148 fprintf(stderr, "Unsupported HTTP request type");
149 const char* response = "HTTP/1.1 403 Forbidden\n"
150 "Content-Length: 120\n"
151 "Connection: close\n"
152 "Content-Type: text/html\n\n"
153 "<html><head>\n<title>403 Forbidden</title>\n</head>"
154 "<body>\n<h1>Forbidden</h1>\nUnsupported HTTP request type\n</body>"
155 "</html>\n";
156 Socket::Write(socket, response, strlen(response));
siva 2013/02/09 01:00:57 In all these writes I would assert that the return
157 close(socket);
158 continue;
159 }
160
161 // Extract GET URL.
162 for (int i = 4; i < len; i++) {
163 if (buffer[i] == ' ') {
164 buffer[i] = '\0';
165 break;
166 }
167 }
168 char* url = &buffer[4];
169 printf("vmstats: %s requested\n", url);
170 // TODO(tball): parse URL to determine data requested.
171 if (strcmp(url, "/isolates") == 0) {
172 std::ostringstream stream;
173 stream << '{' << std::endl;
174 instance_->MemoryUsed(&stream);
siva 2013/02/09 01:00:57 Instead of MemoryUsed you could probably call this
Tom Ball 2013/02/14 23:45:16 Done.
175 // TODO(tball): add other metrics, separated by commas.
176 stream << std::endl << '}' << std::endl;
177 std::string content = stream.str();
178
179 len = snprintf(buffer, BUFSIZE-1,
180 "HTTP/1.1 200 OK\n:Content-Type: application/json; charset=UTF-8\n"
181 "Content-Length: %d\n\n", static_cast<int>(content.length()));
182 Socket::Write(socket, buffer, strlen(buffer));
183 Socket::Write(socket, content.c_str(), content.length());
184 Socket::Write(socket, "\n", 1);
185 Socket::Write(socket, buffer, strlen(buffer));
186 } else {
siva 2013/02/09 01:00:57 I assume this else section is present for serving
Tom Ball 2013/02/14 23:45:16 Done.
187 std::string path(instance_->root_directory_);
188 path.append(url);
189 bool success = false;
190 if (File::Exists(path.c_str())) {
191 File* f = File::Open(path.c_str(), File::kRead);
192 if (f != NULL) {
193 intptr_t len = f->Length();
194 char* text_buffer = reinterpret_cast<char*>(malloc(len));
195 if (f->ReadFully(text_buffer, len)) {
196 std::string content(text_buffer, len);
197 const char* content_type = ContentType(url);
198 len = snprintf(buffer, BUFSIZE-1,
199 "HTTP/1.1 200 OK\n:Content-Type: %s\n"
200 "Content-Length: %d\n\n",
201 content_type, static_cast<int>(content.length()));
202 Socket::Write(socket, buffer, strlen(buffer));
203 Socket::Write(socket, content.c_str(), content.length());
204 Socket::Write(socket, "\n", 1);
205 success = true;
206 }
207 free(text_buffer);
208 delete f;
209 }
210 }
211 if (!success) {
212 const char* response = "HTTP/1.1 404 Not Found\n\n";
213 Socket::Write(socket, response, strlen(response));
214 }
215 }
216 close(socket);
217 }
218 }
219
220
221 void VmStats::MemoryUsed(std::ostringstream* stream) {
222 *stream << "\"isolates\": [" << std::endl;
223 IsolateTable::iterator itr;
224 bool first = true;
225 for (itr = isolate_table_.begin(); itr != isolate_table_.end(); ++itr) {
226 if (!first) {
227 *stream << "," << std::endl;
228 }
229 first = false;
230
231 Dart_Isolate isolate = itr->second;
232 static char request[512];
233 snprintf(request, sizeof(request), "/isolate/0x%llx",
234 reinterpret_cast<int64_t>(isolate));
235 char* status = Dart_GetVmStatus(request);
236 *stream << status;
237 free(status);
238 }
239 *stream << std::endl << "]";
240 }
241
242
243 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698