Program Listing for File tohost_buffer.cpp

Return to documentation for file (tohost_buffer.cpp)

#include "tohost_buffer.hpp"
#include "log.hpp"
#include <algorithm>

ToHostBuffer::ToHostBuffer(int dmaid, std::shared_ptr<Device> d)
    : m_dmaid(dmaid), m_device(d), m_block_size(0),
      m_irq_on_data(IRQ_DATA_AVAILABLE + dmaid), m_irq_counter(0), m_size(0),
      m_stop_flag(false), m_has_zero_copy_reader(false), m_min_bytes_sent(0)
{}


std::vector<std::vector<Elink>> ToHostBuffer::split_elinks_of_type(elink_type_t t, size_t n)
{
    std::vector<Elink> vec = get_elinks_of_type(t);
    std::vector<std::vector<Elink>> result;
    size_t length = vec.size() / n;
    size_t remain = vec.size() % n;
    size_t begin = 0;
    size_t end = 0;
    for (size_t i = 0; i < std::min(n, vec.size()); ++i) {
        end += (remain > 0) ? (length + !!(remain--)) : length;
        result.push_back(std::vector<Elink>(vec.begin() + begin, vec.begin() + end));
        begin = end;
    }
    return result;
}


uint32_t ToHostBuffer::reader_register(bool zero_copy)
{
    std::scoped_lock lock(m_mutex);
    uint64_t offset = (uint64_t)dma_get_read_offset();
    m_bytes_read.push_back(offset);
    m_bytes_sent.push_back(offset);
    uint32_t reader_id = m_bytes_read.size() - 1;
    return reader_id;
}

//The amount of data available is computed with read blocks
//also when zero-copy publishers are used.
//Otherwise the "data available" signal would be always fired
//at the end of the ToHostReader<B>::read function
size_t ToHostBuffer::reader_get_available_bytes(uint32_t reader_id)
{
    uint64_t write_offset = dma_get_write_offset();
    uint64_t read_offset = m_bytes_read[reader_id] % m_size;
    LOG_TRACE("Reader id %u, write 0x%lx read 0x%lx", reader_id, write_offset, read_offset);
    if (write_offset > read_offset) {
        return write_offset - read_offset;
    }
    else if (write_offset < read_offset) {
        return m_size - read_offset;
    }
    else if (dma_is_full()) {
        if (m_bytes_read[reader_id] == m_min_bytes_sent) {
            return m_size - read_offset;
        }
    }
    return 0;
}


bool ToHostBuffer::reader_is_data_available(uint32_t reader_id)
{
    return reader_get_available_bytes(reader_id);
}


std::span<Block> ToHostBuffer::reader_get_available_blocks(uint32_t reader_id)
{
  return std::span(reinterpret_cast<Block*>(m_buffer->vaddr + m_bytes_read[reader_id] % m_size),
        reader_get_available_bytes(reader_id)/sizeof(Block));
}


void ToHostBuffer::reader_advance_read_ptr(uint32_t reader_id, uint32_t read_bytes, uint32_t sent_bytes)
{
    std::scoped_lock lock(m_mutex);
    auto last_bytes_sent = m_bytes_sent[reader_id];
    m_bytes_read[reader_id] += read_bytes;
    m_bytes_sent[reader_id] += sent_bytes;

    if (m_min_bytes_sent == last_bytes_sent) {
        m_min_bytes_sent = *std::ranges::min_element(m_bytes_sent);

        if (m_min_bytes_sent != last_bytes_sent) {
            dma_set_read_ptr_paddr(m_buffer->paddr + (m_min_bytes_sent % m_size));
        }
    }
}


uint32_t ToHostBuffer::dma_get_free_MB()
{
    auto to_read = dma_bytes_available();
    return (m_buffer->size - to_read)/1024/1024;
}