diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/page/linux | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/page/linux')
-rw-r--r-- | Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp | 163 | ||||
-rw-r--r-- | Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp | 171 |
2 files changed, 334 insertions, 0 deletions
diff --git a/Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp b/Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp new file mode 100644 index 000000000..cff63e00e --- /dev/null +++ b/Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2017 Igalia S.L. + * + * 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. AND ITS CONTRIBUTORS ``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 ITS 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" +#include "ResourceUsageOverlay.h" + +#if ENABLE(RESOURCE_USAGE) && OS(LINUX) + +#include "Chrome.h" +#include "ChromeClient.h" +#include "CommonVM.h" +#include "GraphicsContext.h" +#include "Page.h" +#include "RenderTheme.h" +#include "ResourceUsageThread.h" +#include <runtime/VM.h> + +namespace WebCore { + +static ResourceUsageData gData; + +static String cpuUsageString(float cpuUsage) +{ + if (cpuUsage < 0) + return ASCIILiteral("<unknown>"); + return String::format("%.1f%%", cpuUsage); +} + +static String formatByteNumber(size_t number) +{ + if (number >= 1024 * 1048576) + return String::format("%.3f GB", static_cast<double>(number) / (1024 * 1048576)); + if (number >= 1048576) + return String::format("%.2f MB", static_cast<double>(number) / 1048576); + if (number >= 1024) + return String::format("%.1f kB", static_cast<double>(number) / 1024); + return String::format("%lu", number); +} + +static String gcTimerString(double timerFireDate, double now) +{ + if (!timerFireDate) + return ASCIILiteral("[not scheduled]"); + return String::format("%g", timerFireDate - now); +} + +static const float gFontSize = 14; + +class ResourceUsageOverlayPainter final : public GraphicsLayerClient { +public: + ResourceUsageOverlayPainter(ResourceUsageOverlay& overlay) + : m_overlay(overlay) + { + FontCascadeDescription fontDescription; + RenderTheme::defaultTheme()->systemFont(CSSValueMessageBox, fontDescription); + fontDescription.setComputedSize(gFontSize); + m_textFont = FontCascade(fontDescription, 0, 0); + m_textFont.update(nullptr); + } + + ~ResourceUsageOverlayPainter() + { + } + +private: + void paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& clip) override + { + GraphicsContextStateSaver stateSaver(context); + context.fillRect(clip, Color(0.0f, 0.0f, 0.0f, 0.8f)); + context.setFillColor(Color(0.9f, 0.9f, 0.9f, 1.f)); + + FloatPoint position = { 10, 20 }; + String string = "CPU: " + cpuUsageString(gData.cpu); + context.drawText(m_textFont, TextRun(string), position); + position.move(0, gFontSize + 2); + + string = "Memory: " + formatByteNumber(gData.totalDirtySize); + context.drawText(m_textFont, TextRun(string), position); + position.move(0, gFontSize + 2); + + string = "External: " + formatByteNumber(gData.totalExternalSize); + context.drawText(m_textFont, TextRun(string), position); + position.move(0, gFontSize + 2); + + string = "GC Heap: " + formatByteNumber(gData.categories[MemoryCategory::GCHeap].dirtySize); + context.drawText(m_textFont, TextRun(string), position); + position.move(0, gFontSize + 2); + + string = "GC owned: " + formatByteNumber(gData.categories[MemoryCategory::GCOwned].dirtySize); + context.drawText(m_textFont, TextRun(string), position); + position.move(0, gFontSize + 2); + + double now = WTF::currentTime(); + string = "Eden GC: " + gcTimerString(gData.timeOfNextEdenCollection, now); + context.drawText(m_textFont, TextRun(string), position); + position.move(0, gFontSize + 2); + + string = "Full GC: " + gcTimerString(gData.timeOfNextFullCollection, now); + context.drawText(m_textFont, TextRun(string), position); + position.move(0, gFontSize + 2); + } + + void notifyFlushRequired(const GraphicsLayer*) override + { + m_overlay.overlay().page()->chrome().client().scheduleCompositingLayerFlush(); + } + + ResourceUsageOverlay& m_overlay; + FontCascade m_textFont; +}; + +void ResourceUsageOverlay::platformInitialize() +{ + m_overlayPainter = std::make_unique<ResourceUsageOverlayPainter>(*this); + m_paintLayer = GraphicsLayer::create(overlay().page()->chrome().client().graphicsLayerFactory(), *m_overlayPainter); + m_paintLayer->setAnchorPoint(FloatPoint3D()); + m_paintLayer->setSize({ normalWidth, normalHeight }); + m_paintLayer->setBackgroundColor(Color(0.0f, 0.0f, 0.0f, 0.8f)); + m_paintLayer->setDrawsContent(true); + overlay().layer().addChild(m_paintLayer.get()); + + ResourceUsageThread::addObserver(this, [this] (const ResourceUsageData& data) { + gData = data; + m_paintLayer->setNeedsDisplay(); + }); +} + +void ResourceUsageOverlay::platformDestroy() +{ + ResourceUsageThread::removeObserver(this); + if (!m_paintLayer) + return; + + m_paintLayer->removeFromParent(); + m_paintLayer = nullptr; + m_overlayPainter = nullptr; +} + +} // namespace WebCore + +#endif // ENABLE(RESOURCE_USAGE) && OS(LINUX) diff --git a/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp b/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp new file mode 100644 index 000000000..1d19497fb --- /dev/null +++ b/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2017 Igalia S.L. + * + * 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. AND ITS CONTRIBUTORS ``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 ITS 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" +#include "ResourceUsageThread.h" + +#if ENABLE(RESOURCE_USAGE) && OS(LINUX) + +#include "CurrentProcessMemoryStatus.h" +#include <errno.h> +#include <fcntl.h> +#include <heap/GCActivityCallback.h> +#include <runtime/VM.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +namespace WebCore { + +static float cpuPeriod() +{ + FILE* file = fopen("/proc/stat", "r"); + if (!file) + return 0; + + static const unsigned statMaxLineLength = 512; + char buffer[statMaxLineLength + 1]; + char* line = fgets(buffer, statMaxLineLength, file); + if (!line) { + fclose(file); + return 0; + } + + unsigned long long userTime, niceTime, systemTime, idleTime; + unsigned long long ioWait, irq, softIrq, steal, guest, guestnice; + ioWait = irq = softIrq = steal = guest = guestnice = 0; + sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", + &userTime, &niceTime, &systemTime, &idleTime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice); + + // Keep parsing if we still don't know cpuCount. + static unsigned cpuCount = 0; + if (!cpuCount) { + while ((line = fgets(buffer, statMaxLineLength, file))) { + if (strlen(line) > 4 && line[0] == 'c' && line[1] == 'p' && line[2] == 'u') + cpuCount++; + else + break; + } + } + fclose(file); + + if (!cpuCount) + return 0; + + static unsigned long long previousTotalTime = 0; + unsigned long long totalTime = userTime + niceTime + systemTime + irq + softIrq + idleTime + ioWait + steal; + unsigned long long period = totalTime > previousTotalTime ? totalTime - previousTotalTime : 0; + previousTotalTime = totalTime; + return static_cast<float>(period) / cpuCount; +} + +static float cpuUsage() +{ + float period = cpuPeriod(); + if (!period) + return -1; + + int fd = open("/proc/self/stat", O_RDONLY); + if (fd < 0) + return -1; + + static const ssize_t maxBufferLength = BUFSIZ - 1; + char buffer[BUFSIZ]; + buffer[0] = '\0'; + + ssize_t totalBytesRead = 0; + while (totalBytesRead < maxBufferLength) { + ssize_t bytesRead = read(fd, buffer + totalBytesRead, maxBufferLength - totalBytesRead); + if (bytesRead < 0) { + if (errno != EINTR) { + close(fd); + return -1; + } + continue; + } + + if (!bytesRead) + break; + + totalBytesRead += bytesRead; + } + close(fd); + buffer[totalBytesRead] = '\0'; + + // Skip pid and process name. + char* position = strrchr(buffer, ')'); + if (!position) + return -1; + + // Move after state. + position += 4; + + // Skip ppid, pgrp, sid, tty_nr, tty_pgrp, flags, min_flt, cmin_flt, maj_flt, cmaj_flt. + unsigned tokensToSkip = 10; + while (tokensToSkip--) { + while (!isASCIISpace(position[0])) + position++; + position++; + } + + static unsigned long long previousUtime = 0; + static unsigned long long previousStime = 0; + unsigned long long utime = strtoull(position, &position, 10); + unsigned long long stime = strtoull(position, &position, 10); + float usage = (utime + stime - (previousUtime + previousStime)) / period * 100.0; + previousUtime = utime; + previousStime = stime; + + return clampTo<float>(usage, 0, 100); +} + +void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& data) +{ + data.cpu = cpuUsage(); + + ProcessMemoryStatus memoryStatus; + currentProcessMemoryStatus(memoryStatus); + data.totalDirtySize = memoryStatus.resident - memoryStatus.shared; + + size_t currentGCHeapCapacity = vm->heap.blockBytesAllocated(); + size_t currentGCOwnedExtra = vm->heap.extraMemorySize(); + size_t currentGCOwnedExternal = vm->heap.externalMemorySize(); + RELEASE_ASSERT(currentGCOwnedExternal <= currentGCOwnedExtra); + + data.categories[MemoryCategory::GCHeap].dirtySize = currentGCHeapCapacity; + data.categories[MemoryCategory::GCOwned].dirtySize = currentGCOwnedExtra - currentGCOwnedExternal; + data.categories[MemoryCategory::GCOwned].externalSize = currentGCOwnedExternal; + + data.totalExternalSize = currentGCOwnedExternal; + + data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime(); + data.timeOfNextFullCollection = vm->heap.fullActivityCallback()->nextFireTime(); +} + +} // namespace WebCore + +#endif // ENABLE(RESOURCE_USAGE) && OS(LINUX) |