1/*
2 * Copyright (C) 2017 Igalia S.L.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ResourceUsageOverlay.h"
28
29#if ENABLE(RESOURCE_USAGE) && OS(LINUX)
30
31#include "Chrome.h"
32#include "ChromeClient.h"
33#include "CommonVM.h"
34#include "GraphicsContext.h"
35#include "Page.h"
36#include "RenderTheme.h"
37#include "ResourceUsageThread.h"
38#include <JavaScriptCore/VM.h>
39#include <wtf/text/StringConcatenateNumbers.h>
40
41namespace WebCore {
42
43static ResourceUsageData gData;
44
45static String cpuUsageString(float cpuUsage)
46{
47 if (cpuUsage < 0)
48 return "<unknown>"_s;
49 return makeString(FormattedNumber::fixedWidth(cpuUsage, 1), '%');
50}
51
52static String formatByteNumber(size_t number)
53{
54 if (number >= 1024 * 1048576)
55 return makeString(FormattedNumber::fixedWidth(number / (1024. * 1048576), 3), " GB");
56 if (number >= 1048576)
57 return makeString(FormattedNumber::fixedWidth(number / 1048576., 2), " MB");
58 if (number >= 1024)
59 return makeString(FormattedNumber::fixedWidth(number / 1024, 1), " kB");
60 return String::number(number);
61}
62
63static String gcTimerString(MonotonicTime timerFireDate, MonotonicTime now)
64{
65 if (std::isnan(timerFireDate))
66 return "[not scheduled]"_s;
67 return String::numberToStringFixedPrecision((timerFireDate - now).seconds());
68}
69
70static const float gFontSize = 14;
71
72class ResourceUsageOverlayPainter final : public GraphicsLayerClient {
73public:
74 ResourceUsageOverlayPainter(ResourceUsageOverlay& overlay)
75 : m_overlay(overlay)
76 {
77 FontCascadeDescription fontDescription;
78 RenderTheme::singleton().systemFont(CSSValueMessageBox, fontDescription);
79 fontDescription.setComputedSize(gFontSize);
80 m_textFont = FontCascade(WTFMove(fontDescription), 0, 0);
81 m_textFont.update(nullptr);
82 }
83
84 ~ResourceUsageOverlayPainter() = default;
85
86private:
87 void paintContents(const GraphicsLayer*, GraphicsContext& context, OptionSet<GraphicsLayerPaintingPhase>, const FloatRect& clip, GraphicsLayerPaintBehavior) override
88 {
89 GraphicsContextStateSaver stateSaver(context);
90 context.fillRect(clip, Color(0.0f, 0.0f, 0.0f, 0.8f));
91 context.setFillColor(Color(0.9f, 0.9f, 0.9f, 1.f));
92
93 FloatPoint position = { 10, 20 };
94 String string = "CPU: " + cpuUsageString(gData.cpu);
95 context.drawText(m_textFont, TextRun(string), position);
96 position.move(0, gFontSize + 2);
97
98 string = "Memory: " + formatByteNumber(gData.totalDirtySize);
99 context.drawText(m_textFont, TextRun(string), position);
100 position.move(0, gFontSize + 2);
101
102 string = "External: " + formatByteNumber(gData.totalExternalSize);
103 context.drawText(m_textFont, TextRun(string), position);
104 position.move(0, gFontSize + 2);
105
106 string = "GC Heap: " + formatByteNumber(gData.categories[MemoryCategory::GCHeap].dirtySize);
107 context.drawText(m_textFont, TextRun(string), position);
108 position.move(0, gFontSize + 2);
109
110 string = "GC owned: " + formatByteNumber(gData.categories[MemoryCategory::GCOwned].dirtySize);
111 context.drawText(m_textFont, TextRun(string), position);
112 position.move(0, gFontSize + 2);
113
114 MonotonicTime now = MonotonicTime::now();
115 string = "Eden GC: " + gcTimerString(gData.timeOfNextEdenCollection, now);
116 context.drawText(m_textFont, TextRun(string), position);
117 position.move(0, gFontSize + 2);
118
119 string = "Full GC: " + gcTimerString(gData.timeOfNextFullCollection, now);
120 context.drawText(m_textFont, TextRun(string), position);
121 position.move(0, gFontSize + 2);
122 }
123
124 void notifyFlushRequired(const GraphicsLayer*) override
125 {
126 m_overlay.overlay().page()->chrome().client().scheduleCompositingLayerFlush();
127 }
128
129 ResourceUsageOverlay& m_overlay;
130 FontCascade m_textFont;
131};
132
133void ResourceUsageOverlay::platformInitialize()
134{
135 m_overlayPainter = std::make_unique<ResourceUsageOverlayPainter>(*this);
136 m_paintLayer = GraphicsLayer::create(overlay().page()->chrome().client().graphicsLayerFactory(), *m_overlayPainter);
137 m_paintLayer->setAnchorPoint(FloatPoint3D());
138 m_paintLayer->setSize({ normalWidth, normalHeight });
139 m_paintLayer->setBackgroundColor(Color(0.0f, 0.0f, 0.0f, 0.8f));
140 m_paintLayer->setDrawsContent(true);
141 overlay().layer().addChild(*m_paintLayer);
142
143 ResourceUsageThread::addObserver(this, All, [this] (const ResourceUsageData& data) {
144 gData = data;
145 m_paintLayer->setNeedsDisplay();
146 });
147}
148
149void ResourceUsageOverlay::platformDestroy()
150{
151 ResourceUsageThread::removeObserver(this);
152 if (!m_paintLayer)
153 return;
154
155 m_paintLayer->removeFromParent();
156 m_paintLayer = nullptr;
157 m_overlayPainter = nullptr;
158}
159
160} // namespace WebCore
161
162#endif // ENABLE(RESOURCE_USAGE) && OS(LINUX)
163