Bug 1361900: Part 9 - Sort scripts by initial load time before saving. r=erahm

MozReview-Commit-ID: 54UN2DVK4xM

--HG--
extra : rebase_source : f7cb39eb05bb86a03a17b97cbe2cb9d8dd1008fe
This commit is contained in:
Kris Maglione 2017-05-01 14:12:01 -07:00
Родитель ac38356cdd
Коммит 220b0239c3
3 изменённых файлов: 59 добавлений и 20 удалений

Просмотреть файл

@ -47,6 +47,7 @@ ScriptCacheChild::Finalize(LinkedList<ScriptPreloader::CachedScript>& scripts)
data->url() = script->mURL;
data->cachePath() = script->mCachePath;
data->loadTime() = script->mLoadTime;
if (script->HasBuffer()) {
auto& xdrData = script->Buffer();
@ -83,7 +84,7 @@ ScriptCacheParent::Recv__delete__(nsTArray<ScriptData>&& scripts)
auto& cache = ScriptPreloader::GetChildSingleton();
for (auto& script : scripts) {
cache.NoteScript(script.url(), script.cachePath(), processType,
Move(script.xdrData()));
Move(script.xdrData()), script.loadTime());
}
return IPC_OK();

Просмотреть файл

@ -498,7 +498,7 @@ ScriptPreloader::InitCacheInternal()
for (auto script : mRestoredScripts) {
// Only async decode scripts which have been used in this process type.
if (script->mProcessTypes.contains(CurrentProcessType()) &&
script->mSize > MIN_OFFTHREAD_SIZE &&
script->AsyncDecodable() &&
JS::CanCompileOffThread(cx, options, script->mSize)) {
DecodeScriptOffThread(cx, script);
} else {
@ -555,8 +555,6 @@ ScriptPreloader::PrepareCacheWrite()
AutoSafeJSAPI jsapi;
LinkedList<CachedScript> asyncScripts;
for (CachedScript* next = mSavedScripts.getFirst(); next; ) {
CachedScript* script = next;
next = script->getNext();
@ -579,20 +577,9 @@ ScriptPreloader::PrepareCacheWrite()
delete script;
} else {
script->mSize = script->Range().length();
if (script->mSize > MIN_OFFTHREAD_SIZE) {
script->remove();
asyncScripts.insertBack(script);
}
}
}
// Store async-decoded scripts contiguously, since they're loaded
// immediately at startup.
while (CachedScript* s = asyncScripts.popLast()) {
mSavedScripts.insertFront(s);
}
mDataPrepared = true;
}
@ -641,9 +628,19 @@ ScriptPreloader::WriteCache()
AutoFDClose fd;
NS_TRY(cacheFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, 0644, &fd.rwget()));
nsTArray<CachedScript*> scripts;
for (auto script : mSavedScripts) {
scripts.AppendElement(script);
}
// Sort scripts by load time, with async loaded scripts before sync scripts.
// Since async scripts are always loaded immediately at startup, it helps to
// have them stored contiguously.
scripts.Sort(CachedScript::Comparator());
OutputBuffer buf;
size_t offset = 0;
for (auto script : mSavedScripts) {
for (auto script : scripts) {
script->mOffset = offset;
script->Code(buf);
@ -656,8 +653,7 @@ ScriptPreloader::WriteCache()
MOZ_TRY(Write(fd, MAGIC, sizeof(MAGIC)));
MOZ_TRY(Write(fd, headerSize, sizeof(headerSize)));
MOZ_TRY(Write(fd, buf.Get(), buf.cursor()));
for (auto script : mSavedScripts) {
for (auto script : scripts) {
MOZ_TRY(Write(fd, script->Range().begin().get(), script->mSize));
if (script->mScript) {
@ -739,12 +735,14 @@ ScriptPreloader::NoteScript(const nsCString& url, const nsCString& cachePath,
return;
}
script->UpdateLoadTime(TimeStamp::Now());
script->mProcessTypes += CurrentProcessType();
}
void
ScriptPreloader::NoteScript(const nsCString& url, const nsCString& cachePath,
ProcessType processType, nsTArray<uint8_t>&& xdrData)
ProcessType processType, nsTArray<uint8_t>&& xdrData,
TimeStamp loadTime)
{
CachedScript* script = mScripts.Get(cachePath);
bool restored = script && FindScript(mRestoredScripts, cachePath);
@ -772,6 +770,7 @@ ScriptPreloader::NoteScript(const nsCString& url, const nsCString& cachePath,
}
}
script->UpdateLoadTime(loadTime);
script->mProcessTypes += processType;
}

Просмотреть файл

@ -76,7 +76,8 @@ public:
void NoteScript(const nsCString& url, const nsCString& cachePath, JS::HandleScript script);
void NoteScript(const nsCString& url, const nsCString& cachePath,
ProcessType processType, nsTArray<uint8_t>&& xdrData);
ProcessType processType, nsTArray<uint8_t>&& xdrData,
TimeStamp loadTime);
// Initializes the script cache from the startup script cache file.
Result<Ok, nsresult> InitCache(const nsAString& = NS_LITERAL_STRING("scriptCache"));
@ -148,6 +149,33 @@ private:
mCache->mScripts.Remove(mCachePath);
}
// For use with nsTArray::Sort.
//
// Orders scripts by:
//
// 1) Async-decoded scripts before sync-decoded scripts, since the
// former are needed immediately at startup, and should be stored
// contiguously.
// 2) Script load time, so that scripts which are needed earlier are
// stored earlier, and scripts needed at approximately the same
// time are stored approximately contiguously.
struct Comparator
{
bool Equals(const CachedScript* a, const CachedScript* b) const
{
return (a->AsyncDecodable() == b->AsyncDecodable() &&
a->mLoadTime == b->mLoadTime);
}
bool LessThan(const CachedScript* a, const CachedScript* b) const
{
if (a->AsyncDecodable() != b->AsyncDecodable()) {
return a->AsyncDecodable();
}
return a->mLoadTime < b->mLoadTime;
}
};
void Cancel();
void FreeData()
@ -160,6 +188,15 @@ private:
}
}
void UpdateLoadTime(const TimeStamp& loadTime)
{
if (!mLoadTime || loadTime < mLoadTime) {
mLoadTime = loadTime;
}
}
bool AsyncDecodable() const { return mSize > MIN_OFFTHREAD_SIZE; }
// Encodes this script into XDR data, and stores the result in mXDRData.
// Returns true on success, false on failure.
bool XDREncode(JSContext* cx);
@ -237,6 +274,8 @@ private:
// The size of this script's encoded XDR data.
uint32_t mSize = 0;
TimeStamp mLoadTime{};
JS::Heap<JSScript*> mScript;
// True if this script is ready to be executed. This means that either the