Program Listing for File fromhost_buffer.hpp
↰ Return to documentation for file (fromhost_buffer.hpp
)
#ifndef FROMHOST_BUFFER_H_
#define FROMHOST_BUFFER_H_
#include <cstddef>
#include <cstdint>
#include <stdio.h>
#include <thread>
#include <mutex>
#include <atomic>
#include <shared_mutex>
#include <condition_variable>
#include "log.hpp"
#include "device.hpp"
#include "encoder.hpp"
#include "cmem_buffer.hpp"
#include "disk_io.hpp"
#include "fromhost_monitor.hpp"
class FromHostBuffer
{
public:
FromHostBuffer(std::shared_ptr<Device> d) :
m_device(d), m_run_flag(true), m_size(0), m_number_of_writers(0),
m_encoder(), m_mon(), m_mon_prev(), m_trickle_config_size(0)
{};
std::shared_ptr<Device> get_device(){return m_device;}
[[nodiscard]] size_t get_size() const{return m_size;}
size_t get_trickle_config_size(){return m_trickle_config_size;}
void set_trickle_config_size(size_t size){m_trickle_config_size = size;}
void set_encoder_data_format(int format){m_encoder.set_data_format(format);}
[[nodiscard]] int get_dmaid() const{return m_dmaid;}
void set_dmaid(int dma_id)
{
if(m_dmaid == -1) m_dmaid = dma_id;
//else throw std::runtime_error("DMA buffer already initialized with id: " + std::to_string(m_dmaid));
}
void stop(){m_run_flag = false;}
std::vector<Elink> get_elinks(){return m_device->read_enabled_elinks(m_dmaid);}
std::vector<Elink> get_elinks_of_type(elink_type_t t){return m_device->get_enabled_elinks_of_type(m_dmaid, t);};
void increment_writer_counter (){++m_number_of_writers;}
[[nodiscard]] bool has_multiple_writers() const{return m_number_of_writers > 1;}
size_t compute_msg_dma_occupancy(size_t size){return m_encoder.compute_max_msg_occupancy(size);};
void encode_and_write(uint64_t elink, const uint8_t *source, size_t size, bool trickle = false);
uint32_t dma_get_free_MB() {return dma_free_bytes()/1024/1024;}
FromHostDmaStats get_monitoring_data();
virtual size_t dma_free_bytes() = 0;
virtual void allocate_buffer(size_t size,
const std::string& name,
bool vmem, bool free_previous_cmem=true) = 0;
std::mutex m_buffer_mutex; //allow FromHostWriters to lock this
protected:
virtual void set_oneshot_trickle_buffer(size_t config_size) = 0;
virtual void dma_start_continuous() = 0;
virtual void dma_start_circular_trickle_buffer() = 0;
virtual bool dma_is_full() = 0;
virtual uint64_t dma_get_read_offset() = 0;
virtual uint64_t dma_get_write_ptr() = 0;
virtual uint64_t dma_get_write_offset() = 0;
virtual void dma_set_write_offset(uint64_t offset) = 0;
virtual void dma_advance_write_ptr(size_t bytes) = 0;
protected:
int m_dmaid = -1; // -1 is just to check if the buffer is not initialized
std::shared_ptr<Device> m_device;
std::atomic<bool> m_run_flag{true};
size_t m_size;
int m_number_of_writers;
Encoder m_encoder;
FromHostDmaStats m_mon;
FromHostDmaStats m_mon_prev; //to compute rates
size_t m_trickle_config_size;
std::unique_ptr<DmaBuffer> m_buffer;
size_t dma_compute_free_bytes(uint64_t fw_rd_ptr, uint64_t pc_wr_ptr, bool even);
};
inline size_t FromHostBuffer::dma_compute_free_bytes(uint64_t fw_rd_ptr, uint64_t pc_wr_ptr, bool even)
{
size_t value{0};
if(pc_wr_ptr < fw_rd_ptr ) {
value = fw_rd_ptr - pc_wr_ptr;
}
else if( pc_wr_ptr > fw_rd_ptr ) {
value = m_buffer->size - (pc_wr_ptr - fw_rd_ptr);
}
else { // pc_wr_ptr == fw_rd_ptr
if( even ) {
value = m_buffer->size; // Buffer empty
} //else value = 0
}
return value;
}
class FlxFromHostBuffer : public FromHostBuffer {
public:
explicit FlxFromHostBuffer(std::shared_ptr<Device> d);
~FlxFromHostBuffer();
void allocate_buffer(size_t size,
const std::string& name,
bool vmem, bool free_previous_cmem=true) override;
void dma_start_continuous() override;
void dma_start_circular_trickle_buffer() override;
void set_oneshot_trickle_buffer(size_t config_size) override;
size_t dma_free_bytes() override;
bool dma_is_full() override;
uint64_t dma_get_read_offset() override;
uint64_t dma_get_write_offset() override;
uint64_t dma_get_write_ptr() override;
void dma_set_write_offset(uint64_t addr) override;
void dma_advance_write_ptr(size_t bytes) override;
};
class FileFromHostBuffer : public FromHostBuffer {
public:
explicit FileFromHostBuffer(std::shared_ptr<Device> d,
std::string& filename, bool fifo);
~FileFromHostBuffer();
void allocate_buffer(size_t size,
const std::string& name,
bool vmem, bool free_previous_cmem=false) override;
void dma_start_continuous() override;
void dma_start_circular_trickle_buffer() override;
void set_oneshot_trickle_buffer(size_t config_size) override {m_fw_reading_trickle.store(false);};
bool dma_is_full() override;
uint64_t dma_get_read_offset() override;
size_t dma_free_bytes() override;
uint64_t dma_get_write_offset() override;
uint64_t dma_get_write_ptr() override;
void dma_set_write_offset(uint64_t addr) override;
void dma_advance_write_ptr(size_t bytes) override;
private:
bool dma_is_empty();
size_t dma_bytes_to_consume();
void dma_advance_read_ptr(size_t bytes);
void dma_set_read_offset(uint64_t addr);
void set_write_ptr_paddr(uint64_t p_addr);
void copy_from_dma_buffer_to_file();
private:
//regulate concurrent access of read and write pointers
mutable std::shared_mutex m_driver_mutex;
//suspend the card emulator thread when the DMA is empty
std::condition_variable m_reader_cond;
mutable std::mutex m_wake_reader_mutex;
DiskIO m_file;
bool m_rd_odd;
bool m_wr_odd;
std::atomic<bool> m_fw_reading_trickle {false};
std::thread m_reader_thread;
};
#endif /* FROMHOST_BUFFER_H_ */