From: dcarney@chromium.org Date: Tue, 21 Oct 2014 12:38:46 +0000 (+0000) Subject: [turbofan] add ZonePool to correctly track compiler phase memory usage X-Git-Tag: upstream/4.7.83~6220 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=54fef44df3390e9b0f349df4fa08ae04ce64cb3b;p=platform%2Fupstream%2Fv8.git [turbofan] add ZonePool to correctly track compiler phase memory usage R=bmeurer@chromium.org BUG= Review URL: https://codereview.chromium.org/665893006 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24771 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/BUILD.gn b/BUILD.gn index 01972a0..515e969 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -582,6 +582,8 @@ source_set("v8_base") { "src/compiler/value-numbering-reducer.h", "src/compiler/verifier.cc", "src/compiler/verifier.h", + 'src/compiler/zone-pool.cc', + 'src/compiler/zone-pool.h', "src/compiler.cc", "src/compiler.h", "src/contexts.cc", diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc index df86737..8c99561 100644 --- a/src/compiler/pipeline.cc +++ b/src/compiler/pipeline.cc @@ -30,6 +30,7 @@ #include "src/compiler/typer.h" #include "src/compiler/value-numbering-reducer.h" #include "src/compiler/verifier.h" +#include "src/compiler/zone-pool.h" #include "src/hydrogen.h" #include "src/ostreams.h" #include "src/utils.h" @@ -42,20 +43,24 @@ class PhaseStats { public: enum PhaseKind { CREATE_GRAPH, OPTIMIZATION, CODEGEN }; - PhaseStats(CompilationInfo* info, PhaseKind kind, const char* name) + PhaseStats(CompilationInfo* info, ZonePool* zone_pool, PhaseKind kind, + const char* name) : info_(info), + stats_scope_(zone_pool), kind_(kind), name_(name), - size_(info->zone()->allocation_size()) { + size_(0) { if (FLAG_turbo_stats) { timer_.Start(); + size_ = info_->zone()->allocation_size(); } } ~PhaseStats() { if (FLAG_turbo_stats) { base::TimeDelta delta = timer_.Elapsed(); - size_t bytes = info_->zone()->allocation_size() - size_; + size_t bytes = info_->zone()->allocation_size() + + stats_scope_.GetMaxAllocatedBytes() - size_; HStatistics* stats = info_->isolate()->GetTStatistics(); stats->SaveTiming(name_, delta, static_cast(bytes)); @@ -75,6 +80,7 @@ class PhaseStats { private: CompilationInfo* info_; + ZonePool::StatsScope stats_scope_; PhaseKind kind_; const char* name_; size_t size_; @@ -229,6 +235,8 @@ Handle Pipeline::GenerateCode() { PrintCompilationStart(); } + ZonePool zone_pool(isolate()); + // Build the graph. Graph graph(zone()); SourcePositionTable source_positions(&graph); @@ -243,7 +251,7 @@ Handle Pipeline::GenerateCode() { JSGraph jsgraph(&graph, &common, &javascript, &machine); Node* context_node; { - PhaseStats graph_builder_stats(info(), PhaseStats::CREATE_GRAPH, + PhaseStats graph_builder_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH, "graph builder"); AstGraphBuilderWithPositions graph_builder(info(), &jsgraph, &source_positions); @@ -251,7 +259,7 @@ Handle Pipeline::GenerateCode() { context_node = graph_builder.GetFunctionContext(); } { - PhaseStats phi_reducer_stats(info(), PhaseStats::CREATE_GRAPH, + PhaseStats phi_reducer_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH, "phi reduction"); PhiReducer phi_reducer; GraphReducer graph_reducer(&graph); @@ -292,13 +300,14 @@ Handle Pipeline::GenerateCode() { if (info()->is_typing_enabled()) { { // Type the graph. - PhaseStats typer_stats(info(), PhaseStats::CREATE_GRAPH, "typer"); + PhaseStats typer_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH, + "typer"); typer.Run(); VerifyAndPrintGraph(&graph, "Typed"); } { // Lower JSOperators where we can determine types. - PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH, + PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH, "typed lowering"); SourcePositionTable::Scope pos(&source_positions, SourcePosition::Unknown()); @@ -315,7 +324,7 @@ Handle Pipeline::GenerateCode() { } { // Lower simplified operators and insert changes. - PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH, + PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH, "simplified lowering"); SourcePositionTable::Scope pos(&source_positions, SourcePosition::Unknown()); @@ -332,7 +341,7 @@ Handle Pipeline::GenerateCode() { } { // Lower changes that have been inserted before. - PhaseStats lowering_stats(info(), PhaseStats::OPTIMIZATION, + PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::OPTIMIZATION, "change lowering"); SourcePositionTable::Scope pos(&source_positions, SourcePosition::Unknown()); @@ -356,8 +365,8 @@ Handle Pipeline::GenerateCode() { { SourcePositionTable::Scope pos(&source_positions, SourcePosition::Unknown()); - PhaseStats control_reducer_stats(info(), PhaseStats::CREATE_GRAPH, - "control reduction"); + PhaseStats control_reducer_stats( + info(), &zone_pool, PhaseStats::CREATE_GRAPH, "control reduction"); ControlReducer::ReduceGraph(&jsgraph, &common); VerifyAndPrintGraph(&graph, "Control reduced"); @@ -366,7 +375,7 @@ Handle Pipeline::GenerateCode() { { // Lower any remaining generic JSOperators. - PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH, + PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH, "generic lowering"); SourcePositionTable::Scope pos(&source_positions, SourcePosition::Unknown()); @@ -384,9 +393,10 @@ Handle Pipeline::GenerateCode() { Handle code = Handle::null(); { // Compute a schedule. - Schedule* schedule = ComputeSchedule(&graph); + Schedule* schedule = ComputeSchedule(&zone_pool, &graph); // Generate optimized code. - PhaseStats codegen_stats(info(), PhaseStats::CODEGEN, "codegen"); + PhaseStats codegen_stats(info(), &zone_pool, PhaseStats::CODEGEN, + "codegen"); Linkage linkage(info()); code = GenerateCode(&linkage, &graph, schedule, &source_positions); info()->SetCode(code); @@ -407,9 +417,10 @@ Handle Pipeline::GenerateCode() { } -Schedule* Pipeline::ComputeSchedule(Graph* graph) { - PhaseStats schedule_stats(info(), PhaseStats::CODEGEN, "scheduling"); - Schedule* schedule = Scheduler::ComputeSchedule(graph); +Schedule* Pipeline::ComputeSchedule(ZonePool* zone_pool, Graph* graph) { + PhaseStats schedule_stats(info(), zone_pool, PhaseStats::CODEGEN, + "scheduling"); + Schedule* schedule = Scheduler::ComputeSchedule(zone_pool, graph); TraceSchedule(schedule); if (VerifyGraphs()) ScheduleVerifier::Run(schedule); return schedule; @@ -423,7 +434,8 @@ Handle Pipeline::GenerateCodeForMachineGraph(Linkage* linkage, if (schedule == NULL) { // TODO(rossberg): Should this really be untyped? VerifyAndPrintGraph(graph, "Machine", true); - schedule = ComputeSchedule(graph); + ZonePool zone_pool(isolate()); + schedule = ComputeSchedule(&zone_pool, graph); } TraceSchedule(schedule); diff --git a/src/compiler/pipeline.h b/src/compiler/pipeline.h index c13a324..14688d9 100644 --- a/src/compiler/pipeline.h +++ b/src/compiler/pipeline.h @@ -25,6 +25,7 @@ class Linkage; class RegisterAllocator; class Schedule; class SourcePositionTable; +class ZonePool; class Pipeline { public: @@ -51,7 +52,7 @@ class Pipeline { Isolate* isolate() { return info_->isolate(); } Zone* zone() { return info_->zone(); } - Schedule* ComputeSchedule(Graph* graph); + Schedule* ComputeSchedule(ZonePool* zone_pool, Graph* graph); void OpenTurboCfgFile(std::ofstream* stream); void PrintCompilationStart(); void PrintScheduleAndInstructions(const char* phase, const Schedule* schedule, diff --git a/src/compiler/raw-machine-assembler.cc b/src/compiler/raw-machine-assembler.cc index 7f45eb9..39d44f3 100644 --- a/src/compiler/raw-machine-assembler.cc +++ b/src/compiler/raw-machine-assembler.cc @@ -39,7 +39,8 @@ RawMachineAssembler::RawMachineAssembler(Graph* graph, Schedule* RawMachineAssembler::Export() { // Compute the correct codegen order. DCHECK(schedule_->rpo_order()->empty()); - Scheduler::ComputeSpecialRPO(schedule_); + ZonePool zone_pool(isolate()); + Scheduler::ComputeSpecialRPO(&zone_pool, schedule_); // Invalidate MachineAssembler. Schedule* schedule = schedule_; schedule_ = NULL; diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc index 4952827..16773c5 100644 --- a/src/compiler/scheduler.cc +++ b/src/compiler/scheduler.cc @@ -28,8 +28,10 @@ static inline void Trace(const char* msg, ...) { } -Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) - : zone_(zone), +Scheduler::Scheduler(ZonePool* zone_pool, Zone* zone, Graph* graph, + Schedule* schedule) + : zone_pool_(zone_pool), + zone_(zone), graph_(graph), schedule_(schedule), scheduled_nodes_(zone), @@ -38,17 +40,17 @@ Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule) has_floating_control_(false) {} -Schedule* Scheduler::ComputeSchedule(Graph* graph) { +Schedule* Scheduler::ComputeSchedule(ZonePool* zone_pool, Graph* graph) { Schedule* schedule; bool had_floating_control = false; do { - Zone tmp_zone(graph->zone()->isolate()); + ZonePool::Scope zone_scope(zone_pool); schedule = new (graph->zone()) Schedule(graph->zone(), static_cast(graph->NodeCount())); - Scheduler scheduler(&tmp_zone, graph, schedule); + Scheduler scheduler(zone_pool, zone_scope.zone(), graph, schedule); scheduler.BuildCFG(); - Scheduler::ComputeSpecialRPO(schedule); + Scheduler::ComputeSpecialRPO(zone_pool, schedule); scheduler.GenerateImmediateDominatorTree(); scheduler.PrepareUses(); @@ -672,10 +674,11 @@ void Scheduler::ScheduleLate() { ScheduleLateNodeVisitor schedule_late_visitor(this); { - Zone zone(zone_->isolate()); + ZonePool::Scope zone_scope(zone_pool_); + Zone* zone = zone_scope.zone(); GenericGraphVisit::Visit >( - graph_, &zone, schedule_root_nodes_.begin(), schedule_root_nodes_.end(), + graph_, zone, schedule_root_nodes_.begin(), schedule_root_nodes_.end(), &schedule_late_visitor); } @@ -999,9 +1002,10 @@ static void VerifySpecialRPO(int num_loops, LoopInfo* loops, // 2. All loops are contiguous in the order (i.e. no intervening blocks that // do not belong to the loop.) // Note a simple RPO traversal satisfies (1) but not (3). -BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) { - Zone tmp_zone(schedule->zone()->isolate()); - Zone* zone = &tmp_zone; +BasicBlockVector* Scheduler::ComputeSpecialRPO(ZonePool* zone_pool, + Schedule* schedule) { + ZonePool::Scope zone_scope(zone_pool); + Zone* zone = zone_scope.zone(); Trace("--- COMPUTING SPECIAL RPO ----------------------------------\n"); // RPO should not have been computed for this schedule yet. CHECK_EQ(kBlockUnvisited1, schedule->start()->rpo_number()); diff --git a/src/compiler/scheduler.h b/src/compiler/scheduler.h index a520712..246bdae 100644 --- a/src/compiler/scheduler.h +++ b/src/compiler/scheduler.h @@ -9,6 +9,7 @@ #include "src/compiler/opcodes.h" #include "src/compiler/schedule.h" +#include "src/compiler/zone-pool.h" #include "src/zone-containers.h" namespace v8 { @@ -21,10 +22,11 @@ class Scheduler { public: // The complete scheduling algorithm. Creates a new schedule and places all // nodes from the graph into it. - static Schedule* ComputeSchedule(Graph* graph); + static Schedule* ComputeSchedule(ZonePool* zone_pool, Graph* graph); // Compute the RPO of blocks in an existing schedule. - static BasicBlockVector* ComputeSpecialRPO(Schedule* schedule); + static BasicBlockVector* ComputeSpecialRPO(ZonePool* zone_pool, + Schedule* schedule); private: enum Placement { kUnknown, kSchedulable, kFixed }; @@ -40,6 +42,7 @@ class Scheduler { // or not yet known. }; + ZonePool* zone_pool_; Zone* zone_; Graph* graph_; Schedule* schedule_; @@ -48,7 +51,7 @@ class Scheduler { ZoneVector node_data_; bool has_floating_control_; - Scheduler(Zone* zone, Graph* graph, Schedule* schedule); + Scheduler(ZonePool* zone_pool, Zone* zone, Graph* graph, Schedule* schedule); SchedulerData DefaultSchedulerData(); diff --git a/src/compiler/zone-pool.cc b/src/compiler/zone-pool.cc new file mode 100644 index 0000000..8276023 --- /dev/null +++ b/src/compiler/zone-pool.cc @@ -0,0 +1,133 @@ +// Copyright 2014 the V8 project 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 "src/compiler/zone-pool.h" + +namespace v8 { +namespace internal { +namespace compiler { + +ZonePool::StatsScope::StatsScope(ZonePool* zone_pool) + : zone_pool_(zone_pool), max_allocated_bytes_(0) { + zone_pool_->stats_.push_back(this); + for (auto zone : zone_pool_->used_) { + size_t size = static_cast(zone->allocation_size()); + std::pair res = + initial_values_.insert(std::make_pair(zone, size)); + USE(res); + DCHECK(res.second); + } +} + + +ZonePool::StatsScope::~StatsScope() { + DCHECK_EQ(zone_pool_->stats_.back(), this); + zone_pool_->stats_.pop_back(); +} + + +size_t ZonePool::StatsScope::GetMaxAllocatedBytes() { + return std::max(max_allocated_bytes_, GetCurrentAllocatedBytes()); +} + + +size_t ZonePool::StatsScope::GetCurrentAllocatedBytes() { + size_t total = 0; + for (Zone* zone : zone_pool_->used_) { + total += static_cast(zone->allocation_size()); + // Adjust for initial values. + InitialValues::iterator it = initial_values_.find(zone); + if (it != initial_values_.end()) { + total -= it->second; + } + } + return total; +} + + +void ZonePool::StatsScope::ZoneReturned(Zone* zone) { + size_t current_total = GetCurrentAllocatedBytes(); + // Update max. + max_allocated_bytes_ = std::max(max_allocated_bytes_, current_total); + // Drop zone from initial value map. + InitialValues::iterator it = initial_values_.find(zone); + if (it != initial_values_.end()) { + initial_values_.erase(it); + } +} + + +ZonePool::ZonePool(Isolate* isolate) + : isolate_(isolate), max_allocated_bytes_(0), total_deleted_bytes_(0) {} + + +ZonePool::~ZonePool() { + DCHECK(used_.empty()); + DCHECK(stats_.empty()); + for (Zone* zone : unused_) { + delete zone; + } +} + + +size_t ZonePool::GetMaxAllocatedBytes() { + return std::max(max_allocated_bytes_, GetCurrentAllocatedBytes()); +} + + +size_t ZonePool::GetCurrentAllocatedBytes() { + size_t total = 0; + for (Zone* zone : used_) { + total += static_cast(zone->allocation_size()); + } + return total; +} + + +size_t ZonePool::GetTotalAllocatedBytes() { + return total_deleted_bytes_ + GetCurrentAllocatedBytes(); +} + + +Zone* ZonePool::NewEmptyZone() { + Zone* zone; + // Grab a zone from pool if possible. + if (!unused_.empty()) { + zone = unused_.back(); + unused_.pop_back(); + } else { + zone = new Zone(isolate_); + } + used_.push_back(zone); + DCHECK_EQ(0, zone->allocation_size()); + return zone; +} + + +void ZonePool::ReturnZone(Zone* zone) { + size_t current_total = GetCurrentAllocatedBytes(); + // Update max. + max_allocated_bytes_ = std::max(max_allocated_bytes_, current_total); + // Update stats. + for (auto stat_scope : stats_) { + stat_scope->ZoneReturned(zone); + } + // Remove from used. + Used::iterator it = std::find(used_.begin(), used_.end(), zone); + DCHECK(it != used_.end()); + used_.erase(it); + total_deleted_bytes_ += static_cast(zone->allocation_size()); + // Delete zone or clear and stash on unused_. + if (unused_.size() >= kMaxUnusedSize) { + delete zone; + } else { + zone->DeleteAll(); + DCHECK_EQ(0, zone->allocation_size()); + unused_.push_back(zone); + } +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/src/compiler/zone-pool.h b/src/compiler/zone-pool.h new file mode 100644 index 0000000..648ab5a --- /dev/null +++ b/src/compiler/zone-pool.h @@ -0,0 +1,91 @@ +// Copyright 2014 the V8 project 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 V8_COMPILER_ZONE_POOL_H_ +#define V8_COMPILER_ZONE_POOL_H_ + +#include +#include +#include + +#include "src/v8.h" + +namespace v8 { +namespace internal { +namespace compiler { + +class ZonePool FINAL { + public: + class Scope FINAL { + public: + explicit Scope(ZonePool* zone_pool) : zone_pool_(zone_pool), zone_(NULL) {} + ~Scope() { Destroy(); } + + Zone* zone() { + if (zone_ == NULL) zone_ = zone_pool_->NewEmptyZone(); + return zone_; + } + void Destroy() { + if (zone_ != NULL) zone_pool_->ReturnZone(zone_); + zone_ = NULL; + } + + private: + ZonePool* const zone_pool_; + Zone* zone_; + DISALLOW_COPY_AND_ASSIGN(Scope); + }; + + class StatsScope FINAL { + public: + explicit StatsScope(ZonePool* zone_pool); + ~StatsScope(); + + size_t GetMaxAllocatedBytes(); + size_t GetCurrentAllocatedBytes(); + + private: + friend class ZonePool; + void ZoneReturned(Zone* zone); + + typedef std::map InitialValues; + + ZonePool* const zone_pool_; + InitialValues initial_values_; + size_t max_allocated_bytes_; + + DISALLOW_COPY_AND_ASSIGN(StatsScope); + }; + + explicit ZonePool(Isolate* isolate); + ~ZonePool(); + + size_t GetMaxAllocatedBytes(); + size_t GetTotalAllocatedBytes(); + size_t GetCurrentAllocatedBytes(); + + private: + Zone* NewEmptyZone(); + void ReturnZone(Zone* zone); + + static const size_t kMaxUnusedSize = 3; + typedef std::vector Unused; + typedef std::vector Used; + typedef std::vector Stats; + + Isolate* const isolate_; + Unused unused_; + Used used_; + Stats stats_; + size_t max_allocated_bytes_; + size_t total_deleted_bytes_; + + DISALLOW_COPY_AND_ASSIGN(ZonePool); +}; + +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif diff --git a/src/zone.cc b/src/zone.cc index 48d8c7b..eb2e532 100644 --- a/src/zone.cc +++ b/src/zone.cc @@ -150,6 +150,7 @@ void Zone::DeleteAll() { position_ = limit_ = 0; } + allocation_size_ = 0; // Update the head segment to be the kept segment (if any). segment_head_ = keep; } diff --git a/test/cctest/compiler/test-instruction.cc b/test/cctest/compiler/test-instruction.cc index defd9b6..fc48ca2 100644 --- a/test/cctest/compiler/test-instruction.cc +++ b/test/cctest/compiler/test-instruction.cc @@ -51,7 +51,8 @@ class InstructionTester : public HandleAndZoneScope { void allocCode() { if (schedule.rpo_order()->size() == 0) { // Compute the RPO order. - Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(isolate); + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); DCHECK(schedule.rpo_order()->size() > 0); } code = new TestInstrSeq(main_zone(), &graph, &schedule); diff --git a/test/cctest/compiler/test-scheduler.cc b/test/cctest/compiler/test-scheduler.cc index f513112..2a3a1db 100644 --- a/test/cctest/compiler/test-scheduler.cc +++ b/test/cctest/compiler/test-scheduler.cc @@ -93,7 +93,8 @@ static Schedule* ComputeAndVerifySchedule(int expected, Graph* graph) { os << AsDOT(*graph); } - Schedule* schedule = Scheduler::ComputeSchedule(graph); + ZonePool zone_pool(graph->zone()->isolate()); + Schedule* schedule = Scheduler::ComputeSchedule(&zone_pool, graph); if (FLAG_trace_turbo_scheduler) { OFStream os(stdout); @@ -109,7 +110,8 @@ TEST(RPODegenerate1) { HandleAndZoneScope scope; Schedule schedule(scope.main_zone()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 1, false); CHECK_EQ(schedule.start(), order->at(0)); } @@ -120,7 +122,8 @@ TEST(RPODegenerate2) { Schedule schedule(scope.main_zone()); schedule.AddGoto(schedule.start(), schedule.end()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 2, false); CHECK_EQ(schedule.start(), order->at(0)); CHECK_EQ(schedule.end(), order->at(1)); @@ -139,7 +142,9 @@ TEST(RPOLine) { schedule.AddGoto(last, block); last = block; } - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 1 + i, false); for (size_t i = 0; i < schedule.BasicBlockCount(); i++) { @@ -156,7 +161,8 @@ TEST(RPOSelfLoop) { HandleAndZoneScope scope; Schedule schedule(scope.main_zone()); schedule.AddSuccessor(schedule.start(), schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 1, true); BasicBlock* loop[] = {schedule.start()}; CheckLoopContains(loop, 1); @@ -168,7 +174,8 @@ TEST(RPOEntryLoop) { Schedule schedule(scope.main_zone()); schedule.AddSuccessor(schedule.start(), schedule.end()); schedule.AddSuccessor(schedule.end(), schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 2, true); BasicBlock* loop[] = {schedule.start(), schedule.end()}; CheckLoopContains(loop, 2); @@ -180,7 +187,8 @@ TEST(RPOEndLoop) { Schedule schedule(scope.main_zone()); SmartPointer loop1(CreateLoop(&schedule, 2)); schedule.AddSuccessor(schedule.start(), loop1->header()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 3, true); CheckLoopContains(loop1->nodes, loop1->count); } @@ -192,7 +200,8 @@ TEST(RPOEndLoopNested) { SmartPointer loop1(CreateLoop(&schedule, 2)); schedule.AddSuccessor(schedule.start(), loop1->header()); schedule.AddSuccessor(loop1->last(), schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 3, true); CheckLoopContains(loop1->nodes, loop1->count); } @@ -212,7 +221,8 @@ TEST(RPODiamond) { schedule.AddSuccessor(B, D); schedule.AddSuccessor(C, D); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 4, false); CHECK_EQ(0, A->rpo_number()); @@ -236,7 +246,8 @@ TEST(RPOLoop1) { schedule.AddSuccessor(C, B); schedule.AddSuccessor(C, D); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 4, true); BasicBlock* loop[] = {B, C}; CheckLoopContains(loop, 2); @@ -257,7 +268,8 @@ TEST(RPOLoop2) { schedule.AddSuccessor(C, B); schedule.AddSuccessor(B, D); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 4, true); BasicBlock* loop[] = {B, C}; CheckLoopContains(loop, 2); @@ -299,7 +311,9 @@ TEST(RPOLoopN) { if (i == 9) schedule.AddSuccessor(E, G); if (i == 10) schedule.AddSuccessor(F, G); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 7, true); BasicBlock* loop[] = {B, C, D, E, F}; CheckLoopContains(loop, 5); @@ -326,7 +340,8 @@ TEST(RPOLoopNest1) { schedule.AddSuccessor(E, B); schedule.AddSuccessor(E, F); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 6, true); BasicBlock* loop1[] = {B, C, D, E}; CheckLoopContains(loop1, 4); @@ -361,7 +376,8 @@ TEST(RPOLoopNest2) { schedule.AddSuccessor(F, C); schedule.AddSuccessor(G, B); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 8, true); BasicBlock* loop1[] = {B, C, D, E, F, G}; CheckLoopContains(loop1, 6); @@ -388,7 +404,8 @@ TEST(RPOLoopFollow1) { schedule.AddSuccessor(loop1->header(), loop2->header()); schedule.AddSuccessor(loop2->last(), E); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckLoopContains(loop1->nodes, loop1->count); @@ -415,7 +432,8 @@ TEST(RPOLoopFollow2) { schedule.AddSuccessor(S, loop2->header()); schedule.AddSuccessor(loop2->last(), E); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckLoopContains(loop1->nodes, loop1->count); @@ -440,7 +458,9 @@ TEST(RPOLoopFollowN) { schedule.AddSuccessor(A, loop1->header()); schedule.AddSuccessor(loop1->nodes[exit], loop2->header()); schedule.AddSuccessor(loop2->nodes[exit], E); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckLoopContains(loop1->nodes, loop1->count); CHECK_EQ(static_cast(schedule.BasicBlockCount()), @@ -471,7 +491,8 @@ TEST(RPONestedLoopFollow1) { schedule.AddSuccessor(C, E); schedule.AddSuccessor(C, B); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckLoopContains(loop1->nodes, loop1->count); @@ -502,7 +523,9 @@ TEST(RPOLoopBackedges1) { schedule.AddSuccessor(loop1->nodes[i], loop1->header()); schedule.AddSuccessor(loop1->nodes[j], E); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); CheckLoopContains(loop1->nodes, loop1->count); } @@ -529,7 +552,9 @@ TEST(RPOLoopOutedges1) { schedule.AddSuccessor(loop1->nodes[j], D); schedule.AddSuccessor(D, E); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); CheckLoopContains(loop1->nodes, loop1->count); } @@ -556,7 +581,9 @@ TEST(RPOLoopOutedges2) { schedule.AddSuccessor(O, E); } - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); CheckLoopContains(loop1->nodes, loop1->count); } @@ -582,7 +609,9 @@ TEST(RPOLoopOutloops1) { schedule.AddSuccessor(loopN[j]->last(), E); } - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = + Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); CheckLoopContains(loop1->nodes, loop1->count); @@ -613,7 +642,8 @@ TEST(RPOLoopMultibackedge) { schedule.AddSuccessor(D, B); schedule.AddSuccessor(E, B); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + ZonePool zone_pool(scope.main_isolate()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&zone_pool, &schedule); CheckRPONumbers(order, 5, true); BasicBlock* loop1[] = {B, C, D, E}; @@ -628,7 +658,8 @@ TEST(BuildScheduleEmpty) { graph.SetStart(graph.NewNode(builder.Start(0))); graph.SetEnd(graph.NewNode(builder.End(), graph.start())); - USE(Scheduler::ComputeSchedule(&graph)); + ZonePool zone_pool(scope.main_isolate()); + USE(Scheduler::ComputeSchedule(&zone_pool, &graph)); } @@ -643,7 +674,8 @@ TEST(BuildScheduleOneParameter) { graph.SetEnd(graph.NewNode(builder.End(), ret)); - USE(Scheduler::ComputeSchedule(&graph)); + ZonePool zone_pool(scope.main_isolate()); + USE(Scheduler::ComputeSchedule(&zone_pool, &graph)); } diff --git a/test/unittests/compiler/zone-pool-unittest.cc b/test/unittests/compiler/zone-pool-unittest.cc new file mode 100644 index 0000000..5bc0bbd --- /dev/null +++ b/test/unittests/compiler/zone-pool-unittest.cc @@ -0,0 +1,157 @@ +// Copyright 2014 the V8 project 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 "src/base/utils/random-number-generator.h" +#include "src/compiler/zone-pool.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace compiler { + +class ZonePoolTest : public TestWithIsolate { + public: + ZonePoolTest() : zone_pool_(isolate()) {} + + protected: + ZonePool* zone_pool() { return &zone_pool_; } + + void ExpectForPool(size_t current, size_t max, size_t total) { + ASSERT_EQ(current, zone_pool()->GetCurrentAllocatedBytes()); + ASSERT_EQ(max, zone_pool()->GetMaxAllocatedBytes()); + ASSERT_EQ(total, zone_pool()->GetTotalAllocatedBytes()); + } + + void Expect(ZonePool::StatsScope* stats, size_t current, size_t max) { + ASSERT_EQ(current, stats->GetCurrentAllocatedBytes()); + ASSERT_EQ(max, stats->GetMaxAllocatedBytes()); + } + + size_t Allocate(Zone* zone) { + size_t bytes = rng.NextInt(25) + 7; + int size_before = zone->allocation_size(); + zone->New(static_cast(bytes)); + return static_cast(zone->allocation_size() - size_before); + } + + private: + ZonePool zone_pool_; + base::RandomNumberGenerator rng; +}; + + +TEST_F(ZonePoolTest, Empty) { + ExpectForPool(0, 0, 0); + { + ZonePool::StatsScope stats(zone_pool()); + Expect(&stats, 0, 0); + } + ExpectForPool(0, 0, 0); + { + ZonePool::Scope scope(zone_pool()); + scope.zone(); + } + ExpectForPool(0, 0, 0); +} + + +TEST_F(ZonePoolTest, MultipleZonesWithDeletion) { + static const size_t kArraySize = 10; + + ZonePool::Scope* scopes[kArraySize]; + + // Initialize. + size_t before_stats = 0; + for (size_t i = 0; i < kArraySize; ++i) { + scopes[i] = new ZonePool::Scope(zone_pool()); + before_stats += Allocate(scopes[i]->zone()); // Add some stuff. + } + + ExpectForPool(before_stats, before_stats, before_stats); + + ZonePool::StatsScope stats(zone_pool()); + + size_t before_deletion = 0; + for (size_t i = 0; i < kArraySize; ++i) { + before_deletion += Allocate(scopes[i]->zone()); // Add some stuff. + } + + Expect(&stats, before_deletion, before_deletion); + ExpectForPool(before_stats + before_deletion, before_stats + before_deletion, + before_stats + before_deletion); + + // Delete the scopes and create new ones. + for (size_t i = 0; i < kArraySize; ++i) { + delete scopes[i]; + scopes[i] = new ZonePool::Scope(zone_pool()); + } + + Expect(&stats, 0, before_deletion); + ExpectForPool(0, before_stats + before_deletion, + before_stats + before_deletion); + + size_t after_deletion = 0; + for (size_t i = 0; i < kArraySize; ++i) { + after_deletion += Allocate(scopes[i]->zone()); // Add some stuff. + } + + Expect(&stats, after_deletion, std::max(after_deletion, before_deletion)); + ExpectForPool(after_deletion, + std::max(after_deletion, before_stats + before_deletion), + before_stats + before_deletion + after_deletion); + + // Cleanup. + for (size_t i = 0; i < kArraySize; ++i) { + delete scopes[i]; + } + + Expect(&stats, 0, std::max(after_deletion, before_deletion)); + ExpectForPool(0, std::max(after_deletion, before_stats + before_deletion), + before_stats + before_deletion + after_deletion); +} + + +TEST_F(ZonePoolTest, SimpleAllocationLoop) { + int runs = 20; + size_t total_allocated = 0; + size_t max_loop_allocation = 0; + ZonePool::StatsScope outer_stats(zone_pool()); + { + ZonePool::Scope outer_scope(zone_pool()); + size_t outer_allocated = 0; + for (int i = 0; i < runs; ++i) { + { + size_t bytes = Allocate(outer_scope.zone()); + outer_allocated += bytes; + total_allocated += bytes; + } + ZonePool::StatsScope inner_stats(zone_pool()); + size_t allocated = 0; + { + ZonePool::Scope inner_scope(zone_pool()); + for (int j = 0; j < 20; ++j) { + size_t bytes = Allocate(inner_scope.zone()); + allocated += bytes; + total_allocated += bytes; + max_loop_allocation = + std::max(max_loop_allocation, outer_allocated + allocated); + Expect(&inner_stats, allocated, allocated); + Expect(&outer_stats, outer_allocated + allocated, + max_loop_allocation); + ExpectForPool(outer_allocated + allocated, max_loop_allocation, + total_allocated); + } + } + Expect(&inner_stats, 0, allocated); + Expect(&outer_stats, outer_allocated, max_loop_allocation); + ExpectForPool(outer_allocated, max_loop_allocation, total_allocated); + } + } + Expect(&outer_stats, 0, max_loop_allocation); + ExpectForPool(0, max_loop_allocation, total_allocated); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/test/unittests/unittests.gyp b/test/unittests/unittests.gyp index 6361540..5253746 100644 --- a/test/unittests/unittests.gyp +++ b/test/unittests/unittests.gyp @@ -54,6 +54,7 @@ 'compiler/simplified-operator-reducer-unittest.cc', 'compiler/simplified-operator-unittest.cc', 'compiler/value-numbering-reducer-unittest.cc', + 'compiler/zone-pool-unittest.cc', 'libplatform/default-platform-unittest.cc', 'libplatform/task-queue-unittest.cc', 'libplatform/worker-thread-unittest.cc', diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 57296e7..e62ad07 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -496,6 +496,8 @@ '../../src/compiler/value-numbering-reducer.h', '../../src/compiler/verifier.cc', '../../src/compiler/verifier.h', + '../../src/compiler/zone-pool.cc', + '../../src/compiler/zone-pool.h', '../../src/compiler.cc', '../../src/compiler.h', '../../src/contexts.cc',