Display resident memory statistics on the performance overlay. (flutter/engine#3314)

This commit is contained in:
Chinmay Garde
2017-01-03 12:27:30 -08:00
committed by GitHub
parent b194ed3b5e
commit 63fbe60fa6
21 changed files with 303 additions and 38 deletions

View File

@@ -36,6 +36,7 @@ source_set("flow") {
"layers/shader_mask_layer.h",
"layers/transform_layer.cc",
"layers/transform_layer.h",
"process_info.h",
"raster_cache.cc",
"raster_cache.h",
"scene_update_context.cc",

View File

@@ -8,7 +8,8 @@
namespace flow {
CompositorContext::CompositorContext() = default;
CompositorContext::CompositorContext(std::unique_ptr<ProcessInfo> info)
: process_info_(std::move(info)) {}
CompositorContext::~CompositorContext() = default;
@@ -17,6 +18,10 @@ void CompositorContext::BeginFrame(ScopedFrame& frame,
if (enable_instrumentation) {
frame_count_.Increment();
frame_time_.Start();
if (process_info_ && process_info_->SampleNow()) {
memory_usage_.Add(process_info_->GetResidentMemorySize());
}
}
}

View File

@@ -9,6 +9,7 @@
#include <string>
#include "flutter/flow/instrumentation.h"
#include "flutter/flow/process_info.h"
#include "flutter/flow/raster_cache.h"
#include "lib/ftl/macros.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -46,7 +47,7 @@ class CompositorContext {
FTL_DISALLOW_COPY_AND_ASSIGN(ScopedFrame);
};
CompositorContext();
CompositorContext(std::unique_ptr<ProcessInfo> info);
~CompositorContext();
@@ -62,13 +63,17 @@ class CompositorContext {
const Stopwatch& frame_time() const { return frame_time_; }
Stopwatch& engine_time() { return engine_time_; };
Stopwatch& engine_time() { return engine_time_; }
const CounterValues& memory_usage() const { return memory_usage_; }
private:
RasterCache raster_cache_;
std::unique_ptr<ProcessInfo> process_info_;
Counter frame_count_;
Stopwatch frame_time_;
Stopwatch engine_time_;
CounterValues memory_usage_;
void BeginFrame(ScopedFrame& frame, bool enable_instrumentation);

View File

@@ -5,6 +5,7 @@
#include "flutter/flow/instrumentation.h"
#include <algorithm>
#include <limits>
#include "third_party/skia/include/core/SkPath.h"
@@ -18,6 +19,8 @@ Stopwatch::Stopwatch() : start_(ftl::TimePoint::Now()), current_sample_(0) {
laps_.resize(kMaxSamples, delta);
}
Stopwatch::~Stopwatch() = default;
void Stopwatch::Start() {
start_ = ftl::TimePoint::Now();
current_sample_ = (current_sample_ + 1) % kMaxSamples;
@@ -153,6 +156,93 @@ void Stopwatch::Visualize(SkCanvas& canvas, const SkRect& rect) const {
bottom, paint);
}
Stopwatch::~Stopwatch() = default;
CounterValues::CounterValues() : current_sample_(kMaxSamples - 1) {
values_.resize(kMaxSamples, 0);
}
CounterValues::~CounterValues() = default;
void CounterValues::Add(int64_t value) {
current_sample_ = (current_sample_ + 1) % kMaxSamples;
values_[current_sample_] = value;
}
void CounterValues::Visualize(SkCanvas& canvas, const SkRect& rect) const {
size_t max_bytes = GetMaxValue();
if (max_bytes == 0) {
// The backend for this counter probably did not fill in any values.
return;
}
size_t min_bytes = GetMinValue();
SkPaint paint;
// Paint the background.
paint.setColor(0x99FFFFFF);
canvas.drawRect(rect, paint);
// Establish the graph position.
const SkScalar x = rect.x();
const SkScalar y = rect.y();
const SkScalar width = rect.width();
const SkScalar height = rect.height();
const SkScalar bottom = y + height;
const SkScalar right = x + width;
// Prepare a path for the data.
SkPath path;
path.moveTo(x, bottom);
for (size_t i = 0; i < kMaxSamples; ++i) {
int64_t current_bytes = values_[i];
double ratio =
(double)(current_bytes - min_bytes) / (max_bytes - min_bytes);
path.lineTo(x + (((double)(i) / (double)kMaxSamples) * width),
y + ((1.0 - ratio) * height));
}
path.rLineTo(100, 0);
path.lineTo(right, bottom);
path.close();
// Draw the graph.
paint.setColor(0xAA0000FF);
canvas.drawPath(path, paint);
// Paint the vertical marker for the current frame.
const double sample_unit_width = (1.0 / kMaxSamples);
const double sample_margin_unit_width = sample_unit_width / 6.0;
const double sample_margin_width = width * sample_margin_unit_width;
paint.setStyle(SkPaint::Style::kFill_Style);
paint.setColor(SK_ColorGRAY);
double sample_x =
x + width * (static_cast<double>(current_sample_) / kMaxSamples) -
sample_margin_width;
canvas.drawRectCoords(sample_x, y, sample_x + width * sample_unit_width +
sample_margin_width * 2,
bottom, paint);
}
int64_t CounterValues::GetCurrentValue() const {
return values_[current_sample_];
}
int64_t CounterValues::GetMaxValue() const {
auto max = std::numeric_limits<int64_t>::min();
for (size_t i = 0; i < kMaxSamples; ++i) {
max = std::max<int64_t>(max, values_[i]);
}
return max;
}
int64_t CounterValues::GetMinValue() const {
auto min = std::numeric_limits<int64_t>::max();
for (size_t i = 0; i < kMaxSamples; ++i) {
min = std::min<int64_t>(min, values_[i]);
}
return min;
}
} // namespace flow

View File

@@ -18,29 +18,22 @@ static const double kOneFrameMS = 1e3 / 60.0;
class Stopwatch {
public:
class ScopedLap {
public:
explicit ScopedLap(Stopwatch& stopwatch) : stopwatch_(stopwatch) {
stopwatch_.Start();
}
Stopwatch();
~ScopedLap() { stopwatch_.Stop(); }
private:
Stopwatch& stopwatch_;
FTL_DISALLOW_COPY_AND_ASSIGN(ScopedLap);
};
explicit Stopwatch();
~Stopwatch();
const ftl::TimeDelta& LastLap() const;
ftl::TimeDelta CurrentLap() const { return ftl::TimePoint::Now() - start_; }
ftl::TimeDelta MaxDelta() const;
void Visualize(SkCanvas& canvas, const SkRect& rect) const;
void Start();
void Stop();
void SetLapTime(const ftl::TimeDelta& delta);
private:
@@ -53,10 +46,12 @@ class Stopwatch {
class Counter {
public:
explicit Counter() : count_(0) {}
Counter() : count_(0) {}
size_t count() const { return count_; }
void Reset(size_t count = 0) { count_ = count; }
void Increment(size_t count = 1) { count_ += count; }
private:
@@ -65,6 +60,29 @@ class Counter {
FTL_DISALLOW_COPY_AND_ASSIGN(Counter);
};
class CounterValues {
public:
CounterValues();
~CounterValues();
void Add(int64_t value);
void Visualize(SkCanvas& canvas, const SkRect& rect) const;
int64_t GetCurrentValue() const;
int64_t GetMaxValue() const;
int64_t GetMinValue() const;
private:
std::vector<int64_t> values_;
size_t current_sample_;
FTL_DISALLOW_COPY_AND_ASSIGN(CounterValues);
};
} // namespace flow
#endif // FLUTTER_FLOW_INSTRUMENTATION_H_

View File

@@ -21,8 +21,8 @@
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkXfermode.h"
namespace flow {
@@ -45,6 +45,7 @@ class Layer {
SkCanvas& canvas;
const Stopwatch& frame_time;
const Stopwatch& engine_time;
const CounterValues& memory_usage;
};
virtual void Paint(PaintContext& context) = 0;

View File

@@ -51,7 +51,8 @@ void LayerTree::UpdateScene(SceneUpdateContext& context,
void LayerTree::Paint(CompositorContext::ScopedFrame& frame) {
Layer::PaintContext context = {frame.canvas(), frame.context().frame_time(),
frame.context().engine_time()};
frame.context().engine_time(),
frame.context().memory_usage()};
TRACE_EVENT0("flutter", "LayerTree::Paint");
root_layer_->Paint(context);
}

View File

@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <iostream>
#include <iomanip>
#include <iostream>
#include <string>
#include "flutter/flow/layers/performance_overlay_layer.h"
@@ -57,6 +57,34 @@ void VisualizeStopWatch(SkCanvas& canvas,
}
}
void VisualizeCounterValuesBytes(SkCanvas& canvas,
const CounterValues& counter_values,
SkScalar x,
SkScalar y,
SkScalar width,
SkScalar height,
bool show_graph,
bool show_labels,
const std::string& label_prefix) {
const int label_x = 8; // distance from x
const int label_y = -10; // distance from y+height
if (show_graph) {
SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height);
counter_values.Visualize(canvas, visualization_rect);
}
auto current_usage = counter_values.GetCurrentValue();
if (show_labels && current_usage > 0) {
std::stringstream stream;
stream.setf(std::ios::fixed | std::ios::showpoint);
stream << std::setprecision(2);
stream << label_prefix << " " << current_usage * 1e-6 << " MB";
DrawStatisticsText(canvas, stream.str(), x + label_x, y + height + label_y);
}
}
} // namespace
PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options)
@@ -80,6 +108,11 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) {
VisualizeStopWatch(context.canvas, context.engine_time, x, y + height, width,
height, options_ & kVisualizeEngineStatistics,
options_ & kDisplayEngineStatistics, "Engine");
VisualizeCounterValuesBytes(
context.canvas, context.memory_usage, x, y + (2 * height), width, height,
options_ & kVisualizeMemoryStatistics,
options_ & kDisplayMemoryStatistics, "Memory (Resident)");
}
} // namespace flow

View File

@@ -10,10 +10,12 @@
namespace flow {
const int kDisplayRasterizerStatistics = 0x01;
const int kVisualizeRasterizerStatistics = 0x02;
const int kDisplayEngineStatistics = 0x04;
const int kVisualizeEngineStatistics = 0x08;
const int kDisplayRasterizerStatistics = 1 << 0;
const int kVisualizeRasterizerStatistics = 1 << 1;
const int kDisplayEngineStatistics = 1 << 2;
const int kVisualizeEngineStatistics = 1 << 3;
const int kDisplayMemoryStatistics = 1 << 4;
const int kVisualizeMemoryStatistics = 1 << 5;
class PerformanceOverlayLayer : public Layer {
public:

View File

@@ -0,0 +1,29 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLOW_PROCESS_INFO_H_
#define FLUTTER_FLOW_PROCESS_INFO_H_
#include "lib/ftl/macros.h"
namespace flow {
/// The CompositorContext attempts to collect information from the process for
/// instrumentation purposes. The compositor does not have the platform
/// specific capabilities to collect this information on its own. The platform
/// can choose to provide this information however.
class ProcessInfo {
public:
virtual bool SampleNow() = 0;
/// Virtual memory size in bytes.
virtual size_t GetVirtualMemorySize() = 0;
/// Resident memory size in bytes.
virtual size_t GetResidentMemorySize() = 0;
};
} // namespace flow
#endif // FLUTTER_FLOW_PROCESS_INFO_H_

View File

@@ -10,9 +10,9 @@
#include "flutter/flow/compositor_context.h"
#include "flutter/runtime/embedder_resources.h"
#include "flutter/shell/common/engine.h"
#include "flutter/shell/common/picture_serializer.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/picture_serializer.h"
#include "lib/ftl/logging.h"
#include "lib/tonic/dart_binding_macros.h"
#include "lib/tonic/dart_library_natives.h"
@@ -125,7 +125,7 @@ void DiagnosticServer::SkiaPictureTask(Dart_Port port_id) {
recorder.beginRecording(SkRect::MakeWH(layer_tree->frame_size().width(),
layer_tree->frame_size().height()));
flow::CompositorContext compositor_context;
flow::CompositorContext compositor_context(nullptr);
flow::CompositorContext::ScopedFrame frame = compositor_context.AcquireFrame(
nullptr, recorder.getRecordingCanvas(), false);
layer_tree->Raster(frame);

View File

@@ -304,7 +304,7 @@ void PlatformViewServiceProtocol::ScreenshotGpuTask(SkBitmap* bitmap) {
sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(
bitmap->info(), bitmap->getPixels(), bitmap->rowBytes());
flow::CompositorContext compositor_context;
flow::CompositorContext compositor_context(nullptr);
SkCanvas* canvas = surface->getCanvas();
flow::CompositorContext::ScopedFrame frame =
compositor_context.AcquireFrame(nullptr, canvas, false);

View File

@@ -16,7 +16,8 @@
namespace shell {
GPURasterizer::GPURasterizer() : weak_factory_(this) {
GPURasterizer::GPURasterizer(std::unique_ptr<flow::ProcessInfo> info)
: compositor_context_(std::move(info)), weak_factory_(this) {
auto weak_ptr = weak_factory_.GetWeakPtr();
blink::Threads::Gpu()->PostTask(
[weak_ptr]() { Shell::Shared().AddRasterizer(weak_ptr); });

View File

@@ -16,7 +16,7 @@ class Surface;
class GPURasterizer : public Rasterizer {
public:
GPURasterizer();
GPURasterizer(std::unique_ptr<flow::ProcessInfo> info);
~GPURasterizer() override;

View File

@@ -62,7 +62,7 @@ class PlatformMessageResponseAndroid : public blink::PlatformMessageResponse {
} // namespace
PlatformViewAndroid::PlatformViewAndroid()
: PlatformView(std::make_unique<GPURasterizer>()) {
: PlatformView(std::make_unique<GPURasterizer>(nullptr)) {
CreateEngine();
// Create the GL surface so that we can setup the resource context.
@@ -497,7 +497,7 @@ void PlatformViewAndroid::GetBitmapGpuTask(jobject* pixels_out,
sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(
image_info, pixels, frame_size.width() * sizeof(jint));
flow::CompositorContext compositor_context;
flow::CompositorContext compositor_context(nullptr);
SkCanvas* canvas = surface->getCanvas();
flow::CompositorContext::ScopedFrame frame =
compositor_context.AcquireFrame(nullptr, canvas, false);

View File

@@ -9,8 +9,10 @@ source_set("common") {
sources = [
"platform_mac.h",
"platform_mac.mm",
"string_conversions.mm",
"process_info_mac.cc",
"process_info_mac.h",
"string_conversions.h",
"string_conversions.mm",
]
set_sources_assignment_filter(sources_assignment_filter)
@@ -19,6 +21,7 @@ source_set("common") {
"//base:i18n",
"//dart/runtime:libdart",
"//flutter/common",
"//flutter/flow",
"//flutter/runtime",
"//flutter/shell/common",
"//flutter/shell/gpu",

View File

@@ -0,0 +1,36 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/darwin/common/process_info_mac.h"
namespace shell {
ProcessInfoMac::ProcessInfoMac() = default;
ProcessInfoMac::~ProcessInfoMac() = default;
bool ProcessInfoMac::SampleNow() {
mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
kern_return_t result =
task_info(mach_task_self(), //
MACH_TASK_BASIC_INFO, //
reinterpret_cast<task_info_t>(&last_sample_), //
&size);
if (result == KERN_SUCCESS) {
return true;
}
last_sample_ = {};
return false;
}
size_t ProcessInfoMac::GetVirtualMemorySize() {
return last_sample_.virtual_size;
}
size_t ProcessInfoMac::GetResidentMemorySize() {
return last_sample_.resident_size;
}
} // namespace shell

View File

@@ -0,0 +1,36 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_
#include <mach/mach.h>
#include <mach/task.h>
#include <cstdlib>
#include "flutter/flow/process_info.h"
#include "lib/ftl/macros.h"
namespace shell {
class ProcessInfoMac : public flow::ProcessInfo {
public:
ProcessInfoMac();
~ProcessInfoMac();
bool SampleNow() override;
size_t GetVirtualMemorySize() override;
size_t GetResidentMemorySize() override;
private:
struct mach_task_basic_info last_sample_;
FTL_DISALLOW_COPY_AND_ASSIGN(ProcessInfoMac);
};
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_

View File

@@ -13,13 +13,15 @@
#include "flutter/shell/common/switches.h"
#include "flutter/shell/gpu/gpu_rasterizer.h"
#include "flutter/shell/platform/darwin/common/platform_mac.h"
#include "flutter/shell/platform/darwin/common/process_info_mac.h"
#include "flutter/shell/platform/darwin/desktop/vsync_waiter_mac.h"
#include "lib/ftl/synchronization/waitable_event.h"
namespace shell {
PlatformViewMac::PlatformViewMac(NSOpenGLView* gl_view)
: PlatformView(std::make_unique<GPURasterizer>()),
: PlatformView(
std::make_unique<GPURasterizer>(std::make_unique<ProcessInfoMac>())),
opengl_view_([gl_view retain]),
resource_loading_context_([[NSOpenGLContext alloc]
initWithFormat:gl_view.pixelFormat

View File

@@ -72,7 +72,7 @@ void SnapshotRasterizer(ftl::WeakPtr<shell::Rasterizer> rasterizer,
SkCanvas canvas(bitmap);
{
flow::CompositorContext compositor_context;
flow::CompositorContext compositor_context(nullptr);
auto frame = compositor_context.AcquireFrame(nullptr, &canvas,
false /* instrumentation */);
layer_tree->Raster(frame, false /* ignore raster cache. */);

View File

@@ -14,6 +14,7 @@
#include "base/trace_event/trace_event.h"
#include "flutter/common/threads.h"
#include "flutter/shell/gpu/gpu_rasterizer.h"
#include "flutter/shell/platform/darwin/common/process_info_mac.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
#include "lib/ftl/synchronization/waitable_event.h"
@@ -271,7 +272,8 @@ class IOSGLContext {
};
PlatformViewIOS::PlatformViewIOS(CAEAGLLayer* layer)
: PlatformView(std::make_unique<GPURasterizer>()),
: PlatformView(
std::make_unique<GPURasterizer>(std::make_unique<ProcessInfoMac>())),
context_(std::make_unique<IOSGLContext>(surface_config_, layer)),
weak_factory_(this) {
CreateEngine();