Skip to content

Commit

Permalink
Implement Cobalt wrappers for v8::CpuProfiler
Browse files Browse the repository at this point in the history
Provides a baseline cobalt-side implementation of the JS Self-Profiling
API (https://wicg.github.io/js-self-profiling/). Adds Profiler, which
wraps a profile handle from a v8::CpuProfiler, and relevant IDL bindings.

Change-Id: I35577d4f0353144475e7181137ad0d5fadd7791d
  • Loading branch information
Ahmed Elzeiny committed Dec 1, 2023
1 parent 5741f3a commit 9017f60
Show file tree
Hide file tree
Showing 20 changed files with 715 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cobalt/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ target(final_executable_type, "cobalt") {
":browser_switches",
"//cobalt/base",
"//cobalt/css_parser",
"//cobalt/profiler:js_profiler",
"//net",
]
data_deps = [
Expand Down Expand Up @@ -177,6 +178,7 @@ static_library("browser") {
"//cobalt/network",
"//cobalt/overlay_info",
"//cobalt/persistent_storage:persistent_settings",
"//cobalt/profiler:js_profiler",
"//cobalt/render_tree",
"//cobalt/renderer",
"//cobalt/renderer/test/png_utils",
Expand Down
8 changes: 8 additions & 0 deletions cobalt/browser/idl_files.gni
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ source_idl_files = [
"//cobalt/xhr/xml_http_request.idl",
"//cobalt/xhr/xml_http_request_event_target.idl",
"//cobalt/xhr/xml_http_request_upload.idl",

"//cobalt/profiler/profiler.idl",
"//cobalt/profiler/profiler_trace_wrapper.idl",
]

if (!is_gold) {
Expand Down Expand Up @@ -312,6 +315,11 @@ generated_header_idl_files = [
"//cobalt/encoding/text_decode_options.idl",
"//cobalt/encoding/text_decoder_options.idl",
"//cobalt/encoding/text_encoder_encode_into_result.idl",
"//cobalt/profiler/profiler_frame.idl",
"//cobalt/profiler/profiler_init_options.idl",
"//cobalt/profiler/profiler_sample.idl",
"//cobalt/profiler/profiler_stack.idl",
"//cobalt/profiler/profiler_trace.idl",
"//cobalt/h5vcc/h5vcc_crash_type.idl",
"//cobalt/h5vcc/h5vcc_metric_type.idl",
"//cobalt/h5vcc/h5vcc_storage_resource_type_quota_bytes_dictionary.idl",
Expand Down
33 changes: 33 additions & 0 deletions cobalt/profiler/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2023 The Cobalt Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

static_library("js_profiler") {
sources = [
"profiler.cc",
"profiler.h",
"profiler_trace_wrapper.h",
]

deps = [
"//cobalt/base",
"//cobalt/browser:generated_bindings",
"//cobalt/browser:generated_types",
"//cobalt/dom",
"//cobalt/script",
"//cobalt/script/v8c:engine",
"//cobalt/web",
"//third_party/angle:libANGLE_headers",
"//third_party/chromium/media:media",
]
}
90 changes: 90 additions & 0 deletions cobalt/profiler/profiler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/profiler/profiler.h"

#include <memory>
#include <string>
#include <utility>

#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/profiler/profiler_trace_wrapper.h"
#include "cobalt/web/cache_utils.h"
#include "cobalt/web/context.h"
#include "cobalt/web/dom_exception.h"
#include "cobalt/web/environment_settings.h"
#include "cobalt/web/environment_settings_helper.h"

namespace cobalt {
namespace profiler {

volatile uint32_t s_lastProfileId = 0;


Profiler::Profiler(script::EnvironmentSettings* settings,
ProfilerInitOptions options)
: cobalt::web::EventTarget(settings),
stopped_(false),
time_origin_{base::TimeTicks::Now()} {
auto* js_engine = web::get_context(settings)->javascript_engine();

profiler_id_ = nextProfileId();
sample_interval_ = options.sample_interval();
js_engine->StartProfiling(options.sample_interval(),
options.max_buffer_size(), profiler_id_);
}

std::string Profiler::nextProfileId() {
s_lastProfileId++;
return "cobalt::profiler[" + std::to_string(s_lastProfileId) + "]";
}

void Profiler::PerformStop(
script::EnvironmentSettings* environment_settings,
std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference,
base::TimeTicks time_origin, std::string profiler_id) {
auto js_engine = web::get_context(environment_settings)->javascript_engine();
auto trace = js_engine->StopProfiling(profiler_id_, time_origin_);
scoped_refptr<ProfilerTraceWrapper> result = new ProfilerTraceWrapper(trace);
promise_reference->value().Resolve(result);
}

Profiler::ProfilerTracePromise Profiler::Stop(
script::EnvironmentSettings* environment_settings) {
script::HandlePromiseWrappable promise =
web::get_script_value_factory(environment_settings)
->CreateInterfacePromise<scoped_refptr<ProfilerTraceWrapper>>();
if (!stopped()) {
stopped_ = true;
auto* global_wrappable = web::get_global_wrappable(environment_settings);
auto* context = web::get_context(environment_settings);
std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference(
new script::ValuePromiseWrappable::Reference(global_wrappable,
promise));


context->message_loop()->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&Profiler::PerformStop, base::Unretained(this),
environment_settings, std::move(promise_reference),
std::move(time_origin_), std::move(profiler_id_)));
} else {
promise->Reject(new web::DOMException(web::DOMException::kInvalidStateErr,
"Profiler already stopped."));
}
return promise;
}

} // namespace profiler
} // namespace cobalt
61 changes: 61 additions & 0 deletions cobalt/profiler/profiler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef COBALT_PROFILER_PROFILER_H_
#define COBALT_PROFILER_PROFILER_H_

#include <memory>
#include <string>

#include "cobalt/dom/performance_high_resolution_time.h"
#include "cobalt/profiler/profiler_init_options.h"
#include "cobalt/profiler/profiler_trace.h"
#include "cobalt/script/promise.h"
#include "cobalt/script/value_handle.h"
#include "cobalt/script/wrappable.h"
#include "cobalt/web/event_target.h"

namespace cobalt {
namespace profiler {

class Profiler : public cobalt::web::EventTarget {
public:
using ProfilerTracePromise = script::HandlePromiseWrappable;

Profiler(script::EnvironmentSettings* settings, ProfilerInitOptions options);

ProfilerTracePromise Stop(script::EnvironmentSettings* environment_settings);

bool stopped() const { return stopped_; }

dom::DOMHighResTimeStamp sample_interval() const { return sample_interval_; }

DEFINE_WRAPPABLE_TYPE(Profiler);

private:
void PerformStop(script::EnvironmentSettings* environment_settings,
std::unique_ptr<script::ValuePromiseWrappable::Reference>
promise_reference,
base::TimeTicks time_origin, std::string profiler_id);

std::string nextProfileId();

bool stopped_;
dom::DOMHighResTimeStamp sample_interval_;
base::TimeTicks time_origin_;
std::string profiler_id_;
};
} // namespace profiler
} // namespace cobalt
#endif // COBALT_PROFILER_PROFILER_H_
23 changes: 23 additions & 0 deletions cobalt/profiler/profiler.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://wicg.github.io/js-self-profiling/#the-profiler-interface

[Exposed=Window, Constructor(ProfilerInitOptions options), ConstructorCallWith=EnvironmentSettings,]
interface Profiler : EventTarget {
readonly attribute DOMHighResTimeStamp sampleInterval;
readonly attribute boolean stopped;

[CallWith=EnvironmentSettings] Promise<ProfilerTraceWrapper> stop();
};
22 changes: 22 additions & 0 deletions cobalt/profiler/profiler_frame.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://wicg.github.io/js-self-profiling/#the-profilerframe-dictionary

dictionary ProfilerFrame {
required DOMString name;
unsigned long long resourceId;
unsigned long long line;
unsigned long long column;
};
18 changes: 18 additions & 0 deletions cobalt/profiler/profiler_init_options.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

dictionary ProfilerInitOptions {
required DOMHighResTimeStamp sampleInterval;
required unsigned long maxBufferSize;
};
20 changes: 20 additions & 0 deletions cobalt/profiler/profiler_sample.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://wicg.github.io/js-self-profiling/#the-profilersample-dictionary

dictionary ProfilerSample {
required DOMHighResTimeStamp timestamp;
unsigned long long stackId;
};
20 changes: 20 additions & 0 deletions cobalt/profiler/profiler_stack.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://wicg.github.io/js-self-profiling/#the-profilerstack-dictionary

dictionary ProfilerStack {
unsigned long long parentId;
required unsigned long long frameId;
};
22 changes: 22 additions & 0 deletions cobalt/profiler/profiler_trace.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2023 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// https://wicg.github.io/js-self-profiling/#the-profilertrace-dictionary

dictionary ProfilerTrace {
required sequence<DOMString> resources;
required sequence<ProfilerFrame> frames;
required sequence<ProfilerStack> stacks;
required sequence<ProfilerSample> samples;
};
Loading

0 comments on commit 9017f60

Please sign in to comment.