summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/linux
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/page/linux
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/page/linux')
-rw-r--r--Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp163
-rw-r--r--Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp171
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)