diff options
Diffstat (limited to 'Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp')
-rw-r--r-- | Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp | 171 |
1 files changed, 171 insertions, 0 deletions
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) |