diff options
| author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-05-16 12:30:30 -0400 |
|---|---|---|
| committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-05-16 12:30:30 -0400 |
| commit | dd7f66806e66d9637b070841c2a7c914671db969 (patch) | |
| tree | 2310a6036edfab0398fb765db6b88dbf50aea8d9 /native/src/sharedres.cpp | |
| parent | 546b17c0f6360f4e83e6f0dda8db99656aa94077 (diff) | |
C++: Break out the FMLP+ code into own file
Part of refactoring sharedres.cpp.
Diffstat (limited to 'native/src/sharedres.cpp')
| -rw-r--r-- | native/src/sharedres.cpp | 373 |
1 files changed, 19 insertions, 354 deletions
diff --git a/native/src/sharedres.cpp b/native/src/sharedres.cpp index a3b4ed9..259e5a7 100644 --- a/native/src/sharedres.cpp +++ b/native/src/sharedres.cpp | |||
| @@ -128,32 +128,7 @@ void split_by_resource(const ResourceSharingInfo& info, Resources& resources) | |||
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | static void all_from_cluster(const Cluster& cluster, ContentionSet& cs) | 131 | void split_by_resource(const Cluster& cluster, Resources& resources) |
| 132 | { | ||
| 133 | foreach(cluster, it) | ||
| 134 | { | ||
| 135 | const TaskInfo* tsk = *it; | ||
| 136 | |||
| 137 | foreach(tsk->get_requests(), jt) | ||
| 138 | { | ||
| 139 | const RequestBound& req = *jt; | ||
| 140 | cs.push_back(&req); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | static void all_per_cluster(const Clusters& clusters, | ||
| 146 | AllPerCluster& all) | ||
| 147 | { | ||
| 148 | foreach(clusters, it) | ||
| 149 | { | ||
| 150 | all.push_back(ContentionSet()); | ||
| 151 | all_from_cluster(*it, all.back()); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | |||
| 156 | static void split_by_resource(const Cluster& cluster, Resources& resources) | ||
| 157 | { | 132 | { |
| 158 | 133 | ||
| 159 | foreach(cluster, it) | 134 | foreach(cluster, it) |
| @@ -173,8 +148,8 @@ static void split_by_resource(const Cluster& cluster, Resources& resources) | |||
| 173 | } | 148 | } |
| 174 | } | 149 | } |
| 175 | 150 | ||
| 176 | static void split_by_resource(const Clusters& clusters, | 151 | void split_by_resource(const Clusters& clusters, |
| 177 | ClusterResources& resources) | 152 | ClusterResources& resources) |
| 178 | { | 153 | { |
| 179 | foreach(clusters, it) | 154 | foreach(clusters, it) |
| 180 | { | 155 | { |
| @@ -258,45 +233,19 @@ void sort_by_request_length(ClusterResources& resources) | |||
| 258 | apply_foreach(resources, sort_by_request_length); | 233 | apply_foreach(resources, sort_by_request_length); |
| 259 | } | 234 | } |
| 260 | 235 | ||
| 261 | typedef std::vector<ContentionSet> TaskContention; | ||
| 262 | typedef std::vector<TaskContention> ClusterContention; | 236 | typedef std::vector<TaskContention> ClusterContention; |
| 263 | 237 | ||
| 264 | // have one contention set per task | 238 | typedef std::vector<ContentionSet> TaskContention; |
| 265 | static void derive_task_contention(const Cluster& cluster, | ||
| 266 | TaskContention& requests) | ||
| 267 | { | ||
| 268 | requests.reserve(cluster.size()); | ||
| 269 | |||
| 270 | foreach(cluster, it) | ||
| 271 | { | ||
| 272 | const TaskInfo* tsk = *it; | ||
| 273 | |||
| 274 | requests.push_back(ContentionSet()); | ||
| 275 | |||
| 276 | foreach(tsk->get_requests(), jt) | ||
| 277 | { | ||
| 278 | const RequestBound& req = *jt; | ||
| 279 | |||
| 280 | requests.back().push_back(&req); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | static void derive_task_contention(const Clusters& clusters, | ||
| 286 | ClusterContention& contention) | ||
| 287 | { | ||
| 288 | map_ref(clusters, contention, TaskContention, derive_task_contention); | ||
| 289 | } | ||
| 290 | 239 | ||
| 291 | static Interference bound_blocking(const ContentionSet& cont, | 240 | Interference bound_blocking(const ContentionSet& cont, |
| 292 | unsigned long interval, | 241 | unsigned long interval, |
| 293 | unsigned int max_total_requests, | 242 | unsigned int max_total_requests, |
| 294 | unsigned int max_requests_per_source, | 243 | unsigned int max_requests_per_source, |
| 295 | const TaskInfo* exclude_tsk, | 244 | const TaskInfo* exclude_tsk, |
| 296 | // Note: the following parameter excludes | 245 | // Note: the following parameter excludes |
| 297 | // *high-priority* tasks. Used to exclude local higher-priority tasks. | 246 | // *high-priority* tasks. Used to exclude local higher-priority tasks. |
| 298 | // Default: all tasks can block (suitable for remote blocking). | 247 | // Default: all tasks can block (suitable for remote blocking). |
| 299 | unsigned int min_priority = 0) | 248 | unsigned int min_priority /* default == 0 */) |
| 300 | { | 249 | { |
| 301 | Interference inter; | 250 | Interference inter; |
| 302 | unsigned int remaining; | 251 | unsigned int remaining; |
| @@ -370,12 +319,12 @@ static void add_blocking(LimitedContentionSet &lcs, | |||
| 370 | } | 319 | } |
| 371 | } | 320 | } |
| 372 | 321 | ||
| 373 | static Interference bound_blocking(const ContentionSet& cont, | 322 | Interference bound_blocking(const ContentionSet& cont, |
| 374 | unsigned long interval, | 323 | unsigned long interval, |
| 375 | unsigned int max_total_requests, | 324 | unsigned int max_total_requests, |
| 376 | unsigned int max_requests_per_source, | 325 | unsigned int max_requests_per_source, |
| 377 | bool exclude_whole_cluster, | 326 | bool exclude_whole_cluster, |
| 378 | const TaskInfo* exclude_tsk) | 327 | const TaskInfo* exclude_tsk) |
| 379 | { | 328 | { |
| 380 | Interference inter; | 329 | Interference inter; |
| 381 | unsigned int remaining; | 330 | unsigned int remaining; |
| @@ -1434,287 +1383,3 @@ BlockingBounds* task_fair_rw_bounds(const ResourceSharingInfo& info, | |||
| 1434 | } | 1383 | } |
| 1435 | 1384 | ||
| 1436 | 1385 | ||
| 1437 | /* this analysis corresponds to the FMLP+ in the dissertation */ | ||
| 1438 | |||
| 1439 | static void pfmlp_count_direct_blocking(const TaskInfo* tsk, | ||
| 1440 | const ClusterResources& resources, | ||
| 1441 | std::vector<Interference>& counts) | ||
| 1442 | { | ||
| 1443 | unsigned int interval = tsk->get_response(); | ||
| 1444 | |||
| 1445 | |||
| 1446 | // for each resource requested by tsk | ||
| 1447 | foreach(tsk->get_requests(), jt) | ||
| 1448 | { | ||
| 1449 | const RequestBound& req = *jt; | ||
| 1450 | unsigned long issued = req.get_num_requests(); | ||
| 1451 | unsigned int res_id = req.get_resource_id(); | ||
| 1452 | |||
| 1453 | unsigned int i; | ||
| 1454 | |||
| 1455 | // for each cluster | ||
| 1456 | for (i = 0; i < resources.size(); i++) | ||
| 1457 | { | ||
| 1458 | // count interference... direct blocking will be counted later | ||
| 1459 | // make sure that cluster acceses res_id at all | ||
| 1460 | if (resources[i].size() > res_id) | ||
| 1461 | // yes it does---how often can it block? | ||
| 1462 | counts[i] += bound_blocking(resources[i][res_id], | ||
| 1463 | interval, | ||
| 1464 | UNLIMITED, // no total limit | ||
| 1465 | issued, // once per request | ||
| 1466 | tsk); | ||
| 1467 | } | ||
| 1468 | } | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | typedef std::vector<unsigned int> AccessCounts; | ||
| 1472 | typedef std::vector<AccessCounts> PerClusterAccessCounts; | ||
| 1473 | |||
| 1474 | // How many times does a task issue requests that can | ||
| 1475 | // conflict with tasks in a remote cluster. Indexed by cluster id. | ||
| 1476 | typedef std::vector<unsigned int> IssuedRequests; | ||
| 1477 | // Issued requests for each task. Indexed by task id. | ||
| 1478 | typedef std::vector<IssuedRequests> PerTaskIssuedCounts; | ||
| 1479 | |||
| 1480 | static void derive_access_counts(const ContentionSet &cluster_contention, | ||
| 1481 | AccessCounts &counts) | ||
| 1482 | { | ||
| 1483 | foreach(cluster_contention, it) | ||
| 1484 | { | ||
| 1485 | const RequestBound *req = *it; | ||
| 1486 | unsigned int res_id = req->get_resource_id(); | ||
| 1487 | |||
| 1488 | while (counts.size() <= res_id) | ||
| 1489 | counts.push_back(0); | ||
| 1490 | |||
| 1491 | counts[res_id] += req->get_num_requests(); | ||
| 1492 | } | ||
| 1493 | } | ||
| 1494 | |||
| 1495 | static void count_accesses_for_task(const TaskInfo& tsk, | ||
| 1496 | const PerClusterAccessCounts& acc_counts, | ||
| 1497 | IssuedRequests& ireqs) | ||
| 1498 | { | ||
| 1499 | foreach(acc_counts, it) | ||
| 1500 | { | ||
| 1501 | const AccessCounts &ac = *it; | ||
| 1502 | unsigned int count = 0; | ||
| 1503 | |||
| 1504 | // Check for each request of the task to see | ||
| 1505 | // if it conflicts with the cluster. | ||
| 1506 | foreach(tsk.get_requests(), jt) | ||
| 1507 | { | ||
| 1508 | const RequestBound &req = *jt; | ||
| 1509 | unsigned int res_id = req.get_resource_id(); | ||
| 1510 | if (ac.size() > res_id && ac[res_id] > 0) | ||
| 1511 | { | ||
| 1512 | // cluster acceses res_id as well | ||
| 1513 | count += req.get_num_requests(); | ||
| 1514 | } | ||
| 1515 | } | ||
| 1516 | ireqs.push_back(count); | ||
| 1517 | } | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | static void derive_access_counts(const AllPerCluster &per_cluster, | ||
| 1521 | const ResourceSharingInfo &info, | ||
| 1522 | PerTaskIssuedCounts &issued_reqs) | ||
| 1523 | { | ||
| 1524 | PerClusterAccessCounts counts; | ||
| 1525 | |||
| 1526 | /* which resources are accessed by each cluster? */ | ||
| 1527 | map_ref(per_cluster, counts, AccessCounts, derive_access_counts); | ||
| 1528 | |||
| 1529 | issued_reqs.reserve(info.get_tasks().size()); | ||
| 1530 | |||
| 1531 | foreach(info.get_tasks(), it) | ||
| 1532 | { | ||
| 1533 | issued_reqs.push_back(IssuedRequests()); | ||
| 1534 | count_accesses_for_task(*it, counts, issued_reqs.back()); | ||
| 1535 | } | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | static Interference pfmlp_bound_remote_blocking(const TaskInfo* tsk, | ||
| 1539 | const IssuedRequests &icounts, | ||
| 1540 | const std::vector<Interference>& counts, | ||
| 1541 | const ClusterContention& contention) | ||
| 1542 | { | ||
| 1543 | unsigned int i; | ||
| 1544 | |||
| 1545 | unsigned long interval = tsk->get_response(); | ||
| 1546 | Interference blocking; | ||
| 1547 | |||
| 1548 | // for each cluster | ||
| 1549 | for (i = 0; i < contention.size(); i++) | ||
| 1550 | { | ||
| 1551 | // Each task can either directly or indirectly block tsk | ||
| 1552 | // each time that tsk is directly blocked, but no more than | ||
| 1553 | // once per request issued by tsk. | ||
| 1554 | unsigned int max_per_task = std::min(counts[i].count, icounts[i]); | ||
| 1555 | |||
| 1556 | // skip local cluster and independent clusters | ||
| 1557 | if (i == tsk->get_cluster() || !max_per_task) | ||
| 1558 | continue; | ||
| 1559 | |||
| 1560 | Interference b; | ||
| 1561 | |||
| 1562 | // for each task in cluster | ||
| 1563 | foreach(contention[i], it) | ||
| 1564 | { | ||
| 1565 | |||
| 1566 | // count longest critical sections | ||
| 1567 | b += bound_blocking(*it, | ||
| 1568 | interval, | ||
| 1569 | max_per_task, | ||
| 1570 | UNLIMITED, // no limit per source | ||
| 1571 | tsk); | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | blocking += b; | ||
| 1575 | } | ||
| 1576 | return blocking; | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | static Interference pfmlp_bound_np_blocking(const TaskInfo* tsk, | ||
| 1580 | const std::vector<Interference>& counts, | ||
| 1581 | const AllPerCluster& per_cluster) | ||
| 1582 | { | ||
| 1583 | unsigned int i; | ||
| 1584 | |||
| 1585 | unsigned long interval = tsk->get_response(); | ||
| 1586 | Interference blocking; | ||
| 1587 | |||
| 1588 | // for each cluster | ||
| 1589 | for (i = 0; i < per_cluster.size(); i++) | ||
| 1590 | { | ||
| 1591 | // skip local cluster, this is only remote | ||
| 1592 | if (i == tsk->get_cluster()) | ||
| 1593 | continue; | ||
| 1594 | |||
| 1595 | // could be the same task each time tsk is directly blocked | ||
| 1596 | unsigned int max_direct = counts[i].count; | ||
| 1597 | Interference b; | ||
| 1598 | |||
| 1599 | // count longest critical sections | ||
| 1600 | b += bound_blocking(per_cluster[i], | ||
| 1601 | interval, | ||
| 1602 | max_direct, | ||
| 1603 | max_direct, | ||
| 1604 | tsk); | ||
| 1605 | blocking += b; | ||
| 1606 | } | ||
| 1607 | return blocking; | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | static Interference pfmlp_bound_local_blocking(const TaskInfo* tsk, | ||
| 1611 | const std::vector<Interference>& counts, | ||
| 1612 | const ClusterContention& contention) | ||
| 1613 | { | ||
| 1614 | // Locally, we have to account two things. | ||
| 1615 | // 1) Direct blocking from lower-priority tasks. | ||
| 1616 | // 2) Boost blocking from lower-priority tasks. | ||
| 1617 | // (Higher-priority requests are not counted as blocking.) | ||
| 1618 | // Since lower-priority jobs are boosted while | ||
| 1619 | // they directly block, 1) is subsumed by 2). | ||
| 1620 | // Lower-priority tasks cannot issue requests while a higher-priority | ||
| 1621 | // job executes. Therefore, at most one blocking request | ||
| 1622 | // is issued prior to the release of the job under analysis, | ||
| 1623 | // and one prior to each time that the job under analysis resumes. | ||
| 1624 | |||
| 1625 | Interference blocking; | ||
| 1626 | Interference num_db = std::accumulate(counts.begin(), counts.end(), | ||
| 1627 | Interference()); | ||
| 1628 | unsigned int num_arrivals = std::min(tsk->get_num_arrivals(), | ||
| 1629 | num_db.count + 1); | ||
| 1630 | unsigned long interval = tsk->get_response(); | ||
| 1631 | |||
| 1632 | const TaskContention& cont = contention[tsk->get_cluster()]; | ||
| 1633 | |||
| 1634 | // for each task in cluster | ||
| 1635 | foreach(cont, it) | ||
| 1636 | { | ||
| 1637 | // count longest critical sections | ||
| 1638 | blocking += bound_blocking(*it, | ||
| 1639 | interval, | ||
| 1640 | num_arrivals, | ||
| 1641 | UNLIMITED, // no limit per source | ||
| 1642 | tsk, | ||
| 1643 | tsk->get_priority()); | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | return blocking; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | BlockingBounds* part_fmlp_bounds(const ResourceSharingInfo& info, bool preemptive) | ||
| 1650 | { | ||
| 1651 | // split everything by partition | ||
| 1652 | Clusters clusters; | ||
| 1653 | |||
| 1654 | split_by_cluster(info, clusters); | ||
| 1655 | |||
| 1656 | // split each partition by resource | ||
| 1657 | ClusterResources resources; | ||
| 1658 | split_by_resource(clusters, resources); | ||
| 1659 | |||
| 1660 | // find interference on a per-task basis | ||
| 1661 | ClusterContention contention; | ||
| 1662 | derive_task_contention(clusters, contention); | ||
| 1663 | |||
| 1664 | // sort each contention set by request length | ||
| 1665 | sort_by_request_length(contention); | ||
| 1666 | |||
| 1667 | // find total interference on a per-cluster basis | ||
| 1668 | AllPerCluster per_cluster; | ||
| 1669 | PerTaskIssuedCounts access_counts; | ||
| 1670 | |||
| 1671 | all_per_cluster(clusters, per_cluster); | ||
| 1672 | sort_by_request_length(per_cluster); | ||
| 1673 | |||
| 1674 | derive_access_counts(per_cluster, info, access_counts); | ||
| 1675 | |||
| 1676 | // We need to find two blocking sources. Direct blocking (i.e., jobs | ||
| 1677 | // that are enqueued prior to the job under analysis) and boost | ||
| 1678 | // blocking, which occurs when the job under analysis is delayed | ||
| 1679 | // because some other job is priority-boosted. Boost blocking can be | ||
| 1680 | // local and transitive from remote CPUs. To compute this correctly, | ||
| 1681 | // we need to count how many times some job on a remote CPU can directly | ||
| 1682 | // block the job under analysis. So we first compute direct blocking | ||
| 1683 | // and count on which CPUs a job can be blocked. | ||
| 1684 | |||
| 1685 | unsigned int i; | ||
| 1686 | |||
| 1687 | // direct blocking results | ||
| 1688 | BlockingBounds* _results = new BlockingBounds(info); | ||
| 1689 | BlockingBounds& results = *_results; | ||
| 1690 | |||
| 1691 | for (i = 0; i < info.get_tasks().size(); i++) | ||
| 1692 | { | ||
| 1693 | const TaskInfo& tsk = info.get_tasks()[i]; | ||
| 1694 | std::vector<Interference> counts(resources.size()); | ||
| 1695 | Interference remote, local; | ||
| 1696 | |||
| 1697 | // Determine counts. | ||
| 1698 | pfmlp_count_direct_blocking(&tsk, resources, counts); | ||
| 1699 | |||
| 1700 | // Find longest remote requests. | ||
| 1701 | remote = pfmlp_bound_remote_blocking(&tsk, access_counts[i], counts, | ||
| 1702 | contention); | ||
| 1703 | |||
| 1704 | // Add in local boost blocking. | ||
| 1705 | local = pfmlp_bound_local_blocking(&tsk, counts, contention); | ||
| 1706 | |||
| 1707 | if (!preemptive) | ||
| 1708 | { | ||
| 1709 | // Charge for additional delays due to remot non-preemptive | ||
| 1710 | // sections. | ||
| 1711 | remote += pfmlp_bound_np_blocking(&tsk, counts, per_cluster); | ||
| 1712 | } | ||
| 1713 | results[i] = remote + local; | ||
| 1714 | results.set_remote_blocking(i, remote); | ||
| 1715 | results.set_local_blocking(i, local); | ||
| 1716 | } | ||
| 1717 | |||
| 1718 | return _results; | ||
| 1719 | } | ||
| 1720 | |||
