aboutsummaryrefslogtreecommitdiffstats
path: root/native/src/sharedres.cpp
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2012-05-16 12:30:30 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2012-05-16 12:30:30 -0400
commitdd7f66806e66d9637b070841c2a7c914671db969 (patch)
tree2310a6036edfab0398fb765db6b88dbf50aea8d9 /native/src/sharedres.cpp
parent546b17c0f6360f4e83e6f0dda8db99656aa94077 (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.cpp373
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
131static void all_from_cluster(const Cluster& cluster, ContentionSet& cs) 131void 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
145static 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
156static 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
176static void split_by_resource(const Clusters& clusters, 151void 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
261typedef std::vector<ContentionSet> TaskContention;
262typedef std::vector<TaskContention> ClusterContention; 236typedef std::vector<TaskContention> ClusterContention;
263 237
264// have one contention set per task 238typedef std::vector<ContentionSet> TaskContention;
265static 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
285static void derive_task_contention(const Clusters& clusters,
286 ClusterContention& contention)
287{
288 map_ref(clusters, contention, TaskContention, derive_task_contention);
289}
290 239
291static Interference bound_blocking(const ContentionSet& cont, 240Interference 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
373static Interference bound_blocking(const ContentionSet& cont, 322Interference 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
1439static 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
1471typedef std::vector<unsigned int> AccessCounts;
1472typedef 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.
1476typedef std::vector<unsigned int> IssuedRequests;
1477// Issued requests for each task. Indexed by task id.
1478typedef std::vector<IssuedRequests> PerTaskIssuedCounts;
1479
1480static 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
1495static 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
1520static 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
1538static 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
1579static 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
1610static 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
1649BlockingBounds* 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