[profiler] Tracing-based CPU profiler.
A new V8 API object v8::TracingCpuProfiler is introduced. Client can create it on an isolate to enable JS CPU profiles collected during tracing session. Once the v8.cpu_profile2 tracing category is enabled the profiler emits CpuProfile and CpuProfileChunk events with the profile data. BUG=chromium:406277 Review-Url: https://codereview.chromium.org/2396733002 Cr-Commit-Position: refs/heads/master@{#40054}
This commit is contained in:
parent
549690f2bf
commit
4b575dfcef
@ -48,7 +48,7 @@ namespace v8 {
|
||||
|
||||
/**
|
||||
* TracingCpuProfiler monitors tracing being enabled/disabled
|
||||
* and emits CpuProfile trace events once v8.cpu_profile2 tracing category
|
||||
* and emits CpuProfile trace events once v8.cpu_profiler tracing category
|
||||
* is enabled. It has no overhead unless the category is enabled.
|
||||
*/
|
||||
class V8_EXPORT TracingCpuProfiler {
|
||||
|
@ -326,33 +326,21 @@ void CpuProfiler::StartProcessorIfNotStarted() {
|
||||
processor_->StartSynchronously();
|
||||
}
|
||||
|
||||
|
||||
CpuProfile* CpuProfiler::StopProfiling(const char* title) {
|
||||
if (!is_profiling_) return nullptr;
|
||||
StopProcessorIfLastProfile(title);
|
||||
CpuProfile* result = profiles_->StopProfiling(title);
|
||||
if (result) {
|
||||
result->Print();
|
||||
}
|
||||
return result;
|
||||
return profiles_->StopProfiling(title);
|
||||
}
|
||||
|
||||
|
||||
CpuProfile* CpuProfiler::StopProfiling(String* title) {
|
||||
if (!is_profiling_) return nullptr;
|
||||
const char* profile_title = profiles_->GetName(title);
|
||||
StopProcessorIfLastProfile(profile_title);
|
||||
return profiles_->StopProfiling(profile_title);
|
||||
return StopProfiling(profiles_->GetName(title));
|
||||
}
|
||||
|
||||
|
||||
void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
|
||||
if (profiles_->IsLastProfile(title)) {
|
||||
StopProcessor();
|
||||
}
|
||||
if (!profiles_->IsLastProfile(title)) return;
|
||||
StopProcessor();
|
||||
}
|
||||
|
||||
|
||||
void CpuProfiler::StopProcessor() {
|
||||
Logger* logger = isolate_->logger();
|
||||
is_profiling_ = false;
|
||||
|
@ -30,20 +30,22 @@ CodeEntry::CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
|
||||
line_info_(line_info),
|
||||
instruction_start_(instruction_start) {}
|
||||
|
||||
ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry)
|
||||
ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry,
|
||||
ProfileNode* parent)
|
||||
: tree_(tree),
|
||||
entry_(entry),
|
||||
self_ticks_(0),
|
||||
children_(CodeEntriesMatch),
|
||||
parent_(parent),
|
||||
id_(tree->next_node_id()),
|
||||
line_ticks_(LineTickMatch) {}
|
||||
|
||||
line_ticks_(LineTickMatch) {
|
||||
tree_->EnqueueNode(this);
|
||||
}
|
||||
|
||||
inline unsigned ProfileNode::function_id() const {
|
||||
return tree_->GetFunctionId(this);
|
||||
}
|
||||
|
||||
|
||||
inline Isolate* ProfileNode::isolate() const { return tree_->isolate(); }
|
||||
|
||||
} // namespace internal
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "src/global-handles.h"
|
||||
#include "src/profiler/cpu-profiler.h"
|
||||
#include "src/profiler/profile-generator-inl.h"
|
||||
#include "src/tracing/trace-event.h"
|
||||
#include "src/tracing/traced-value.h"
|
||||
#include "src/unicode.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -214,9 +216,8 @@ ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
|
||||
base::HashMap::Entry* map_entry =
|
||||
children_.LookupOrInsert(entry, CodeEntryHash(entry));
|
||||
ProfileNode* node = reinterpret_cast<ProfileNode*>(map_entry->value);
|
||||
if (node == NULL) {
|
||||
// New node added.
|
||||
node = new ProfileNode(tree_, entry);
|
||||
if (!node) {
|
||||
node = new ProfileNode(tree_, entry, this);
|
||||
map_entry->value = node;
|
||||
children_list_.Add(node);
|
||||
}
|
||||
@ -305,7 +306,7 @@ class DeleteNodesCallback {
|
||||
ProfileTree::ProfileTree(Isolate* isolate)
|
||||
: root_entry_(CodeEventListener::FUNCTION_TAG, "(root)"),
|
||||
next_node_id_(1),
|
||||
root_(new ProfileNode(this, &root_entry_)),
|
||||
root_(new ProfileNode(this, &root_entry_, nullptr)),
|
||||
isolate_(isolate),
|
||||
next_function_id_(1),
|
||||
function_ids_(ProfileNode::CodeEntriesMatch) {}
|
||||
@ -397,13 +398,22 @@ void ProfileTree::TraverseDepthFirst(Callback* callback) {
|
||||
}
|
||||
}
|
||||
|
||||
using v8::tracing::TracedValue;
|
||||
|
||||
CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
|
||||
bool record_samples)
|
||||
: title_(title),
|
||||
record_samples_(record_samples),
|
||||
start_time_(base::TimeTicks::HighResolutionNow()),
|
||||
top_down_(profiler->isolate()),
|
||||
profiler_(profiler) {}
|
||||
profiler_(profiler),
|
||||
streaming_next_sample_(0) {
|
||||
auto value = TracedValue::Create();
|
||||
value->SetDouble("startTime",
|
||||
(start_time_ - base::TimeTicks()).InMicroseconds());
|
||||
TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"),
|
||||
"CpuProfile", this, "data", std::move(value));
|
||||
}
|
||||
|
||||
void CpuProfile::AddPath(base::TimeTicks timestamp,
|
||||
const std::vector<CodeEntry*>& path, int src_line,
|
||||
@ -414,10 +424,91 @@ void CpuProfile::AddPath(base::TimeTicks timestamp,
|
||||
timestamps_.Add(timestamp);
|
||||
samples_.Add(top_frame_node);
|
||||
}
|
||||
const int kSamplesFlushCount = 100;
|
||||
const int kNodesFlushCount = 10;
|
||||
if (samples_.length() - streaming_next_sample_ >= kSamplesFlushCount ||
|
||||
top_down_.pending_nodes_count() >= kNodesFlushCount) {
|
||||
StreamPendingTraceEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuProfile::CalculateTotalTicksAndSamplingRate() {
|
||||
namespace {
|
||||
|
||||
void BuildNodeValue(const ProfileNode* node, TracedValue* value) {
|
||||
const CodeEntry* entry = node->entry();
|
||||
value->BeginDictionary("callFrame");
|
||||
value->SetString("functionName", entry->name());
|
||||
if (*entry->resource_name()) {
|
||||
value->SetString("url", entry->resource_name());
|
||||
}
|
||||
value->SetInteger("scriptId", entry->script_id());
|
||||
if (entry->line_number()) {
|
||||
value->SetInteger("lineNumber", entry->line_number() - 1);
|
||||
}
|
||||
if (entry->column_number()) {
|
||||
value->SetInteger("columnNumber", entry->column_number() - 1);
|
||||
}
|
||||
value->EndDictionary();
|
||||
value->SetInteger("id", node->id());
|
||||
if (node->parent()) {
|
||||
value->SetInteger("parent", node->parent()->id());
|
||||
}
|
||||
const char* deopt_reason = entry->bailout_reason();
|
||||
if (deopt_reason && deopt_reason[0] && strcmp(deopt_reason, "no reason")) {
|
||||
value->SetString("deoptReason", deopt_reason);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CpuProfile::StreamPendingTraceEvents() {
|
||||
std::vector<const ProfileNode*> pending_nodes = top_down_.TakePendingNodes();
|
||||
if (pending_nodes.empty() && !samples_.length()) return;
|
||||
auto value = TracedValue::Create();
|
||||
|
||||
if (!pending_nodes.empty()) {
|
||||
value->BeginArray("nodes");
|
||||
for (auto node : pending_nodes) {
|
||||
value->BeginDictionary();
|
||||
BuildNodeValue(node, value.get());
|
||||
value->EndDictionary();
|
||||
}
|
||||
value->EndArray();
|
||||
}
|
||||
|
||||
if (streaming_next_sample_ != samples_.length()) {
|
||||
value->BeginArray("samples");
|
||||
for (int i = streaming_next_sample_; i < samples_.length(); ++i) {
|
||||
value->AppendInteger(samples_[i]->id());
|
||||
}
|
||||
value->EndArray();
|
||||
value->BeginArray("timeDeltas");
|
||||
base::TimeTicks lastTimestamp =
|
||||
streaming_next_sample_ ? timestamps_[streaming_next_sample_ - 1]
|
||||
: start_time();
|
||||
for (int i = streaming_next_sample_; i < timestamps_.length(); ++i) {
|
||||
value->AppendInteger(
|
||||
static_cast<int>((timestamps_[i] - lastTimestamp).InMicroseconds()));
|
||||
lastTimestamp = timestamps_[i];
|
||||
}
|
||||
value->EndArray();
|
||||
DCHECK(samples_.length() == timestamps_.length());
|
||||
streaming_next_sample_ = samples_.length();
|
||||
}
|
||||
|
||||
TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"),
|
||||
"CpuProfileChunk", this, "data",
|
||||
std::move(value));
|
||||
}
|
||||
|
||||
void CpuProfile::FinishProfile() {
|
||||
end_time_ = base::TimeTicks::HighResolutionNow();
|
||||
StreamPendingTraceEvents();
|
||||
auto value = TracedValue::Create();
|
||||
value->SetDouble("endTime", (end_time_ - base::TimeTicks()).InMicroseconds());
|
||||
TRACE_EVENT_SAMPLE_WITH_ID1(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"),
|
||||
"CpuProfileChunk", this, "data",
|
||||
std::move(value));
|
||||
}
|
||||
|
||||
void CpuProfile::Print() {
|
||||
@ -504,7 +595,7 @@ bool CpuProfilesCollection::StartProfiling(const char* title,
|
||||
|
||||
CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
|
||||
const int title_len = StrLength(title);
|
||||
CpuProfile* profile = NULL;
|
||||
CpuProfile* profile = nullptr;
|
||||
current_profiles_semaphore_.Wait();
|
||||
for (int i = current_profiles_.length() - 1; i >= 0; --i) {
|
||||
if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) {
|
||||
@ -514,8 +605,8 @@ CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
|
||||
}
|
||||
current_profiles_semaphore_.Signal();
|
||||
|
||||
if (profile == NULL) return NULL;
|
||||
profile->CalculateTotalTicksAndSamplingRate();
|
||||
if (!profile) return nullptr;
|
||||
profile->FinishProfile();
|
||||
finished_profiles_.Add(profile);
|
||||
return profile;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ class ProfileTree;
|
||||
|
||||
class ProfileNode {
|
||||
public:
|
||||
inline ProfileNode(ProfileTree* tree, CodeEntry* entry);
|
||||
inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent);
|
||||
|
||||
ProfileNode* FindChild(CodeEntry* entry);
|
||||
ProfileNode* FindOrAddChild(CodeEntry* entry);
|
||||
@ -196,6 +196,7 @@ class ProfileNode {
|
||||
const List<ProfileNode*>* children() const { return &children_list_; }
|
||||
unsigned id() const { return id_; }
|
||||
unsigned function_id() const;
|
||||
ProfileNode* parent() const { return parent_; }
|
||||
unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
|
||||
bool GetLineTicks(v8::CpuProfileNode::LineTick* entries,
|
||||
unsigned int length) const;
|
||||
@ -223,6 +224,7 @@ class ProfileNode {
|
||||
// Mapping from CodeEntry* to ProfileNode*
|
||||
base::CustomMatcherHashMap children_;
|
||||
List<ProfileNode*> children_list_;
|
||||
ProfileNode* parent_;
|
||||
unsigned id_;
|
||||
base::CustomMatcherHashMap line_ticks_;
|
||||
|
||||
@ -251,10 +253,18 @@ class ProfileTree {
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
|
||||
void EnqueueNode(const ProfileNode* node) { pending_nodes_.push_back(node); }
|
||||
size_t pending_nodes_count() const { return pending_nodes_.size(); }
|
||||
std::vector<const ProfileNode*> TakePendingNodes() {
|
||||
return std::move(pending_nodes_);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Callback>
|
||||
void TraverseDepthFirst(Callback* callback);
|
||||
|
||||
std::vector<const ProfileNode*> pending_nodes_;
|
||||
|
||||
CodeEntry root_entry_;
|
||||
unsigned next_node_id_;
|
||||
ProfileNode* root_;
|
||||
@ -274,7 +284,7 @@ class CpuProfile {
|
||||
// Add pc -> ... -> main() call path to the profile.
|
||||
void AddPath(base::TimeTicks timestamp, const std::vector<CodeEntry*>& path,
|
||||
int src_line, bool update_stats);
|
||||
void CalculateTotalTicksAndSamplingRate();
|
||||
void FinishProfile();
|
||||
|
||||
const char* title() const { return title_; }
|
||||
const ProfileTree* top_down() const { return &top_down_; }
|
||||
@ -294,6 +304,8 @@ class CpuProfile {
|
||||
void Print();
|
||||
|
||||
private:
|
||||
void StreamPendingTraceEvents();
|
||||
|
||||
const char* title_;
|
||||
bool record_samples_;
|
||||
base::TimeTicks start_time_;
|
||||
@ -302,6 +314,7 @@ class CpuProfile {
|
||||
List<base::TimeTicks> timestamps_;
|
||||
ProfileTree top_down_;
|
||||
CpuProfiler* const profiler_;
|
||||
int streaming_next_sample_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CpuProfile);
|
||||
};
|
||||
|
@ -4,8 +4,13 @@
|
||||
|
||||
#include "src/profiler/tracing-cpu-profiler.h"
|
||||
|
||||
#include "src/profiler/cpu-profiler.h"
|
||||
#include "src/tracing/trace-event.h"
|
||||
#include "src/v8.h"
|
||||
|
||||
#define PROFILER_TRACE_CATEGORY_ENABLED(cat) \
|
||||
(*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT(cat)))
|
||||
|
||||
namespace v8 {
|
||||
|
||||
std::unique_ptr<TracingCpuProfiler> TracingCpuProfiler::Create(
|
||||
@ -17,9 +22,57 @@ std::unique_ptr<TracingCpuProfiler> TracingCpuProfiler::Create(
|
||||
|
||||
namespace internal {
|
||||
|
||||
TracingCpuProfilerImpl::TracingCpuProfilerImpl(Isolate* isolate) {}
|
||||
TracingCpuProfilerImpl::TracingCpuProfilerImpl(Isolate* isolate)
|
||||
: isolate_(isolate), profiling_enabled_(false) {
|
||||
// Make sure tracing system notices profiler categories.
|
||||
PROFILER_TRACE_CATEGORY_ENABLED("v8.cpu_profiler");
|
||||
PROFILER_TRACE_CATEGORY_ENABLED("v8.cpu_profiler.hires");
|
||||
V8::GetCurrentPlatform()->AddTraceStateObserver(this);
|
||||
}
|
||||
|
||||
TracingCpuProfilerImpl::~TracingCpuProfilerImpl() {}
|
||||
TracingCpuProfilerImpl::~TracingCpuProfilerImpl() {
|
||||
StopProfiling();
|
||||
V8::GetCurrentPlatform()->RemoveTraceStateObserver(this);
|
||||
}
|
||||
|
||||
void TracingCpuProfilerImpl::OnTraceEnabled() {
|
||||
if (!PROFILER_TRACE_CATEGORY_ENABLED("v8.cpu_profiler")) return;
|
||||
profiling_enabled_ = true;
|
||||
isolate_->RequestInterrupt(
|
||||
[](v8::Isolate*, void* data) {
|
||||
reinterpret_cast<TracingCpuProfilerImpl*>(data)->StartProfiling();
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
void TracingCpuProfilerImpl::OnTraceDisabled() {
|
||||
base::LockGuard<base::Mutex> lock(&mutex_);
|
||||
if (!profiling_enabled_) return;
|
||||
profiling_enabled_ = false;
|
||||
isolate_->RequestInterrupt(
|
||||
[](v8::Isolate*, void* data) {
|
||||
reinterpret_cast<TracingCpuProfilerImpl*>(data)->StopProfiling();
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
void TracingCpuProfilerImpl::StartProfiling() {
|
||||
base::LockGuard<base::Mutex> lock(&mutex_);
|
||||
if (!profiling_enabled_ || profiler_) return;
|
||||
int sampling_interval_us =
|
||||
PROFILER_TRACE_CATEGORY_ENABLED("v8.cpu_profiler.hires") ? 100 : 1000;
|
||||
profiler_.reset(new CpuProfiler(isolate_));
|
||||
profiler_->set_sampling_interval(
|
||||
base::TimeDelta::FromMicroseconds(sampling_interval_us));
|
||||
profiler_->StartProfiling("", true);
|
||||
}
|
||||
|
||||
void TracingCpuProfilerImpl::StopProfiling() {
|
||||
base::LockGuard<base::Mutex> lock(&mutex_);
|
||||
if (!profiler_) return;
|
||||
profiler_->StopProfiling("");
|
||||
profiler_.reset();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -5,18 +5,37 @@
|
||||
#ifndef V8_PROFILER_TRACING_CPU_PROFILER_H
|
||||
#define V8_PROFILER_TRACING_CPU_PROFILER_H
|
||||
|
||||
#include "include/v8-platform.h"
|
||||
#include "include/v8-profiler.h"
|
||||
#include "src/base/atomic-utils.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class TracingCpuProfilerImpl final : public TracingCpuProfiler {
|
||||
class CpuProfiler;
|
||||
class Isolate;
|
||||
|
||||
class TracingCpuProfilerImpl final : public TracingCpuProfiler,
|
||||
private v8::Platform::TraceStateObserver {
|
||||
public:
|
||||
explicit TracingCpuProfilerImpl(Isolate*);
|
||||
~TracingCpuProfilerImpl();
|
||||
|
||||
// v8::Platform::TraceStateObserver
|
||||
void OnTraceEnabled() final;
|
||||
void OnTraceDisabled() final;
|
||||
|
||||
private:
|
||||
void StartProfiling();
|
||||
void StopProfiling();
|
||||
|
||||
Isolate* isolate_;
|
||||
std::unique_ptr<CpuProfiler> profiler_;
|
||||
bool profiling_enabled_;
|
||||
base::Mutex mutex_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TracingCpuProfilerImpl);
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,9 @@
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/profiler-extension.h"
|
||||
|
||||
#include "include/libplatform/v8-tracing.h"
|
||||
#include "src/tracing/trace-event.h"
|
||||
|
||||
using i::CodeEntry;
|
||||
using i::CpuProfile;
|
||||
using i::CpuProfiler;
|
||||
@ -2098,3 +2101,79 @@ TEST(DeoptUntrackedFunction) {
|
||||
|
||||
iprofiler->DeleteProfile(iprofile);
|
||||
}
|
||||
|
||||
using v8::platform::tracing::TraceBuffer;
|
||||
using v8::platform::tracing::TraceConfig;
|
||||
using v8::platform::tracing::TraceObject;
|
||||
|
||||
namespace {
|
||||
|
||||
class CpuProfileEventChecker : public v8::platform::tracing::TraceWriter {
|
||||
public:
|
||||
void AppendTraceEvent(TraceObject* trace_event) override {
|
||||
if (trace_event->name() != std::string("CpuProfile") &&
|
||||
trace_event->name() != std::string("CpuProfileChunk"))
|
||||
return;
|
||||
CHECK(!profile_id_ || trace_event->id() == profile_id_);
|
||||
CHECK_EQ(1, trace_event->num_args());
|
||||
CHECK_EQ(TRACE_VALUE_TYPE_CONVERTABLE, trace_event->arg_types()[0]);
|
||||
profile_id_ = trace_event->id();
|
||||
v8::ConvertableToTraceFormat* arg =
|
||||
trace_event->arg_convertables()[0].get();
|
||||
arg->AppendAsTraceFormat(&result_json_);
|
||||
}
|
||||
void Flush() override {}
|
||||
|
||||
std::string result_json() const { return result_json_; }
|
||||
|
||||
private:
|
||||
std::string result_json_;
|
||||
uint64_t profile_id_ = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(TracingCpuProfiler) {
|
||||
v8::Platform* old_platform = i::V8::GetCurrentPlatform();
|
||||
v8::Platform* default_platform = v8::platform::CreateDefaultPlatform();
|
||||
i::V8::SetPlatformForTesting(default_platform);
|
||||
|
||||
v8::platform::tracing::TracingController tracing_controller;
|
||||
v8::platform::SetTracingController(default_platform, &tracing_controller);
|
||||
|
||||
CpuProfileEventChecker* event_checker = new CpuProfileEventChecker();
|
||||
TraceBuffer* ring_buffer =
|
||||
TraceBuffer::CreateTraceBufferRingBuffer(1, event_checker);
|
||||
tracing_controller.Initialize(ring_buffer);
|
||||
TraceConfig* trace_config = new TraceConfig();
|
||||
trace_config->AddIncludedCategory(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler"));
|
||||
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
{
|
||||
tracing_controller.StartTracing(trace_config);
|
||||
auto profiler = v8::TracingCpuProfiler::Create(env->GetIsolate());
|
||||
CompileRun("function foo() { } foo();");
|
||||
tracing_controller.StopTracing();
|
||||
CompileRun("function bar() { } bar();");
|
||||
}
|
||||
|
||||
const char* profile_checker =
|
||||
"function checkProfile(profile) {\n"
|
||||
" if (typeof profile['startTime'] !== 'number') return 'startTime';\n"
|
||||
" return '';\n"
|
||||
"}\n"
|
||||
"checkProfile(";
|
||||
std::string profile_json = event_checker->result_json();
|
||||
CHECK_LT(0u, profile_json.length());
|
||||
printf("Profile JSON: %s\n", profile_json.c_str());
|
||||
std::string code = profile_checker + profile_json + ")";
|
||||
v8::Local<v8::Value> result =
|
||||
CompileRunChecked(CcTest::isolate(), code.c_str());
|
||||
v8::String::Utf8Value value(result);
|
||||
printf("Check result: %*s\n", value.length(), *value);
|
||||
CHECK_EQ(0, value.length());
|
||||
|
||||
i::V8::SetPlatformForTesting(old_platform);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user