<commit_before>#include "RootDirectory.h"
#include "DDR.h"
#include "../config.h"
#include <iomanip>
using namespace std;

namespace Simulator
{

// When we shortcut a message over the ring, we want at least one slots
// available in the buffer to avoid deadlocking the ring network. This
// is not necessary for forwarding messages.
static const size_t MINSPACE_SHORTCUT = 2;
static const size_t MINSPACE_FORWARD  = 1;

COMA::RootDirectory::Line* COMA::RootDirectory::FindLine(MemAddr address, bool check_only)
{
    const MemAddr tag  = (address / m_lineSize) / m_sets;
    const size_t  set  = (size_t)((address / m_lineSize) % m_sets) * m_assoc;

    // Find the line
    Line* empty = NULL;
    for (size_t i = 0; i < m_assoc; ++i)
    {
        Line* line = &m_lines[set + i];

        if (line->state == LINE_EMPTY)
        {
            // Empty, unused line, remember this one
            empty = line;
        }
        else if (line->tag == tag)
        {
            // The wanted line was in the cache
            return line;
        }
    }

    // The line could not be found, allocate the empty line or replace an existing line
    Line* line = NULL;
    if (!check_only && empty != NULL)
    {
        // Reset the line
        line = empty;
        line->tag    = tag;
        line->state  = LINE_EMPTY;
        line->tokens = 0;
    }
    return line;
}

const COMA::RootDirectory::Line* COMA::RootDirectory::FindLine(MemAddr address) const
{
    const MemAddr tag  = (address / m_lineSize) / m_sets;
    const size_t  set  = (size_t)((address / m_lineSize) % m_sets) * m_assoc;

    // Find the line
    for (size_t i = 0; i < m_assoc; ++i)
    {
        const Line* line = &m_lines[set + i];
        if (line->state != LINE_EMPTY && line->tag == tag)
        {
            return line;
        }
    }
    return NULL;
}

bool COMA::RootDirectory::OnReadCompleted(MemAddr address, const MemData& data)
{
    assert(m_activeMsg != NULL);
    assert(m_activeMsg->address == address);
    assert(m_activeMsg->type == Message::REQUEST);
    
    COMMIT
    {
        m_activeMsg->type = Message::REQUEST_DATA_TOKEN;
        m_activeMsg->data = data;
    }
    
    if (!m_responses.Push(m_activeMsg))
    {
        DeadlockWrite("Unable to push reply into send buffer");
        return false;
    }
    
    // We're done with this request
    if (!m_memready.Set())
    {
        return false;
    }
    COMMIT{ m_activeMsg = NULL; }
    return true;
}

bool COMA::RootDirectory::OnMessageReceived(Message* msg)
{
    assert(msg != NULL);
    
    if (((msg->address / m_lineSize) % m_numRoots) == m_id)
    {
        // This message is for us
        if (!p_lines.Invoke())
        {
            return false;
        }

        switch (msg->type)
        {
        case Message::REQUEST:
        {
            // Cache-line read request
            assert(msg->data.size == m_lineSize);
        
            // Find or allocate the line
            Line* line = FindLine(msg->address, false);
            if (line != NULL && line->state == LINE_EMPTY)
            {
                // Line has not been read yet it; queue the read
                TraceWrite(msg->address, "Received Read Request; Miss; Queuing request");
                if (!m_requests.Push(msg))
                {
                    return false;
                }

                COMMIT
                {
                    line->state  = LINE_LOADING;
                    line->sender = msg->sender;
                }
                return true;
            }
            break;
        }
    
        case Message::REQUEST_DATA:
        {
            // We should have the line since the request already hit a copy to get the data
            Line* line = FindLine(msg->address, true);
            assert(line != NULL);
            assert(line->state == LINE_FULL);
        
            if (line->tokens > 0)
            {
                // Give the request the tokens that we have
                TraceWrite(msg->address, "Received Read Request with data; Attaching %u tokens", line->tokens);
                COMMIT
                {
                    msg->type    = Message::REQUEST_DATA_TOKEN;
                    msg->tokens  = line->tokens;
                    line->tokens = 0;
                }
            }
            break;
        }

        case Message::EVICTION:
        {<commit_msg>[mgsim] Fixed bug in ML COMA.<commit_after>#include "RootDirectory.h"
#include "DDR.h"
#include "../config.h"
#include <iomanip>
using namespace std;

namespace Simulator
{

// When we shortcut a message over the ring, we want at least one slots
// available in the buffer to avoid deadlocking the ring network. This
// is not necessary for forwarding messages.
static const size_t MINSPACE_SHORTCUT = 2;
static const size_t MINSPACE_FORWARD  = 1;

COMA::RootDirectory::Line* COMA::RootDirectory::FindLine(MemAddr address, bool check_only)
{
    const MemAddr tag  = (address / m_lineSize) / m_sets;
    const size_t  set  = (size_t)((address / m_lineSize) % m_sets) * m_assoc;

    // Find the line
    Line* empty = NULL;
    for (size_t i = 0; i < m_assoc; ++i)
    {
        Line* line = &m_lines[set + i];

        if (line->state == LINE_EMPTY)
        {
            // Empty, unused line, remember this one
            empty = line;
        }
        else if (line->tag == tag)
        {
            // The wanted line was in the cache
            return line;
        }
    }

    // The line could not be found, allocate the empty line or replace an existing line
    Line* line = NULL;
    if (!check_only && empty != NULL)
    {
        // Reset the line
        line = empty;
        line->tag    = tag;
        line->state  = LINE_EMPTY;
        line->tokens = 0;
    }
    return line;
}

const COMA::RootDirectory::Line* COMA::RootDirectory::FindLine(MemAddr address) const
{
    const MemAddr tag  = (address / m_lineSize) / m_sets;
    const size_t  set  = (size_t)((address / m_lineSize) % m_sets) * m_assoc;

    // Find the line
    for (size_t i = 0; i < m_assoc; ++i)
    {
        const Line* line = &m_lines[set + i];
        if (line->state != LINE_EMPTY && line->tag == tag)
        {
            return line;
        }
    }
    return NULL;
}

bool COMA::RootDirectory::OnReadCompleted(MemAddr address, const MemData& data)
{
    assert(m_activeMsg != NULL);
    assert(m_activeMsg->address == address);
    assert(m_activeMsg->type == Message::REQUEST);
    
    COMMIT
    {
        m_activeMsg->type = Message::REQUEST_DATA_TOKEN;
        m_activeMsg->data = data;
    }
    
    if (!m_responses.Push(m_activeMsg))
    {
        DeadlockWrite("Unable to push reply into send buffer");
        return false;
    }
    
    // We're done with this request
    if (!m_memready.Set())
    {
        return false;
    }
    COMMIT{ m_activeMsg = NULL; }
    return true;
}

bool COMA::RootDirectory::OnMessageReceived(Message* msg)
{
    assert(msg != NULL);
    
    if (((msg->address / m_lineSize) % m_numRoots) == m_id)
    {
        // This message is for us
        if (!p_lines.Invoke())
        {
            return false;
        }

        switch (msg->type)
        {
        case Message::REQUEST:
        {
            // Cache-line read request
            assert(msg->data.size == m_lineSize);
        
            // Find or allocate the line
            Line* line = FindLine(msg->address, false);
            if (line != NULL && line->state == LINE_EMPTY)
            {
                // Line has not been read yet it; queue the read
                TraceWrite(msg->address, "Received Read Request; Miss; Queuing request");
                if (!m_requests.Push(msg))
                {
                    return false;
                }

                COMMIT
                {
                    line->state  = LINE_LOADING;
                    line->sender = msg->sender;
                }
                return true;
            }
            break;
        }
    
        case Message::REQUEST_DATA:
        {
            // Cache-line read request with data
            assert(msg->data.size == m_lineSize);
            
            // Find or allocate the line. This should not fail.
            Line* line = FindLine(msg->address, false);
            assert(line != NULL);
            
            if (line->state == LINE_EMPTY)
            {
                // It's possible that a read request with data grabs data from the last copy of a cache-line,
                // which is then evicted from the system before this request comes to the root directory.
                // In that case, we simply reintroduce the tokens into the system (the data is already in
                // the system, so no need to read it from memory).
                TraceWrite(msg->address, "Received Read Request with data; Miss; Introducing and attaching %u tokens", (unsigned)m_numCaches);
                
                COMMIT
                {
                    msg->type   = Message::REQUEST_DATA_TOKEN;
                    msg->tokens = m_numCaches;
                    line->state = LINE_FULL;
                }
            }
            else if (line->tokens > 0)
            {
                // Give the request the tokens that we have
                TraceWrite(msg->address, "Received Read Request with data; Hit; Attaching %u tokens", line->tokens);
                
                COMMIT
                {
                    msg->type    = Message::REQUEST_DATA_TOKEN;
                    msg->tokens  = line->tokens;
                    line->tokens = 0;
                }
            }
            break;
        }

        case Message::EVICTION:
        {
{'fraction_non_alphanumeric': 0.104055166735282, 'fraction_numerical': 0.001440922190201729, 'mean_word_length': 1.5801911842804035, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 70, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2821172', 'n_tokens_mistral': 2830, 'n_tokens_neox': 2739, 'n_words': 806}