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

Side by Side Diff: ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc

Issue 876483002: NaCl: Move src/trusted/plugin/ to components/nacl/renderer/plugin/ (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Update #include guards Created 5 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ppapi/native_client/src/trusted/plugin/pnacl_coordinator.h"
6
7 #include <algorithm>
8 #include <sstream>
9 #include <utility>
10
11 #include "native_client/src/include/portability_io.h"
12 #include "native_client/src/shared/platform/nacl_check.h"
13 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
14
15 #include "ppapi/c/pp_bool.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/c/private/ppb_uma_private.h"
18
19 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
20 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
21 #include "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h"
22 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
23 #include "ppapi/native_client/src/trusted/plugin/temporary_file.h"
24
25 namespace plugin {
26
27 namespace {
28
29 const int32_t kSizeKBMin = 1;
30 const int32_t kSizeKBMax = 512*1024; // very large .pexe / .nexe.
31 const uint32_t kSizeKBBuckets = 100;
32
33 const int32_t kRatioMin = 10;
34 const int32_t kRatioMax = 10*100; // max of 10x difference.
35 const uint32_t kRatioBuckets = 100;
36
37 void HistogramSizeKB(pp::UMAPrivate& uma,
38 const std::string& name, int32_t kb) {
39 if (kb < 0) return;
40 uma.HistogramCustomCounts(name,
41 kb,
42 kSizeKBMin, kSizeKBMax,
43 kSizeKBBuckets);
44 }
45
46 void HistogramRatio(pp::UMAPrivate& uma,
47 const std::string& name, int64_t a, int64_t b) {
48 if (a < 0 || b <= 0) return;
49 uma.HistogramCustomCounts(name,
50 static_cast<int32_t>(100 * a / b),
51 kRatioMin, kRatioMax,
52 kRatioBuckets);
53 }
54
55 std::string GetArchitectureAttributes(Plugin* plugin) {
56 pp::Var attrs_var(pp::PASS_REF,
57 plugin->nacl_interface()->GetCpuFeatureAttrs());
58 return attrs_var.AsString();
59 }
60
61 void DidCacheHit(void* user_data, PP_FileHandle nexe_file_handle) {
62 PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data);
63 coordinator->BitcodeStreamCacheHit(nexe_file_handle);
64 }
65
66 void DidCacheMiss(void* user_data, int64_t expected_pexe_size,
67 PP_FileHandle temp_nexe_file) {
68 PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data);
69 coordinator->BitcodeStreamCacheMiss(expected_pexe_size,
70 temp_nexe_file);
71 }
72
73 void DidStreamData(void* user_data, const void* stream_data, int32_t length) {
74 PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data);
75 coordinator->BitcodeStreamGotData(stream_data, length);
76 }
77
78 void DidFinishStream(void* user_data, int32_t pp_error) {
79 PnaclCoordinator* coordinator = static_cast<PnaclCoordinator*>(user_data);
80 coordinator->BitcodeStreamDidFinish(pp_error);
81 }
82
83 PPP_PexeStreamHandler kPexeStreamHandler = {
84 &DidCacheHit,
85 &DidCacheMiss,
86 &DidStreamData,
87 &DidFinishStream
88 };
89
90 } // namespace
91
92 PnaclCoordinator* PnaclCoordinator::BitcodeToNative(
93 Plugin* plugin,
94 const std::string& pexe_url,
95 const PP_PNaClOptions& pnacl_options,
96 const pp::CompletionCallback& translate_notify_callback) {
97 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (plugin=%p, pexe=%s)\n",
98 static_cast<void*>(plugin), pexe_url.c_str()));
99 PnaclCoordinator* coordinator =
100 new PnaclCoordinator(plugin, pexe_url,
101 pnacl_options,
102 translate_notify_callback);
103
104 GetNaClInterface()->SetPNaClStartTime(plugin->pp_instance());
105 int cpus = plugin->nacl_interface()->GetNumberOfProcessors();
106 coordinator->split_module_count_ = std::min(4, std::max(1, cpus));
107
108 // First start a network request for the pexe, to tickle the component
109 // updater's On-Demand resource throttler, and to get Last-Modified/ETag
110 // cache information. We can cancel the request later if there's
111 // a bitcode->nexe cache hit.
112 coordinator->OpenBitcodeStream();
113 return coordinator;
114 }
115
116 PnaclCoordinator::PnaclCoordinator(
117 Plugin* plugin,
118 const std::string& pexe_url,
119 const PP_PNaClOptions& pnacl_options,
120 const pp::CompletionCallback& translate_notify_callback)
121 : translate_finish_error_(PP_OK),
122 plugin_(plugin),
123 translate_notify_callback_(translate_notify_callback),
124 translation_finished_reported_(false),
125 pexe_url_(pexe_url),
126 pnacl_options_(pnacl_options),
127 architecture_attributes_(GetArchitectureAttributes(plugin)),
128 split_module_count_(1),
129 error_already_reported_(false),
130 pexe_size_(0),
131 pexe_bytes_compiled_(0),
132 expected_pexe_size_(-1) {
133 callback_factory_.Initialize(this);
134 }
135
136 PnaclCoordinator::~PnaclCoordinator() {
137 PLUGIN_PRINTF(("PnaclCoordinator::~PnaclCoordinator (this=%p, "
138 "translate_thread=%p\n",
139 static_cast<void*>(this), translate_thread_.get()));
140 // Stopping the translate thread will cause the translate thread to try to
141 // run translation_complete_callback_ on the main thread. This destructor is
142 // running from the main thread, and by the time it exits, callback_factory_
143 // will have been destroyed. This will result in the cancellation of
144 // translation_complete_callback_, so no notification will be delivered.
145 if (translate_thread_.get() != NULL)
146 translate_thread_->AbortSubprocesses();
147 if (!translation_finished_reported_) {
148 plugin_->nacl_interface()->ReportTranslationFinished(
149 plugin_->pp_instance(),
150 PP_FALSE, 0, 0, 0);
151 }
152 // Force deleting the translate_thread now. It must be deleted
153 // before any scoped_* fields hanging off of PnaclCoordinator
154 // since the thread may be accessing those fields.
155 // It will also be accessing obj_files_.
156 translate_thread_.reset(NULL);
157 for (size_t i = 0; i < obj_files_.size(); i++)
158 delete obj_files_[i];
159 }
160
161 PP_FileHandle PnaclCoordinator::TakeTranslatedFileHandle() {
162 DCHECK(temp_nexe_file_ != NULL);
163 return temp_nexe_file_->TakeFileHandle();
164 }
165
166 void PnaclCoordinator::ReportNonPpapiError(PP_NaClError err_code,
167 const std::string& message) {
168 ErrorInfo error_info;
169 error_info.SetReport(err_code, message);
170 plugin_->ReportLoadError(error_info);
171 ExitWithError();
172 }
173
174 void PnaclCoordinator::ReportPpapiError(PP_NaClError err_code,
175 int32_t pp_error,
176 const std::string& message) {
177 std::stringstream ss;
178 ss << "PnaclCoordinator: " << message << " (pp_error=" << pp_error << ").";
179 ErrorInfo error_info;
180 error_info.SetReport(err_code, ss.str());
181 plugin_->ReportLoadError(error_info);
182 ExitWithError();
183 }
184
185 void PnaclCoordinator::ExitWithError() {
186 PLUGIN_PRINTF(("PnaclCoordinator::ExitWithError\n"));
187 // Free all the intermediate callbacks we ever created.
188 // Note: this doesn't *cancel* the callbacks from the factories attached
189 // to the various helper classes (e.g., pnacl_resources). Thus, those
190 // callbacks may still run asynchronously. We let those run but ignore
191 // any other errors they may generate so that they do not end up running
192 // translate_notify_callback_, which has already been freed.
193 callback_factory_.CancelAll();
194 if (!error_already_reported_) {
195 error_already_reported_ = true;
196 translation_finished_reported_ = true;
197 plugin_->nacl_interface()->ReportTranslationFinished(
198 plugin_->pp_instance(),
199 PP_FALSE, 0, 0, 0);
200 translate_notify_callback_.Run(PP_ERROR_FAILED);
201 }
202 }
203
204 // Signal that Pnacl translation completed normally.
205 void PnaclCoordinator::TranslateFinished(int32_t pp_error) {
206 PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%"
207 NACL_PRId32 ")\n", pp_error));
208 // Bail out if there was an earlier error (e.g., pexe load failure),
209 // or if there is an error from the translation thread.
210 if (translate_finish_error_ != PP_OK || pp_error != PP_OK) {
211 plugin_->ReportLoadError(error_info_);
212 ExitWithError();
213 return;
214 }
215
216 // Send out one last progress event, to finish up the progress events
217 // that were delayed (see the delay inserted in BitcodeGotCompiled).
218 if (expected_pexe_size_ != -1) {
219 pexe_bytes_compiled_ = expected_pexe_size_;
220 GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
221 PP_NACL_EVENT_PROGRESS,
222 pexe_url_.c_str(),
223 PP_TRUE,
224 pexe_bytes_compiled_,
225 expected_pexe_size_);
226 }
227 struct nacl_abi_stat stbuf;
228 struct NaClDesc* desc = temp_nexe_file_->read_wrapper()->desc();
229 if (0 == (*((struct NaClDescVtbl const *)desc->base.vtbl)->Fstat)(desc,
230 &stbuf)) {
231 nacl_abi_off_t nexe_size = stbuf.nacl_abi_st_size;
232 HistogramSizeKB(plugin_->uma_interface(),
233 "NaCl.Perf.Size.PNaClTranslatedNexe",
234 static_cast<int32_t>(nexe_size / 1024));
235 HistogramRatio(plugin_->uma_interface(),
236 "NaCl.Perf.Size.PexeNexeSizePct", pexe_size_, nexe_size);
237 }
238 // The nexe is written to the temp_nexe_file_. We must Reset() the file
239 // pointer to be able to read it again from the beginning.
240 temp_nexe_file_->Reset();
241
242 // Report to the browser that translation finished. The browser will take
243 // care of storing the nexe in the cache.
244 translation_finished_reported_ = true;
245 plugin_->nacl_interface()->ReportTranslationFinished(
246 plugin_->pp_instance(), PP_TRUE, pnacl_options_.opt_level,
247 pexe_size_, translate_thread_->GetCompileTime());
248
249 NexeReadDidOpen(PP_OK);
250 }
251
252 void PnaclCoordinator::NexeReadDidOpen(int32_t pp_error) {
253 PLUGIN_PRINTF(("PnaclCoordinator::NexeReadDidOpen (pp_error=%"
254 NACL_PRId32 ")\n", pp_error));
255 if (pp_error != PP_OK) {
256 if (pp_error == PP_ERROR_FILENOTFOUND) {
257 ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_NOTFOUND,
258 pp_error,
259 "Failed to open translated nexe (not found).");
260 return;
261 }
262 if (pp_error == PP_ERROR_NOACCESS) {
263 ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_NOACCESS,
264 pp_error,
265 "Failed to open translated nexe (no access).");
266 return;
267 }
268 ReportPpapiError(PP_NACL_ERROR_PNACL_CACHE_FETCH_OTHER,
269 pp_error,
270 "Failed to open translated nexe.");
271 return;
272 }
273
274 translate_notify_callback_.Run(PP_OK);
275 }
276
277 void PnaclCoordinator::OpenBitcodeStream() {
278 // Even though we haven't started downloading, create the translation
279 // thread object immediately. This ensures that any pieces of the file
280 // that get downloaded before the compilation thread is accepting
281 // SRPCs won't get dropped.
282 translate_thread_.reset(new PnaclTranslateThread());
283 if (translate_thread_ == NULL) {
284 ReportNonPpapiError(
285 PP_NACL_ERROR_PNACL_THREAD_CREATE,
286 "PnaclCoordinator: could not allocate translation thread.");
287 return;
288 }
289
290 GetNaClInterface()->StreamPexe(plugin_->pp_instance(),
291 pexe_url_.c_str(),
292 pnacl_options_.opt_level,
293 &kPexeStreamHandler,
294 this);
295 }
296
297 void PnaclCoordinator::BitcodeStreamCacheHit(PP_FileHandle handle) {
298 if (handle == PP_kInvalidFileHandle) {
299 ReportNonPpapiError(
300 PP_NACL_ERROR_PNACL_CREATE_TEMP,
301 std::string(
302 "PnaclCoordinator: Got bad temp file handle from GetNexeFd"));
303 BitcodeStreamDidFinish(PP_ERROR_FAILED);
304 return;
305 }
306 temp_nexe_file_.reset(new TempFile(plugin_, handle));
307 // Open it for reading as the cached nexe file.
308 NexeReadDidOpen(temp_nexe_file_->Open(false));
309 }
310
311 void PnaclCoordinator::BitcodeStreamCacheMiss(int64_t expected_pexe_size,
312 PP_FileHandle nexe_handle) {
313 // IMPORTANT: Make sure that PnaclResources::StartLoad() is only
314 // called after you receive a response to a request for a .pexe file.
315 //
316 // The component updater's resource throttles + OnDemand update/install
317 // should block the URL request until the compiler is present. Now we
318 // can load the resources (e.g. llc and ld nexes).
319 resources_.reset(new PnaclResources(plugin_));
320 CHECK(resources_ != NULL);
321
322 // The first step of loading resources: read the resource info file.
323 if (!resources_->ReadResourceInfo()) {
324 ExitWithError();
325 return;
326 }
327
328 // Second step of loading resources: call StartLoad to load pnacl-llc
329 // and pnacl-ld, based on the filenames found in the resource info file.
330 if (!resources_->StartLoad()) {
331 ReportNonPpapiError(
332 PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
333 std::string("The Portable Native Client (pnacl) component is not "
334 "installed. Please consult chrome://components for more "
335 "information."));
336 return;
337 }
338
339 expected_pexe_size_ = expected_pexe_size;
340
341 for (int i = 0; i < split_module_count_; i++) {
342 PP_FileHandle obj_handle =
343 plugin_->nacl_interface()->CreateTemporaryFile(plugin_->pp_instance());
344 nacl::scoped_ptr<TempFile> temp_file(new TempFile(plugin_, obj_handle));
345 int32_t pp_error = temp_file->Open(true);
346 if (pp_error != PP_OK) {
347 ReportPpapiError(PP_NACL_ERROR_PNACL_CREATE_TEMP,
348 pp_error,
349 "Failed to open scratch object file.");
350 return;
351 } else {
352 obj_files_.push_back(temp_file.release());
353 }
354 }
355 invalid_desc_wrapper_.reset(plugin_->wrapper_factory()->MakeInvalid());
356
357 temp_nexe_file_.reset(new TempFile(plugin_, nexe_handle));
358 // Open the nexe file for connecting ld and sel_ldr.
359 // Start translation when done with this last step of setup!
360 RunTranslate(temp_nexe_file_->Open(true));
361 }
362
363 void PnaclCoordinator::BitcodeStreamGotData(const void* data, int32_t length) {
364 DCHECK(translate_thread_.get());
365
366 translate_thread_->PutBytes(data, length);
367 if (data && length > 0)
368 pexe_size_ += length;
369 }
370
371 void PnaclCoordinator::BitcodeStreamDidFinish(int32_t pp_error) {
372 PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamDidFinish (pp_error=%"
373 NACL_PRId32 ")\n", pp_error));
374 if (pp_error != PP_OK) {
375 // Defer reporting the error and cleanup until after the translation
376 // thread returns, because it may be accessing the coordinator's
377 // objects or writing to the files.
378 translate_finish_error_ = pp_error;
379 if (pp_error == PP_ERROR_ABORTED) {
380 error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_ABORTED,
381 "PnaclCoordinator: pexe load failed (aborted).");
382 }
383 if (pp_error == PP_ERROR_NOACCESS) {
384 error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_NOACCESS,
385 "PnaclCoordinator: pexe load failed (no access).");
386 } else {
387 std::stringstream ss;
388 ss << "PnaclCoordinator: pexe load failed (pp_error=" << pp_error << ").";
389 error_info_.SetReport(PP_NACL_ERROR_PNACL_PEXE_FETCH_OTHER, ss.str());
390 }
391
392 if (translate_thread_->started())
393 translate_thread_->AbortSubprocesses();
394 else
395 TranslateFinished(pp_error);
396 } else {
397 // Compare download completion pct (100% now), to compile completion pct.
398 HistogramRatio(plugin_->uma_interface(),
399 "NaCl.Perf.PNaClLoadTime.PctCompiledWhenFullyDownloaded",
400 pexe_bytes_compiled_, pexe_size_);
401 translate_thread_->EndStream();
402 }
403 }
404
405 void PnaclCoordinator::BitcodeGotCompiled(int32_t pp_error,
406 int64_t bytes_compiled) {
407 DCHECK(pp_error == PP_OK);
408 pexe_bytes_compiled_ += bytes_compiled;
409 // Hold off reporting the last few bytes of progress, since we don't know
410 // when they are actually completely compiled. "bytes_compiled" only means
411 // that bytes were sent to the compiler.
412 if (expected_pexe_size_ != -1) {
413 if (!ShouldDelayProgressEvent()) {
414 GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
415 PP_NACL_EVENT_PROGRESS,
416 pexe_url_.c_str(),
417 PP_TRUE,
418 pexe_bytes_compiled_,
419 expected_pexe_size_);
420 }
421 } else {
422 GetNaClInterface()->DispatchEvent(plugin_->pp_instance(),
423 PP_NACL_EVENT_PROGRESS,
424 pexe_url_.c_str(),
425 PP_FALSE,
426 pexe_bytes_compiled_,
427 expected_pexe_size_);
428 }
429 }
430
431 pp::CompletionCallback PnaclCoordinator::GetCompileProgressCallback(
432 int64_t bytes_compiled) {
433 return callback_factory_.NewCallback(&PnaclCoordinator::BitcodeGotCompiled,
434 bytes_compiled);
435 }
436
437 void PnaclCoordinator::RunTranslate(int32_t pp_error) {
438 PLUGIN_PRINTF(("PnaclCoordinator::RunTranslate (pp_error=%"
439 NACL_PRId32 ")\n", pp_error));
440 // Invoke llc followed by ld off the main thread. This allows use of
441 // blocking RPCs that would otherwise block the JavaScript main thread.
442 pp::CompletionCallback report_translate_finished =
443 callback_factory_.NewCallback(&PnaclCoordinator::TranslateFinished);
444
445 CHECK(translate_thread_ != NULL);
446 translate_thread_->RunTranslate(report_translate_finished,
447 &obj_files_,
448 temp_nexe_file_.get(),
449 invalid_desc_wrapper_.get(),
450 &error_info_,
451 resources_.get(),
452 &pnacl_options_,
453 architecture_attributes_,
454 this,
455 plugin_);
456 }
457
458 } // namespace plugin
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698