TEST(Region, all) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; RegionDB region_db; region_db.add_region(0,".nothing_bc", 0); region_db.add_region(1,"nothing_bulk", 0); { Region r=region_db.add_region(1001,".top", 2); EXPECT_EQ(2, r.idx() ); EXPECT_TRUE( r.is_boundary() ); EXPECT_EQ(1, r.boundary_idx() ); EXPECT_TRUE( r.is_valid() ); EXPECT_EQ(1001, r.id()); EXPECT_EQ(".top", r.label()); EXPECT_EQ(2, r.dim()); EXPECT_EQ(2, region_db.add_region(1001,".top", 2).idx() ); // try to convert Region to RegionIdx RegionIdx r_idx = r; EXPECT_EQ(2, r_idx.idx()); } { Region r=region_db.add_region(1002,"inside 1", 3); EXPECT_EQ(3, r.idx() ); EXPECT_EQ(1, r.bulk_idx() ); EXPECT_EQ("inside 1", r.label() ); EXPECT_EQ(1002, r.id() ); EXPECT_EQ(3, r.dim()); } { Region a=region_db.find_label(".top"); Region b=region_db.find_id(1001); EXPECT_EQ(a,b); Region c=region_db.find_id(1002); EXPECT_TRUE(a!=c); EXPECT_FALSE( region_db.find_id(1007).is_valid() ); } { Region r=region_db.add_region(1003, region_db.create_label_from_id(1003), 3); EXPECT_EQ(5, r.idx() ); EXPECT_EQ(2, r.bulk_idx() ); EXPECT_EQ("region_1003", r.label() ); } { Region r=region_db.add_region(1004,".bottom", 2); EXPECT_EQ(4, r.idx() ); EXPECT_EQ(2, r.boundary_idx() ); EXPECT_EQ(".bottom", r.label() ); EXPECT_EQ(1004, r.id() ); } region_db.add_region(1005,".side", 2); //EXPECT_THROW( region_db.add_region(1005,"new", 3, false) , RegionDB::ExcInconsistentAdd); EXPECT_THROW( region_db.add_region(1001,".bottom", 2) , RegionDB::ExcNonuniqueID); EXPECT_THROW( region_db.add_region(1101,".top", 2) , RegionDB::ExcNonuniqueLabel); EXPECT_THROW( region_db.add_region(1001,".top", 3) , RegionDB::ExcNonuniqueLabel); //EXPECT_THROW( region_db.add_region(1001,"top", 2) , RegionDB::ExcNonuniqueLabel); region_db.close(); // close should be called automatically at first call to any size method. EXPECT_EQ(8, region_db.size()); EXPECT_EQ(4, region_db.boundary_size()); EXPECT_EQ(3, region_db.bulk_size()); RegionSet bulk = region_db.get_region_set("BULK"); EXPECT_EQ(3,bulk.size()); EXPECT_EQ(1, bulk[0].id()); EXPECT_EQ(1002, bulk[1].id()); EXPECT_EQ(1003, bulk[2].id()); EXPECT_THROW_WHAT( { region_db.add_region(1006,".side_", 2);}, RegionDB::ExcAddingIntoClosed, "Can not add label='.side_'");
/** * Sorts the regions vector in a linear order to be used for * translation. The goal is to obtain an order that improves locality * when the function is executed. */ static void sortRegion(RegionVec& regions, const Func* func, const TransCFG& cfg, const ProfData* profData, const TransIDToRegionMap& headToRegion, const RegionToTransIDsMap& regionToTransIds) { RegionVec sorted; RegionSet selected; if (regions.size() == 0) return; // First, pick the region starting at the lowest bytecode offset. // This will normally correspond to the main function entry (for // normal, regular bytecode), but it may not be for irregular // functions written in hhas (like array_map and array_filter). If // there multiple regions starting at the lowest bytecode offset, // pick the one with the largest profile weight. RegionDescPtr entryRegion = nullptr; int64_t maxEntryWeight = -1; Offset lowestOffset = kInvalidOffset; for (const auto& pair : regionToTransIds) { auto r = pair.first; auto& tids = pair.second; TransID firstTid = tids[0]; Offset firstOffset = profData->transSrcKey(firstTid).offset(); int64_t weight = cfg.weight(firstTid); if (lowestOffset == kInvalidOffset || firstOffset < lowestOffset || (firstOffset == lowestOffset && weight > maxEntryWeight)) { entryRegion = r; maxEntryWeight = weight; lowestOffset = firstOffset; } } assert(entryRegion); sorted.push_back(entryRegion); selected.insert(entryRegion); RegionDescPtr region = entryRegion; // Select the remaining regions, iteratively picking the most likely // region to execute next. for (auto i = 1; i < regions.size(); i++) { int64_t maxWeight = -1; int64_t maxHeadWeight = -1; RegionDescPtr bestNext = nullptr; auto regionTransIds = getRegionTransIDVec(regionToTransIds, region); for (auto next : regions) { if (selected.count(next)) continue; auto nextTransIds = getRegionTransIDVec(regionToTransIds, next); int64_t weight = interRegionWeight(regionTransIds, nextTransIds[0], cfg); int64_t headWeight = cfg.weight(nextTransIds[0]); if ((weight > maxWeight) || (weight == maxWeight && headWeight > maxHeadWeight)) { maxWeight = weight; maxHeadWeight = headWeight; bestNext = next; } } assert(bestNext); sorted.push_back(bestNext); selected.insert(bestNext); region = bestNext; } assert(sorted.size() == regions.size()); regions = sorted; if (debug && Trace::moduleEnabled(HPHP::Trace::pgo, 5)) { for (size_t i = 0; i < regions.size(); i++) { auto r = regions[i]; auto tids = getRegionTransIDVec(regionToTransIds, r); std::string transIds = folly::join(", ", tids); FTRACE(6, "sortRegion: region[{}]: {}\n", i, transIds); } } }
/** * Sorts the regions vector in a linear order to be used for * translation. The goal is to obtain an order that improves locality * when the function is executed. */ static void sortRegion(RegionVec& regions, const Func* func, const TransCFG& cfg, const ProfData* profData, const TransIDToRegionMap& headToRegion, const RegionToTransIDsMap& regionToTransIds) { RegionVec sorted; RegionSet selected; // First, pick the region for the function body entry. There may be // multiple translations of the function body, so pick the one with // largest profile weight. RegionDescPtr entryRegion = nullptr; int64_t maxEntryWeight = -1; for (const auto& pair : regionToTransIds) { auto r = pair.first; auto& tids = pair.second; for (auto tid : tids) { if (profData->transSrcKey(tid).offset() == func->base()) { int64_t weight = cfg.weight(tid); if (weight > maxEntryWeight) { entryRegion = r; maxEntryWeight = weight; } } } } assert(entryRegion); sorted.push_back(entryRegion); selected.insert(entryRegion); RegionDescPtr region = entryRegion; // Select the remaining regions, iteratively picking the most likely // region to execute next. for (auto i = 1; i < regions.size(); i++) { int64_t maxWeight = -1; int64_t maxHeadWeight = -1; RegionDescPtr bestNext = nullptr; auto regionTransIds = getRegionTransIDVec(regionToTransIds, region); for (auto next : regions) { if (setContains(selected, next)) continue; auto nextTransIds = getRegionTransIDVec(regionToTransIds, next); int64_t weight = interRegionWeight(regionTransIds, nextTransIds[0], cfg); int64_t headWeight = cfg.weight(nextTransIds[0]); if ((weight > maxWeight) || (weight == maxWeight && headWeight > maxHeadWeight)) { maxWeight = weight; maxHeadWeight = headWeight; bestNext = next; } } assert(bestNext); sorted.push_back(bestNext); selected.insert(bestNext); region = bestNext; } assert(sorted.size() == regions.size()); regions = sorted; if (debug && Trace::moduleEnabled(HPHP::Trace::pgo, 5)) { for (size_t i = 0; i < regions.size(); i++) { auto r = regions[i]; auto tids = getRegionTransIDVec(regionToTransIds, r); std::string transIds = folly::join(", ", tids); FTRACE(6, "sortRegion: region[{}]: {}\n", i, transIds); } } }