Commit a91b574d authored by dschuff@chromium.org's avatar dschuff@chromium.org

PnaclCoordinator: Use llc's module-splitting for pexe compilation

When there is more than 1 core in the system, request extra temp files
and use LLC's StreamInitWithSplit rpc to enable module splitting.
If the RPC fails, fall back to StreamInitWithOverrides.

Add a private Pepper interface to get the cpu count rather than
duplicating base::SysInfo in the plugin.

TEST=browser_tests --gtest_filter=NaClBrowserTstPnacl.*
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3777
R=jschuh@chromium.org, jvoung@chromium.org, teravest@chromium.org

Review URL: https://codereview.chromium.org/165433003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251458 0039d316-1c4b-4281-b951-d872f2087c98
parent 4532c970
......@@ -4,6 +4,7 @@
#include "components/nacl/browser/nacl_host_message_filter.h"
#include "base/sys_info.h"
#include "components/nacl/browser/nacl_browser.h"
#include "components/nacl/browser/nacl_file_host.h"
#include "components/nacl/browser/nacl_process_host.h"
......@@ -52,6 +53,8 @@ bool NaClHostMessageFilter::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_HANDLER(NaClHostMsg_NaClErrorStatus, OnNaClErrorStatus)
IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_OpenNaClExecutable,
OnOpenNaClExecutable)
IPC_MESSAGE_HANDLER(NaClHostMsg_NaClGetNumProcessors,
OnNaClGetNumProcessors)
#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
......@@ -133,6 +136,10 @@ void NaClHostMessageFilter::AsyncReturnTemporaryFile(
IPC::GetFileHandleForProcess(fd, PeerHandle(), false)));
}
void NaClHostMessageFilter::OnNaClGetNumProcessors(int *num_processors) {
*num_processors = base::SysInfo::NumberOfProcessors();
}
void NaClHostMessageFilter::OnGetNexeFd(
int render_view_id,
int pp_instance,
......
......@@ -54,6 +54,7 @@ class NaClHostMessageFilter : public content::BrowserMessageFilter {
void OnGetReadonlyPnaclFd(const std::string& filename,
IPC::Message* reply_msg);
void OnNaClCreateTemporaryFile(IPC::Message* reply_msg);
void OnNaClGetNumProcessors(int* num_processors);
void OnGetNexeFd(int render_view_id,
int pp_instance,
const PnaclCacheInfo& cache_info);
......
......@@ -99,3 +99,6 @@ IPC_SYNC_MESSAGE_CONTROL2_3(NaClHostMsg_OpenNaClExecutable,
IPC::PlatformFileForTransit /* output file */,
uint64 /* file_token_lo */,
uint64 /* file_token_hi */)
IPC_SYNC_MESSAGE_CONTROL0_1(NaClHostMsg_NaClGetNumProcessors,
int /* Number of processors */)
......@@ -256,6 +256,16 @@ PP_FileHandle CreateTemporaryFile(PP_Instance instance) {
return handle;
}
int32_t GetNumberOfProcessors() {
int32_t num_processors;
IPC::Sender* sender = content::RenderThread::Get();
DCHECK(sender);
if(!sender->Send(new NaClHostMsg_NaClGetNumProcessors(&num_processors))) {
return 1;
}
return num_processors;
}
int32_t GetNexeFd(PP_Instance instance,
const char* pexe_url,
uint32_t abi_version,
......@@ -465,6 +475,7 @@ const PPB_NaCl_Private nacl_interface = {
&BrokerDuplicateHandle,
&GetReadonlyPnaclFD,
&CreateTemporaryFile,
&GetNumberOfProcessors,
&GetNexeFd,
&ReportTranslationFinished,
&ReportNaClError,
......
......@@ -110,6 +110,9 @@ interface PPB_NaCl_Private {
*/
PP_FileHandle CreateTemporaryFile([in] PP_Instance instance);
/* Return the number of processors in the system as reported by the OS */
int32_t GetNumberOfProcessors();
/* Create a temporary file, which will be deleted by the time the
* last handle is closed (or earlier on POSIX systems), to use for
* the nexe with the cache information given by |pexe_url|,
......
......@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
/* From private/ppb_nacl_private.idl modified Mon Feb 10 11:05:29 2014. */
/* From private/ppb_nacl_private.idl modified Thu Feb 13 15:50:26 2014. */
#ifndef PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
#define PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
......@@ -127,6 +127,8 @@ struct PPB_NaCl_Private_1_0 {
* returns a posix handle to that temporary file.
*/
PP_FileHandle (*CreateTemporaryFile)(PP_Instance instance);
/* Return the number of processors in the system as reported by the OS */
int32_t (*GetNumberOfProcessors)(void);
/* Create a temporary file, which will be deleted by the time the
* last handle is closed (or earlier on POSIX systems), to use for
* the nexe with the cache information given by |pexe_url|,
......
......@@ -200,6 +200,9 @@ PnaclCoordinator* PnaclCoordinator::BitcodeToNative(
PLUGIN_PRINTF(("PnaclCoordinator::BitcodeToNative (manifest=%p, ",
reinterpret_cast<const void*>(coordinator->manifest_.get())));
int cpus = plugin->nacl_interface()->GetNumberOfProcessors();
coordinator->split_module_count_ = std::min(4, std::max(1, cpus));
// First start a network request for the pexe, to tickle the component
// updater's On-Demand resource throttler, and to get Last-Modified/ETag
// cache information. We can cancel the request later if there's
......@@ -220,6 +223,8 @@ PnaclCoordinator::PnaclCoordinator(
manifest_(new PnaclManifest()),
pexe_url_(pexe_url),
pnacl_options_(pnacl_options),
split_module_count_(1),
num_object_files_opened_(0),
is_cache_hit_(PP_FALSE),
error_already_reported_(false),
pnacl_init_time_(0),
......@@ -248,6 +253,9 @@ PnaclCoordinator::~PnaclCoordinator() {
plugin_->pp_instance(),
PP_FALSE);
}
for (int i = 0; i < num_object_files_opened_; i++) {
delete obj_files_[i];
}
}
nacl::DescWrapper* PnaclCoordinator::ReleaseTranslatedFD() {
......@@ -531,10 +539,14 @@ void PnaclCoordinator::NexeFdDidOpen(int32_t pp_error) {
} else {
// Open an object file first so the translator can start writing to it
// during streaming translation.
obj_file_.reset(new TempFile(plugin_));
pp::CompletionCallback obj_cb =
callback_factory_.NewCallback(&PnaclCoordinator::ObjectFileDidOpen);
obj_file_->Open(obj_cb, true);
for (int i = 0; i < split_module_count_; i++) {
obj_files_.push_back(new TempFile(plugin_));
pp::CompletionCallback obj_cb =
callback_factory_.NewCallback(&PnaclCoordinator::ObjectFileDidOpen);
obj_files_[i]->Open(obj_cb, true);
}
invalid_desc_wrapper_.reset(plugin_->wrapper_factory()->MakeInvalid());
// Meanwhile, a miss means we know we need to stream the bitcode, so stream
// the rest of it now. (Calling FinishStreaming means that the downloader
......@@ -643,11 +655,14 @@ void PnaclCoordinator::ObjectFileDidOpen(int32_t pp_error) {
"Failed to open scratch object file.");
return;
}
// Open the nexe file for connecting ld and sel_ldr.
// Start translation when done with this last step of setup!
pp::CompletionCallback cb =
callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate);
temp_nexe_file_->Open(cb, true);
num_object_files_opened_++;
if (num_object_files_opened_ == split_module_count_) {
// Open the nexe file for connecting ld and sel_ldr.
// Start translation when done with this last step of setup!
pp::CompletionCallback cb =
callback_factory_.NewCallback(&PnaclCoordinator::RunTranslate);
temp_nexe_file_->Open(cb, true);
}
}
void PnaclCoordinator::RunTranslate(int32_t pp_error) {
......@@ -661,8 +676,9 @@ void PnaclCoordinator::RunTranslate(int32_t pp_error) {
CHECK(translate_thread_ != NULL);
translate_thread_->RunTranslate(report_translate_finished,
manifest_.get(),
obj_file_.get(),
&obj_files_,
temp_nexe_file_.get(),
invalid_desc_wrapper_.get(),
&error_info_,
resources_.get(),
&pnacl_options_,
......
......@@ -77,6 +77,9 @@ class TempFile;
// Complete when NexeReadDidOpen is invoked.
class PnaclCoordinator: public CallbackSource<FileStreamData> {
public:
// Maximum number of object files passable to the translator. Cannot be
// changed without changing the RPC signatures.
const static size_t kMaxTranslatorObjectFiles = 16;
virtual ~PnaclCoordinator();
// The factory method for translations.
......@@ -202,7 +205,12 @@ class PnaclCoordinator: public CallbackSource<FileStreamData> {
PnaclOptions pnacl_options_;
// Object file, produced by the translator and consumed by the linker.
nacl::scoped_ptr<TempFile> obj_file_;
std::vector<TempFile*> obj_files_;
nacl::scoped_ptr<nacl::DescWrapper> invalid_desc_wrapper_;
// Number of split modules (threads) for llc
int split_module_count_;
int num_object_files_opened_;
// Translated nexe file, produced by the linker.
nacl::scoped_ptr<TempFile> temp_nexe_file_;
// Passed to the browser, which sets it to true if there is a translation
......
......@@ -4,6 +4,8 @@
#include "ppapi/native_client/src/trusted/plugin/pnacl_translate_thread.h"
#include <iterator>
#include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
#include "ppapi/native_client/src/trusted/plugin/plugin.h"
#include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
......@@ -19,7 +21,7 @@ PnaclTranslateThread::PnaclTranslateThread() : llc_subprocess_active_(false),
done_(false),
time_stats_(),
manifest_(NULL),
obj_file_(NULL),
obj_files_(NULL),
nexe_file_(NULL),
coordinator_error_info_(NULL),
resources_(NULL),
......@@ -33,8 +35,9 @@ PnaclTranslateThread::PnaclTranslateThread() : llc_subprocess_active_(false),
void PnaclTranslateThread::RunTranslate(
const pp::CompletionCallback& finish_callback,
const Manifest* manifest,
TempFile* obj_file,
const std::vector<TempFile*>* obj_files,
TempFile* nexe_file,
nacl::DescWrapper* invalid_desc_wrapper,
ErrorInfo* error_info,
PnaclResources* resources,
PnaclOptions* pnacl_options,
......@@ -42,8 +45,9 @@ void PnaclTranslateThread::RunTranslate(
Plugin* plugin) {
PLUGIN_PRINTF(("PnaclStreamingTranslateThread::RunTranslate)\n"));
manifest_ = manifest;
obj_file_ = obj_file;
obj_files_ = obj_files;
nexe_file_ = nexe_file;
invalid_desc_wrapper_ = invalid_desc_wrapper;
coordinator_error_info_ = error_info;
resources_ = resources;
pnacl_options_ = pnacl_options;
......@@ -130,7 +134,14 @@ void WINAPI PnaclTranslateThread::DoTranslateThread(void* arg) {
void PnaclTranslateThread::DoTranslate() {
ErrorInfo error_info;
SrpcParams params;
nacl::DescWrapper* llc_out_file = obj_file_->write_wrapper();
std::vector<nacl::DescWrapper*> llc_out_files;
size_t i;
for (i = 0; i < obj_files_->size(); i++) {
llc_out_files.push_back((*obj_files_)[i]->write_wrapper());
}
for (; i < PnaclCoordinator::kMaxTranslatorObjectFiles; i++) {
llc_out_files.push_back(invalid_desc_wrapper_);
}
{
nacl::MutexLocker ml(&subprocess_mu_);
......@@ -149,19 +160,60 @@ void PnaclTranslateThread::DoTranslate() {
// Run LLC.
PluginReverseInterface* llc_reverse =
llc_subprocess_->service_runtime()->rev_interface();
llc_reverse->AddTempQuotaManagedFile(obj_file_->identifier());
for (size_t i = 0; i < obj_files_->size(); i++) {
llc_reverse->AddTempQuotaManagedFile((*obj_files_)[i]->identifier());
}
}
int64_t compile_start_time = NaClGetTimeOfDayMicroseconds();
bool init_success;
std::vector<char> options = pnacl_options_->GetOptCommandline();
// Try to init with splitting
// TODO(dschuff): This CL override is ugly. Change llc to default to using
// the number of modules specified in the first param, and ignore multiple
// uses of -split-module
std::vector<char> split_args;
nacl::stringstream ss;
ss << "-split-module=" << obj_files_->size();
nacl::string split_arg = ss.str();
std::copy(split_arg.begin(), split_arg.end(), std::back_inserter(split_args));
split_args.push_back('\x00');
std::copy(options.begin(), options.end(), std::back_inserter(split_args));
int modules_used = static_cast<int>(obj_files_->size());
init_success = llc_subprocess_->InvokeSrpcMethod(
"StreamInitWithOverrides",
"hC",
"StreamInitWithSplit",
"ihhhhhhhhhhhhhhhhC",
&params,
llc_out_file->desc(),
&options[0],
options.size());
modules_used,
llc_out_files[0]->desc(),
llc_out_files[1]->desc(),
llc_out_files[2]->desc(),
llc_out_files[3]->desc(),
llc_out_files[4]->desc(),
llc_out_files[5]->desc(),
llc_out_files[6]->desc(),
llc_out_files[7]->desc(),
llc_out_files[8]->desc(),
llc_out_files[9]->desc(),
llc_out_files[10]->desc(),
llc_out_files[11]->desc(),
llc_out_files[12]->desc(),
llc_out_files[13]->desc(),
llc_out_files[14]->desc(),
llc_out_files[15]->desc(),
&split_args[0],
split_args.size());
if (!init_success) {
init_success = llc_subprocess_->InvokeSrpcMethod(
"StreamInitWithOverrides",
"hC",
&params,
llc_out_files[0]->desc(),
&options[0],
options.size());
modules_used = 1;
}
if (!init_success) {
if (llc_subprocess_->srpc_client()->GetLastError() ==
......@@ -256,25 +308,36 @@ void PnaclTranslateThread::DoTranslate() {
llc_subprocess_.reset(NULL);
NaClXMutexUnlock(&subprocess_mu_);
if(!RunLdSubprocess(is_shared_library, soname, lib_dependencies)) {
if(!RunLdSubprocess(
modules_used, is_shared_library, soname, lib_dependencies)) {
return;
}
core->CallOnMainThread(0, report_translate_finished_, PP_OK);
}
bool PnaclTranslateThread::RunLdSubprocess(int is_shared_library,
bool PnaclTranslateThread::RunLdSubprocess(int modules_used,
int is_shared_library,
const nacl::string& soname,
const nacl::string& lib_dependencies
) {
ErrorInfo error_info;
SrpcParams params;
// Reset object file for reading first.
if (!obj_file_->Reset()) {
TranslateFailed(ERROR_PNACL_LD_SETUP,
"Link process could not reset object file");
return false;
std::vector<nacl::DescWrapper*> ld_in_files;
size_t i;
for (i = 0; i < obj_files_->size(); i++) {
// Reset object file for reading first.
if (!(*obj_files_)[i]->Reset()) {
TranslateFailed(ERROR_PNACL_LD_SETUP,
"Link process could not reset object file");
return false;
}
ld_in_files.push_back((*obj_files_)[i]->read_wrapper());
}
nacl::DescWrapper* ld_in_file = obj_file_->read_wrapper();
for (; i < PnaclCoordinator::kMaxTranslatorObjectFiles; i++) {
ld_in_files.push_back(invalid_desc_wrapper_);
}
nacl::DescWrapper* ld_out_file = nexe_file_->write_wrapper();
{
......@@ -299,14 +362,41 @@ bool PnaclTranslateThread::RunLdSubprocess(int is_shared_library,
int64_t link_start_time = NaClGetTimeOfDayMicroseconds();
// Run LD.
if (!ld_subprocess_->InvokeSrpcMethod("RunWithDefaultCommandLine",
"hhiss",
&params,
ld_in_file->desc(),
ld_out_file->desc(),
is_shared_library,
soname.c_str(),
lib_dependencies.c_str())) {
bool success;
// If we ran LLC with module splitting, we can't fall back here.
if (modules_used > 1) {
success = ld_subprocess_->InvokeSrpcMethod("RunWithSplit",
"ihhhhhhhhhhhhhhhhh",
&params,
modules_used,
ld_in_files[0]->desc(),
ld_in_files[1]->desc(),
ld_in_files[2]->desc(),
ld_in_files[3]->desc(),
ld_in_files[4]->desc(),
ld_in_files[5]->desc(),
ld_in_files[6]->desc(),
ld_in_files[7]->desc(),
ld_in_files[8]->desc(),
ld_in_files[9]->desc(),
ld_in_files[10]->desc(),
ld_in_files[11]->desc(),
ld_in_files[12]->desc(),
ld_in_files[13]->desc(),
ld_in_files[14]->desc(),
ld_in_files[15]->desc(),
ld_out_file->desc());
} else {
success = ld_subprocess_->InvokeSrpcMethod("RunWithDefaultCommandLine",
"hhiss",
&params,
ld_in_files[0]->desc(),
ld_out_file->desc(),
is_shared_library,
soname.c_str(),
lib_dependencies.c_str());
}
if (!success) {
TranslateFailed(ERROR_PNACL_LD_INTERNAL,
"link failed.");
return false;
......
......@@ -50,8 +50,9 @@ class PnaclTranslateThread {
// as it is passed in with PutBytes.
void RunTranslate(const pp::CompletionCallback& finish_callback,
const Manifest* manifest,
TempFile* obj_file,
const std::vector<TempFile*>* obj_files,
TempFile* nexe_file,
nacl::DescWrapper* invalid_desc_wrapper,
ErrorInfo* error_info,
PnaclResources* resources,
PnaclOptions* pnacl_options,
......@@ -85,7 +86,8 @@ class PnaclTranslateThread {
void TranslateFailed(enum PluginErrorCode err_code,
const nacl::string& error_string);
// Run the LD subprocess, returning true on success
bool RunLdSubprocess(int is_shared_library,
bool RunLdSubprocess(int modules_used,
int is_shared_library,
const nacl::string& soname,
const nacl::string& lib_dependencies);
......@@ -121,8 +123,9 @@ class PnaclTranslateThread {
// Data about the translation files, owned by the coordinator
const Manifest* manifest_;
TempFile* obj_file_;
const std::vector<TempFile*>* obj_files_;
TempFile* nexe_file_;
nacl::DescWrapper* invalid_desc_wrapper_;
ErrorInfo* coordinator_error_info_;
PnaclResources* resources_;
PnaclOptions* pnacl_options_;
......
......@@ -3144,6 +3144,11 @@ static PP_FileHandle Pnacl_M25_PPB_NaCl_Private_CreateTemporaryFile(PP_Instance
return iface->CreateTemporaryFile(instance);
}
static int32_t Pnacl_M25_PPB_NaCl_Private_GetNumberOfProcessors(void) {
const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface;
return iface->GetNumberOfProcessors();
}
static int32_t Pnacl_M25_PPB_NaCl_Private_GetNexeFd(PP_Instance instance, const char* pexe_url, uint32_t abi_version, uint32_t opt_level, const char* last_modified, const char* etag, PP_Bool has_no_store_header, PP_Bool* is_hit, PP_FileHandle* nexe_handle, struct PP_CompletionCallback* callback) {
const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface;
return iface->GetNexeFd(instance, pexe_url, abi_version, opt_level, last_modified, etag, has_no_store_header, is_hit, nexe_handle, *callback);
......@@ -5045,6 +5050,7 @@ static struct PPB_NaCl_Private_1_0 Pnacl_Wrappers_PPB_NaCl_Private_1_0 = {
.BrokerDuplicateHandle = (int32_t (*)(PP_FileHandle source_handle, uint32_t process_id, PP_FileHandle* target_handle, uint32_t desired_access, uint32_t options))&Pnacl_M25_PPB_NaCl_Private_BrokerDuplicateHandle,
.GetReadonlyPnaclFd = (PP_FileHandle (*)(const char* filename))&Pnacl_M25_PPB_NaCl_Private_GetReadonlyPnaclFd,
.CreateTemporaryFile = (PP_FileHandle (*)(PP_Instance instance))&Pnacl_M25_PPB_NaCl_Private_CreateTemporaryFile,
.GetNumberOfProcessors = (int32_t (*)(void))&Pnacl_M25_PPB_NaCl_Private_GetNumberOfProcessors,
.GetNexeFd = (int32_t (*)(PP_Instance instance, const char* pexe_url, uint32_t abi_version, uint32_t opt_level, const char* last_modified, const char* etag, PP_Bool has_no_store_header, PP_Bool* is_hit, PP_FileHandle* nexe_handle, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_NaCl_Private_GetNexeFd,
.ReportTranslationFinished = (void (*)(PP_Instance instance, PP_Bool success))&Pnacl_M25_PPB_NaCl_Private_ReportTranslationFinished,
.ReportNaClError = (PP_ExternalPluginResult (*)(PP_Instance instance, PP_NaClError message_id))&Pnacl_M25_PPB_NaCl_Private_ReportNaClError,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment