AddressProfiler.cc revision 7055
1/*
2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "mem/gems_common/Map.hh"
30#include "mem/gems_common/PrioHeap.hh"
31#include "mem/protocol/CacheMsg.hh"
32#include "mem/ruby/profiler/AccessTraceForAddress.hh"
33#include "mem/ruby/profiler/AddressProfiler.hh"
34#include "mem/ruby/profiler/Profiler.hh"
35#include "mem/ruby/system/System.hh"
36
37using namespace std;
38typedef AddressProfiler::AddressMap AddressMap;
39
40// Helper functions
41AccessTraceForAddress&
42lookupTraceForAddress(const Address& addr, AddressMap* record_map)
43{
44    if (!record_map->exist(addr)) {
45        record_map->add(addr, AccessTraceForAddress(addr));
46    }
47    return record_map->lookup(addr);
48}
49
50void
51printSorted(ostream& out, int num_of_sequencers, const AddressMap* record_map,
52            string description)
53{
54    const int records_printed = 100;
55
56    uint64 misses = 0;
57    PrioHeap<AccessTraceForAddress*> heap;
58    Vector<Address> keys = record_map->keys();
59    for (int i = 0; i < keys.size(); i++) {
60        AccessTraceForAddress* record = &(record_map->lookup(keys[i]));
61        misses += record->getTotal();
62        heap.insert(record);
63    }
64
65    out << "Total_entries_" << description << ": " << keys.size() << endl;
66    if (g_system_ptr->getProfiler()->getAllInstructions())
67        out << "Total_Instructions_" << description << ": " << misses << endl;
68    else
69        out << "Total_data_misses_" << description << ": " << misses << endl;
70
71    out << "total | load store atomic | user supervisor | sharing | touched-by"
72        << endl;
73
74    Histogram remaining_records(1, 100);
75    Histogram all_records(1, 100);
76    Histogram remaining_records_log(-1);
77    Histogram all_records_log(-1);
78
79    // Allows us to track how many lines where touched by n processors
80    Vector<int64> m_touched_vec;
81    Vector<int64> m_touched_weighted_vec;
82    m_touched_vec.setSize(num_of_sequencers+1);
83    m_touched_weighted_vec.setSize(num_of_sequencers+1);
84    for (int i = 0; i < m_touched_vec.size(); i++) {
85        m_touched_vec[i] = 0;
86        m_touched_weighted_vec[i] = 0;
87    }
88
89    int counter = 0;
90    while (heap.size() > 0 && counter < records_printed) {
91        AccessTraceForAddress* record = heap.extractMin();
92        double percent = 100.0 * (record->getTotal() / double(misses));
93        out << description << " | " << percent << " % " << *record << endl;
94        all_records.add(record->getTotal());
95        all_records_log.add(record->getTotal());
96        counter++;
97        m_touched_vec[record->getTouchedBy()]++;
98        m_touched_weighted_vec[record->getTouchedBy()] += record->getTotal();
99    }
100
101    while (heap.size() > 0) {
102        AccessTraceForAddress* record = heap.extractMin();
103        all_records.add(record->getTotal());
104        remaining_records.add(record->getTotal());
105        all_records_log.add(record->getTotal());
106        remaining_records_log.add(record->getTotal());
107        m_touched_vec[record->getTouchedBy()]++;
108        m_touched_weighted_vec[record->getTouchedBy()] += record->getTotal();
109    }
110    out << endl;
111    out << "all_records_" << description << ": "
112        << all_records << endl
113        << "all_records_log_" << description << ": "
114        << all_records_log << endl
115        << "remaining_records_" << description << ": "
116        << remaining_records << endl
117        << "remaining_records_log_" << description << ": "
118        << remaining_records_log << endl
119        << "touched_by_" << description << ": "
120        << m_touched_vec << endl
121        << "touched_by_weighted_" << description << ": "
122        << m_touched_weighted_vec << endl
123        << endl;
124}
125
126AddressProfiler::AddressProfiler(int num_of_sequencers)
127{
128    m_dataAccessTrace = new AddressMap;
129    m_macroBlockAccessTrace = new AddressMap;
130    m_programCounterAccessTrace = new AddressMap;
131    m_retryProfileMap = new AddressMap;
132    m_num_of_sequencers = num_of_sequencers;
133    clearStats();
134}
135
136AddressProfiler::~AddressProfiler()
137{
138    delete m_dataAccessTrace;
139    delete m_macroBlockAccessTrace;
140    delete m_programCounterAccessTrace;
141    delete m_retryProfileMap;
142}
143
144void
145AddressProfiler::setHotLines(bool hot_lines)
146{
147    m_hot_lines = hot_lines;
148}
149
150void
151AddressProfiler::setAllInstructions(bool all_instructions)
152{
153    m_all_instructions = all_instructions;
154}
155
156void
157AddressProfiler::printStats(ostream& out) const
158{
159    if (m_hot_lines) {
160        out << endl;
161        out << "AddressProfiler Stats" << endl;
162        out << "---------------------" << endl;
163
164        out << endl;
165        out << "sharing_misses: " << m_sharing_miss_counter << endl;
166        out << "getx_sharing_histogram: " << m_getx_sharing_histogram << endl;
167        out << "gets_sharing_histogram: " << m_gets_sharing_histogram << endl;
168
169        out << endl;
170        out << "Hot Data Blocks" << endl;
171        out << "---------------" << endl;
172        out << endl;
173        printSorted(out, m_num_of_sequencers, m_dataAccessTrace,
174                    "block_address");
175
176        out << endl;
177        out << "Hot MacroData Blocks" << endl;
178        out << "--------------------" << endl;
179        out << endl;
180        printSorted(out, m_num_of_sequencers, m_macroBlockAccessTrace,
181                    "macroblock_address");
182
183        out << "Hot Instructions" << endl;
184        out << "----------------" << endl;
185        out << endl;
186        printSorted(out, m_num_of_sequencers, m_programCounterAccessTrace,
187                    "pc_address");
188    }
189
190    if (m_all_instructions) {
191        out << endl;
192        out << "All Instructions Profile:" << endl;
193        out << "-------------------------" << endl;
194        out << endl;
195        printSorted(out, m_num_of_sequencers, m_programCounterAccessTrace,
196                    "pc_address");
197        out << endl;
198    }
199
200    if (m_retryProfileHisto.size() > 0) {
201        out << "Retry Profile" << endl;
202        out << "-------------" << endl;
203        out << endl;
204        out << "retry_histogram_absolute: " << m_retryProfileHisto << endl;
205        out << "retry_histogram_write: " << m_retryProfileHistoWrite << endl;
206        out << "retry_histogram_read: " << m_retryProfileHistoRead << endl;
207
208        out << "retry_histogram_percent: ";
209        m_retryProfileHisto.printPercent(out);
210        out << endl;
211
212        printSorted(out, m_num_of_sequencers, m_retryProfileMap,
213                    "block_address");
214        out << endl;
215    }
216}
217
218void
219AddressProfiler::clearStats()
220{
221    // Clear the maps
222    m_sharing_miss_counter = 0;
223    m_dataAccessTrace->clear();
224    m_macroBlockAccessTrace->clear();
225    m_programCounterAccessTrace->clear();
226    m_retryProfileMap->clear();
227    m_retryProfileHisto.clear();
228    m_retryProfileHistoRead.clear();
229    m_retryProfileHistoWrite.clear();
230    m_getx_sharing_histogram.clear();
231    m_gets_sharing_histogram.clear();
232}
233
234void
235AddressProfiler::profileGetX(const Address& datablock, const Address& PC,
236                             const Set& owner, const Set& sharers,
237                             NodeID requestor)
238{
239    Set indirection_set;
240    indirection_set.addSet(sharers);
241    indirection_set.addSet(owner);
242    indirection_set.remove(requestor);
243    int num_indirections = indirection_set.count();
244
245    m_getx_sharing_histogram.add(num_indirections);
246    bool indirection_miss = (num_indirections > 0);
247
248    addTraceSample(datablock, PC, CacheRequestType_ST, AccessModeType(0),
249                   requestor, indirection_miss);
250}
251
252void
253AddressProfiler::profileGetS(const Address& datablock, const Address& PC,
254                             const Set& owner, const Set& sharers,
255                             NodeID requestor)
256{
257    Set indirection_set;
258    indirection_set.addSet(owner);
259    indirection_set.remove(requestor);
260    int num_indirections = indirection_set.count();
261
262    m_gets_sharing_histogram.add(num_indirections);
263    bool indirection_miss = (num_indirections > 0);
264
265    addTraceSample(datablock, PC, CacheRequestType_LD, AccessModeType(0),
266                   requestor, indirection_miss);
267}
268
269void
270AddressProfiler::addTraceSample(Address data_addr, Address pc_addr,
271                                CacheRequestType type,
272                                AccessModeType access_mode, NodeID id,
273                                bool sharing_miss)
274{
275    if (m_all_instructions) {
276        if (sharing_miss) {
277            m_sharing_miss_counter++;
278        }
279
280        // record data address trace info
281        data_addr.makeLineAddress();
282        lookupTraceForAddress(data_addr, m_dataAccessTrace).
283            update(type, access_mode, id, sharing_miss);
284
285        // record macro data address trace info
286
287        // 6 for datablock, 4 to make it 16x more coarse
288        Address macro_addr(data_addr.maskLowOrderBits(10));
289        lookupTraceForAddress(macro_addr, m_macroBlockAccessTrace).
290            update(type, access_mode, id, sharing_miss);
291
292        // record program counter address trace info
293        lookupTraceForAddress(pc_addr, m_programCounterAccessTrace).
294            update(type, access_mode, id, sharing_miss);
295    }
296
297    if (m_all_instructions) {
298        // This code is used if the address profiler is an
299        // all-instructions profiler record program counter address
300        // trace info
301        lookupTraceForAddress(pc_addr, m_programCounterAccessTrace).
302            update(type, access_mode, id, sharing_miss);
303    }
304}
305
306void
307AddressProfiler::profileRetry(const Address& data_addr, AccessType type,
308                              int count)
309{
310    m_retryProfileHisto.add(count);
311    if (type == AccessType_Read) {
312        m_retryProfileHistoRead.add(count);
313    } else {
314        m_retryProfileHistoWrite.add(count);
315    }
316    if (count > 1) {
317        lookupTraceForAddress(data_addr, m_retryProfileMap).addSample(count);
318    }
319}
320