2012-02-12 03:21:32 +00:00
|
|
|
/*
|
2019-09-18 00:36:19 +00:00
|
|
|
* Copyright (C) 2012-2019 Apple Inc. All rights reserved.
|
2012-02-12 03:21:32 +00:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
2018-10-15 14:24:49 +00:00
|
|
|
#include <wtf/DataLog.h>
|
|
|
|
|
2012-02-12 03:21:32 +00:00
|
|
|
#include <stdarg.h>
|
2014-04-29 20:28:37 +00:00
|
|
|
#include <string.h>
|
2012-11-24 03:16:47 +00:00
|
|
|
#include <wtf/FilePrintStream.h>
|
2016-12-14 17:25:19 +00:00
|
|
|
#include <wtf/LockedPrintStream.h>
|
2017-05-18 07:12:13 +00:00
|
|
|
#include <wtf/ProcessID.h>
|
2019-02-18 00:11:24 +00:00
|
|
|
#include <mutex>
|
2012-11-27 01:09:31 +00:00
|
|
|
|
2013-03-11 22:45:06 +00:00
|
|
|
#define DATA_LOG_TO_FILE 0
|
2012-02-12 03:21:32 +00:00
|
|
|
|
2014-04-29 20:28:37 +00:00
|
|
|
// Set to 1 to use the temp directory from confstr instead of hardcoded directory.
|
|
|
|
// The last component of DATA_LOG_FILENAME will still be used.
|
|
|
|
#define DATA_LOG_TO_DARWIN_TEMP_DIR 0
|
2012-11-28 23:39:32 +00:00
|
|
|
|
2014-04-29 20:28:37 +00:00
|
|
|
// Uncomment to force logging to the given file regardless of what the environment variable says.
|
|
|
|
// Note that we will append ".<pid>.txt" where <pid> is the PID.
|
2012-11-28 23:39:32 +00:00
|
|
|
// This path won't work on Windows, make sure to change to something like C:\\Users\\<more path>\\log.txt.
|
2012-11-27 01:09:31 +00:00
|
|
|
#define DATA_LOG_FILENAME "/tmp/WTFLog"
|
2012-02-12 03:21:32 +00:00
|
|
|
|
|
|
|
namespace WTF {
|
|
|
|
|
2019-09-18 00:36:19 +00:00
|
|
|
static constexpr size_t maxPathLength = 1024;
|
2012-02-12 03:21:32 +00:00
|
|
|
|
2017-02-28 18:50:00 +00:00
|
|
|
static PrintStream* s_file;
|
2016-12-14 17:25:19 +00:00
|
|
|
static uint64_t s_fileData[(sizeof(FilePrintStream) + 7) / 8];
|
The mutator should be able to perform increments of GC work
https://bugs.webkit.org/show_bug.cgi?id=167528
Reviewed by Keith Miller and Geoffrey Garen.
Source/JavaScriptCore:
The cool thing about having a concurrent and parallel collector is that it's easy to also make
it incremental, because the load balancer can also hand over work to anyone (including the
mutator) and since the collector is running concurrently anyway, the mutator can usually rely
on the balancer having some spare work.
This change adds a classic work-based incremental mode to the GC. When you allocate K bytes,
you have to do Options::gcIncrementScale() * K "bytes" of draining. This is ammortized so that
it only happens in allocation slow paths.
On computers that have a lot of CPUs, this mode is not profitable and we set gcIncrementScale
to zero. On such computers, Riptide was already performing great because there was no way that
one mutator thread could outpace many GC threads. But on computers with fewer CPUs, there were
problems having to do with making the collector progress quickly enough so that the heap
doesn't grow too much. The stochastic scheduler actually made things worse, because it relies
a lot on the fact that the GC will simply be faster than the mutator anyway. The old scheduler
claimed to address the problem of GC pace, but it used a time-based scheduler, which is not as
precise at keeping pase as the new work-based incremental mode.
In theory, the work-based mode guarantees a bound on how much the heap can grow during a
collection just because each byte allocated means some number of bytes visited. We don't try
to create such a theoretical bound. We're just trying to give the collector an unfair advantage
in any race with the mutator.
Turning on incremental mode, the stochastic scheduler, and passive draining in combination with
each other is a huge splay-latency speed-up on my iPad. It's also a CDjs progression. It does
regress splay-throughput, but I think that's fine (the regression is 11%, the progression is
3x).
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::~Heap):
(JSC::Heap::markToFixpoint):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::endMarking):
(JSC::Heap::finalize):
(JSC::Heap::didAllocate):
(JSC::Heap::visitCount):
(JSC::Heap::bytesVisited):
(JSC::Heap::forEachSlotVisitor):
(JSC::Heap::performIncrement):
(JSC::Heap::threadVisitCount): Deleted.
(JSC::Heap::threadBytesVisited): Deleted.
* heap/Heap.h:
* heap/MarkStack.cpp:
(JSC::MarkStackArray::transferTo):
* heap/MarkStack.h:
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::didStartMarking):
(JSC::SlotVisitor::clearMarkStacks):
(JSC::SlotVisitor::appendToMarkStack):
(JSC::SlotVisitor::noteLiveAuxiliaryCell):
(JSC::SlotVisitor::donateKnownParallel):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::performIncrementOfDraining):
(JSC::SlotVisitor::didReachTermination):
(JSC::SlotVisitor::hasWork):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::correspondingGlobalStack):
* heap/SlotVisitor.h:
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::reportExtraMemoryVisited):
(JSC::SlotVisitor::forEachMarkStack):
* heap/SpaceTimeMutatorScheduler.cpp:
(JSC::SpaceTimeMutatorScheduler::log):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::log):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionHeapCapacity):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
Source/WTF:
We want dataLog to be locked even if you're not logging to a file!
* wtf/DataLog.cpp:
(WTF::initializeLogFileOnce):
Canonical link: https://commits.webkit.org/184687@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211448 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-01-31 22:31:24 +00:00
|
|
|
static uint64_t s_lockedFileData[(sizeof(LockedPrintStream) + 7) / 8];
|
2013-07-25 04:01:20 +00:00
|
|
|
|
2012-02-12 03:21:32 +00:00
|
|
|
static void initializeLogFileOnce()
|
|
|
|
{
|
2017-02-28 18:50:00 +00:00
|
|
|
const char* filename = nullptr;
|
2014-04-29 20:28:37 +00:00
|
|
|
|
2017-02-28 18:50:00 +00:00
|
|
|
if (s_file)
|
|
|
|
return;
|
2014-04-29 20:28:37 +00:00
|
|
|
|
2017-02-28 18:50:00 +00:00
|
|
|
#if DATA_LOG_TO_FILE
|
2014-04-29 20:28:37 +00:00
|
|
|
#if DATA_LOG_TO_DARWIN_TEMP_DIR
|
|
|
|
char filenameBuffer[maxPathLength + 1];
|
|
|
|
#if defined(DATA_LOG_FILENAME)
|
2017-07-12 18:07:14 +00:00
|
|
|
const char* logBasename = strrchr(DATA_LOG_FILENAME, '/');
|
2014-04-29 20:28:37 +00:00
|
|
|
if (!logBasename)
|
|
|
|
logBasename = (char*)DATA_LOG_FILENAME;
|
|
|
|
#else
|
|
|
|
const char* logBasename = "WTFLog";
|
|
|
|
#endif
|
|
|
|
|
2015-11-18 19:47:08 +00:00
|
|
|
bool success = confstr(_CS_DARWIN_USER_TEMP_DIR, filenameBuffer, sizeof(filenameBuffer));
|
|
|
|
if (success) {
|
|
|
|
// FIXME: Assert that the path ends with a slash instead of adding a slash if it does not exist
|
|
|
|
// once <rdar://problem/23579077> is fixed in all iOS Simulator versions that we use.
|
2017-02-28 18:50:00 +00:00
|
|
|
size_t lastComponentLength = strlen(logBasename) + 20; // More than enough for ".<pid>.txt"
|
2015-11-18 19:47:08 +00:00
|
|
|
size_t dirnameLength = strlen(filenameBuffer);
|
|
|
|
bool shouldAddPathSeparator = filenameBuffer[dirnameLength - 1] != '/' && logBasename[0] != '/';
|
|
|
|
if (lastComponentLength + shouldAddPathSeparator <= sizeof(filenameBuffer) - dirnameLength - 1) {
|
|
|
|
if (shouldAddPathSeparator)
|
|
|
|
strncat(filenameBuffer, "/", 1);
|
|
|
|
strncat(filenameBuffer, logBasename, sizeof(filenameBuffer) - strlen(filenameBuffer) - 1);
|
|
|
|
filename = filenameBuffer;
|
|
|
|
}
|
2014-04-29 20:28:37 +00:00
|
|
|
}
|
|
|
|
#elif defined(DATA_LOG_FILENAME)
|
2017-02-28 18:50:00 +00:00
|
|
|
filename = DATA_LOG_FILENAME;
|
2012-02-12 03:21:32 +00:00
|
|
|
#else
|
2019-02-18 00:11:24 +00:00
|
|
|
filename = getenv("WTF_DATA_LOG_FILENAME");
|
2012-02-12 03:21:32 +00:00
|
|
|
#endif
|
2014-04-29 20:28:37 +00:00
|
|
|
char actualFilename[maxPathLength + 1];
|
2012-11-28 23:39:32 +00:00
|
|
|
|
2017-02-28 18:50:00 +00:00
|
|
|
if (filename && !strstr(filename, "%pid")) {
|
|
|
|
snprintf(actualFilename, sizeof(actualFilename), "%s.%%pid.txt", filename);
|
|
|
|
filename = actualFilename;
|
2012-02-12 03:21:32 +00:00
|
|
|
}
|
2012-11-24 03:16:47 +00:00
|
|
|
#endif // DATA_LOG_TO_FILE
|
2017-02-28 18:50:00 +00:00
|
|
|
|
|
|
|
setDataFile(filename);
|
2012-02-12 03:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void initializeLogFile()
|
|
|
|
{
|
2016-12-14 17:25:19 +00:00
|
|
|
static std::once_flag once;
|
|
|
|
std::call_once(
|
|
|
|
once,
|
|
|
|
[] {
|
|
|
|
initializeLogFileOnce();
|
|
|
|
});
|
2012-02-12 03:21:32 +00:00
|
|
|
}
|
|
|
|
|
2017-02-28 18:50:00 +00:00
|
|
|
void setDataFile(const char* path)
|
|
|
|
{
|
|
|
|
FilePrintStream* file = nullptr;
|
|
|
|
char formattedPath[maxPathLength + 1];
|
|
|
|
const char* pathToOpen = path;
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
const char* pidFormat = strstr(path, "%pid");
|
|
|
|
if (pidFormat) {
|
|
|
|
size_t leadingPathLength = pidFormat - path;
|
|
|
|
size_t pathCharactersAvailable = std::min(maxPathLength, leadingPathLength);
|
|
|
|
strncpy(formattedPath, path, pathCharactersAvailable);
|
|
|
|
char* nextDest = formattedPath + pathCharactersAvailable;
|
|
|
|
pathCharactersAvailable = maxPathLength - pathCharactersAvailable;
|
|
|
|
if (pathCharactersAvailable) {
|
2017-05-18 07:12:13 +00:00
|
|
|
int pidTextLength = snprintf(nextDest, pathCharactersAvailable, "%d", getCurrentProcessID());
|
|
|
|
|
2020-04-02 18:44:57 +00:00
|
|
|
if (pidTextLength >= 0 && static_cast<size_t>(pidTextLength) < pathCharactersAvailable) {
|
2017-02-28 18:50:00 +00:00
|
|
|
pathCharactersAvailable -= static_cast<size_t>(pidTextLength);
|
|
|
|
nextDest += pidTextLength;
|
|
|
|
strncpy(nextDest, pidFormat + 4, pathCharactersAvailable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
formattedPath[maxPathLength] = '\0';
|
|
|
|
pathToOpen = formattedPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
file = FilePrintStream::open(pathToOpen, "w").release();
|
|
|
|
if (file)
|
|
|
|
WTFLogAlways("*** DataLog output to \"%s\" ***\n", pathToOpen);
|
|
|
|
else
|
|
|
|
WTFLogAlways("Warning: Could not open DataLog file %s for writing.\n", pathToOpen);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
// Use placement new; this makes it easier to use dataLog() to debug
|
|
|
|
// fastMalloc.
|
|
|
|
file = new (s_fileData) FilePrintStream(stderr, FilePrintStream::Borrow);
|
|
|
|
}
|
|
|
|
|
2020-05-08 17:31:54 +00:00
|
|
|
setvbuf(file->file(), nullptr, _IONBF, 0); // Prefer unbuffered output, so that we get a full log upon crash or deadlock.
|
2017-02-28 18:50:00 +00:00
|
|
|
|
|
|
|
if (s_file)
|
|
|
|
s_file->flush();
|
|
|
|
|
|
|
|
s_file = new (s_lockedFileData) LockedPrintStream(std::unique_ptr<FilePrintStream>(file));
|
|
|
|
}
|
|
|
|
|
2020-02-19 05:37:45 +00:00
|
|
|
void setDataFile(std::unique_ptr<PrintStream>&& file)
|
|
|
|
{
|
|
|
|
s_file = file.release();
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:25:19 +00:00
|
|
|
PrintStream& dataFile()
|
2012-02-12 03:21:32 +00:00
|
|
|
{
|
|
|
|
initializeLogFile();
|
2016-12-14 17:25:19 +00:00
|
|
|
return *s_file;
|
2012-02-12 03:21:32 +00:00
|
|
|
}
|
|
|
|
|
2012-11-22 04:23:36 +00:00
|
|
|
void dataLogFV(const char* format, va_list argList)
|
2012-02-12 03:21:32 +00:00
|
|
|
{
|
2012-11-24 03:16:47 +00:00
|
|
|
dataFile().vprintf(format, argList);
|
2012-02-12 03:21:32 +00:00
|
|
|
}
|
|
|
|
|
2012-11-22 04:23:36 +00:00
|
|
|
void dataLogF(const char* format, ...)
|
2012-02-12 03:21:32 +00:00
|
|
|
{
|
|
|
|
va_list argList;
|
|
|
|
va_start(argList, format);
|
2012-11-22 04:23:36 +00:00
|
|
|
dataLogFV(format, argList);
|
2012-02-12 03:21:32 +00:00
|
|
|
va_end(argList);
|
|
|
|
}
|
|
|
|
|
2012-11-22 04:23:36 +00:00
|
|
|
void dataLogFString(const char* str)
|
2012-06-06 23:11:09 +00:00
|
|
|
{
|
2012-11-24 03:16:47 +00:00
|
|
|
dataFile().printf("%s", str);
|
2012-06-06 23:11:09 +00:00
|
|
|
}
|
|
|
|
|
2012-02-12 03:21:32 +00:00
|
|
|
} // namespace WTF
|
|
|
|
|