gecko-dev/js/xpconnect/loader/ScriptPreloader-inl.h

312 lines
6.5 KiB
C
Raw Normal View History

Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ScriptPreloader_inl_h
#define ScriptPreloader_inl_h
#include "mozilla/Attributes.h"
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/EnumSet.h"
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
#include "mozilla/Range.h"
#include "mozilla/ResultExtensions.h"
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
#include "mozilla/Unused.h"
#include "mozilla/dom/ScriptSettings.h"
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
#include "nsString.h"
#include "nsTArray.h"
#include <prio.h>
namespace mozilla {
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
namespace loader {
using mozilla::dom::AutoJSAPI;
struct MOZ_RAII AutoSafeJSAPI : public AutoJSAPI
{
AutoSafeJSAPI() { Init(); }
};
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
class OutputBuffer
{
public:
OutputBuffer()
{}
uint8_t*
write(size_t size)
{
auto buf = data.AppendElements(size);
cursor_ += size;
return buf;
}
void
codeUint8(const uint8_t& val)
{
*write(sizeof val) = val;
}
template<typename T>
void
codeUint8(const EnumSet<T>& val)
{
// EnumSets are always represented as uint32_t values, so we need to
// assert that the value actually fits in a uint8 before writing it.
uint32_t value = val.serialize();
codeUint8(CheckedUint8(value).value());
}
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
void
codeUint16(const uint16_t& val)
{
LittleEndian::writeUint16(write(sizeof val), val);
}
void
codeUint32(const uint32_t& val)
{
LittleEndian::writeUint32(write(sizeof val), val);
}
void
codeString(const nsCString& str)
{
auto len = CheckedUint16(str.Length()).value();
codeUint16(len);
memcpy(write(len), str.BeginReading(), len);
}
size_t cursor() const { return cursor_; }
uint8_t* Get() { return data.Elements(); }
const uint8_t* Get() const { return data.Elements(); }
private:
nsTArray<uint8_t> data;
size_t cursor_ = 0;
};
class InputBuffer
{
public:
explicit InputBuffer(const Range<uint8_t>& buffer)
: data(buffer)
{}
const uint8_t*
read(size_t size)
{
MOZ_ASSERT(checkCapacity(size));
auto buf = &data[cursor_];
cursor_ += size;
return buf;
}
bool
codeUint8(uint8_t& val)
{
if (checkCapacity(sizeof val)) {
val = *read(sizeof val);
}
return !error_;
}
template<typename T>
bool
codeUint8(EnumSet<T>& val)
{
uint8_t value;
if (codeUint8(value)) {
val.deserialize(value);
}
return !error_;
}
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
bool
codeUint16(uint16_t& val)
{
if (checkCapacity(sizeof val)) {
val = LittleEndian::readUint16(read(sizeof val));
}
return !error_;
}
bool
codeUint32(uint32_t& val)
{
if (checkCapacity(sizeof val)) {
val = LittleEndian::readUint32(read(sizeof val));
}
return !error_;
}
bool
codeString(nsCString& str)
{
uint16_t len;
if (codeUint16(len)) {
if (checkCapacity(len)) {
str.SetLength(len);
memcpy(str.BeginWriting(), read(len), len);
}
}
return !error_;
}
bool error() { return error_; }
bool finished() { return error_ || !remainingCapacity(); }
size_t remainingCapacity() { return data.length() - cursor_; }
size_t cursor() const { return cursor_; }
const uint8_t* Get() const { return data.begin().get(); }
private:
bool
checkCapacity(size_t size)
{
if (size > remainingCapacity()) {
error_ = true;
}
return !error_;
}
bool error_ = false;
public:
const Range<uint8_t>& data;
size_t cursor_ = 0;
};
template <typename T> struct Matcher;
// Wraps the iterator for a nsTHashTable so that it may be used as a range
// iterator. Each iterator result acts as a smart pointer to the hash element,
// and has a Remove() method which will remove the element from the hash.
//
// It also accepts an optional Matcher instance against which to filter the
// elements which should be iterated over.
//
// Example:
//
// for (auto& elem : HashElemIter<HashType>(hash)) {
// if (elem->IsDead()) {
// elem.Remove();
// }
// }
template <typename T>
class HashElemIter
{
using Iterator = typename T::Iterator;
using ElemType = typename T::UserDataType;
T& hash_;
Matcher<ElemType>* matcher_;
Maybe<Iterator> iter_;
public:
explicit HashElemIter(T& hash, Matcher<ElemType>* matcher = nullptr)
: hash_(hash), matcher_(matcher)
{
iter_.emplace(Move(hash.Iter()));
}
class Elem
{
friend class HashElemIter<T>;
HashElemIter<T>& iter_;
bool done_;
Elem(HashElemIter& iter, bool done)
: iter_(iter), done_(done)
{
skipNonMatching();
}
Iterator& iter() { return iter_.iter_.ref(); }
void skipNonMatching()
{
if (iter_.matcher_) {
while (!done_ && !iter_.matcher_->Matches(get())) {
iter().Next();
done_ = iter().Done();
}
}
}
public:
Elem& operator*() { return *this; }
ElemType get()
{
if (done_) {
return nullptr;
}
return iter().Data();
}
ElemType operator->() { return get(); }
operator ElemType() { return get(); }
void Remove() { iter().Remove(); }
Elem& operator++()
{
MOZ_ASSERT(!done_);
iter().Next();
done_ = iter().Done();
skipNonMatching();
return *this;
}
bool operator!=(Elem& other)
{
return done_ != other.done_ || this->get() != other.get();
}
};
Elem begin() { return Elem(*this, iter_->Done()); }
Elem end() { return Elem(*this, true); }
};
template <typename T>
HashElemIter<T> IterHash(T& hash, Matcher<typename T::UserDataType>* matcher = nullptr)
{
return HashElemIter<T>(hash, matcher);
}
template <typename T, typename F>
bool
Find(T&& iter, F&& match)
{
for (auto& elem : iter) {
if (match(elem)) {
return true;
}
}
return false;
}
Bug 1359653: Part 5 - Pre-load scripts needed during startup in a background thread. r=shu,erahm One of the things that I've noticed in profiling startup overhead is that, even with the startup cache, we spend about 130ms just loading and decoding scripts from the startup cache on my machine. I think we should be able to do better than that by doing some of that work in the background for scripts that we know we'll need during startup. With this change, we seem to consistently save about 3-5% on non-e10s startup overhead on talos. But there's a lot of room for tuning, and I think we get some considerable improvement with a few ongoing tweeks. Some notes about the approach: - Setting up the off-thread compile is fairly expensive, since we need to create a global object, and a lot of its built-in prototype objects for each compile. So in order for there to be a performance improvement for OMT compiles, the script has to be pretty large. Right now, the tipping point seems to be about 20K. There's currently no easy way to improve the per-compile setup overhead, but we should be able to combine the off-thread compiles for multiple smaller scripts into a single operation without any additional per-script overhead. - The time we spend setting up scripts for OMT compile is almost entirely CPU-bound. That means that we have a chunk of about 20-50ms where we can safely schedule thread-safe IO work during early startup, so if we schedule some of our current synchronous IO operations on background threads during the script cache setup, we basically get them for free, and can probably increase the number of scripts we compile in the background. - I went with an uncompressed mmap of the raw XDR data for a storage format. That currently occupies about 5MB of disk space. Gzipped, it's ~1.2MB, so compressing it might save some startup disk IO, but keeping it uncompressed simplifies a lot of the OMT and even main thread decoding process, but, more importantly: - We currently don't use the startup cache in content processes, for a variety of reasons. However, with this approach, I think we can safely store the cached script data from a content process before we load any untrusted code into it, and then share mmapped startup cache data between all content processes. That should speed up content process startup *a lot*, and very likely save memory, too. And: - If we're especially concerned about saving per-process memory, and we keep the cache data mapped for the lifetime of the JS runtime, I think that with some effort we can probably share the static string data from scripts between content processes, without any copying. Right now, it looks like for the main process, there's about 1.5MB of string-ish data in the XDR dumps. It's probably less for content processes, but if we could save .5MB per process this way, it might make it easier to increase the number of content processes we allow. MozReview-Commit-ID: CVJahyNktKB --HG-- extra : source : 1c7df945505930d2d86a076ee20807104324c8cc extra : histedit_source : 75e193839edf727874f01b2a9f6852f6c1f087fb%2C3ce966d7dcf2bd0454a7d673d0467097456bd782
2017-05-06 19:24:22 +00:00
}; // namespace loader
}; // namespace mozilla
#endif // ScriptPreloader_inl_h