Skip to content

Commit

Permalink
Merge pull request #451 from 4ms/load-balance-with-cables
Browse files Browse the repository at this point in the history
Load balancing of modules and internal cables
  • Loading branch information
danngreen authored Jan 9, 2025
2 parents cd68552 + 5569407 commit 782604e
Show file tree
Hide file tree
Showing 9 changed files with 377 additions and 156 deletions.
2 changes: 1 addition & 1 deletion firmware/lib/cpputil
83 changes: 9 additions & 74 deletions firmware/src/core_a7/aux_core_main.cc
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
#include "aux_core_player.hh"
#include "conf/hsem_conf.hh"
#include "core_a7/a7_shared_memory.hh"
#include "core_a7/async_thread_control.hh"
#include "core_a7/smp_api.hh"
#include "debug.hh"
#include "drivers/hsem.hh"
#include "drivers/smp.hh"
#include "drivers/timekeeper.hh"
#include "dynload/plugin_manager.hh"
#include "fs/filesystem.hh"
#include "fs/norflash_layout.hh"
#include "gui/ui.hh"
#include "internal_plugin_manager.hh"
#include "patch_play/patch_player.hh"

using FrameBufferT =
std::array<lv_color_t, MetaModule::ScreenBufferConf::width * MetaModule::ScreenBufferConf::height / 4>;
Expand All @@ -31,92 +28,30 @@ extern "C" void aux_core_main() {

pr_info("A7 Core 2 starting\n");

auto patch_player = A7SharedMemoryS::ptrs.patch_player;
auto patch_playloader = A7SharedMemoryS::ptrs.patch_playloader;
auto file_storage_proxy = A7SharedMemoryS::ptrs.patch_storage;
auto open_patch_manager = A7SharedMemoryS::ptrs.open_patch_manager;
auto sync_params = A7SharedMemoryS::ptrs.sync_params;
auto patch_mod_queue = A7SharedMemoryS::ptrs.patch_mod_queue;
auto ramdisk_storage = A7SharedMemoryS::ptrs.ramdrive;
#ifdef CONSOLE_USE_USB
UartLog::use_usb(A7SharedMemoryS::ptrs.console_buffer);
#endif

LVGLDriver gui{MMDisplay::flush_to_screen, MMDisplay::read_input, MMDisplay::wait_cb, framebuf1, framebuf2};

RamDiskOps ramdisk_ops{*ramdisk_storage};
RamDiskOps ramdisk_ops{*A7SharedMemoryS::ptrs.ramdrive};
FatFileIO ramdisk{&ramdisk_ops, Volume::RamDisk};
AssetFS asset_fs{AssetVolFlashOffset};
Filesystem::Init(ramdisk);
PluginManager plugin_manager{*file_storage_proxy, ramdisk};
Ui ui{*patch_playloader,
*file_storage_proxy,
*open_patch_manager,
*sync_params,
*patch_mod_queue,
PluginManager plugin_manager{*A7SharedMemoryS::ptrs.patch_storage, ramdisk};
Ui ui{*A7SharedMemoryS::ptrs.patch_playloader,
*A7SharedMemoryS::ptrs.patch_storage,
*A7SharedMemoryS::ptrs.open_patch_manager,
*A7SharedMemoryS::ptrs.sync_params,
*A7SharedMemoryS::ptrs.patch_mod_queue,
plugin_manager,
ramdisk};
ui.update_screen();
ui.update_page();

InternalPluginManager internal_plugin_manager{ramdisk, asset_fs};

struct AuxCoreModulesToRun {
uint32_t starting_idx = 1;
uint32_t num_modules = 0;
uint32_t idx_increment = 2;
} modules_to_run;

constexpr auto PlayModuleListIRQn = SMPControl::IRQn(SMPCommand::PlayModuleList);
InterruptManager::register_and_start_isr(PlayModuleListIRQn, 1, 0, [&modules_to_run, &patch_player]() {
// Debug::Pin1::high();
for (unsigned i = modules_to_run.starting_idx; i < modules_to_run.num_modules;
i += modules_to_run.idx_increment)
{
patch_player->modules[i]->update();
}
// Debug::Pin1::low();
SMPThread::signal_done();
});

constexpr auto NewModuleListIRQn = SMPControl::IRQn(SMPCommand::NewModuleList);
InterruptManager::register_and_start_isr(NewModuleListIRQn, 0, 0, [&modules_to_run]() {
modules_to_run.starting_idx = SMPControl::read<SMPRegister::ModuleID>();
modules_to_run.num_modules = SMPControl::read<SMPRegister::NumModulesInPatch>();
modules_to_run.idx_increment = SMPControl::read<SMPRegister::UpdateModuleOffset>();
SMPThread::signal_done();
});

constexpr auto ReadPatchLightsIRQn = SMPControl::IRQn(SMPCommand::ReadPatchLights);
InterruptManager::register_and_start_isr(ReadPatchLightsIRQn, 2, 0, [patch_player, &ui]() {
if (ui.new_patch_data == false) {

for (auto &w : ui.lights().watch_lights) {
if (w.is_active()) {
auto val = patch_player->get_module_light(w.module_id, w.light_id);
w.value = val;
}
}

for (auto &d : ui.displays().watch_displays) {
if (d.is_active()) {
auto text = std::span<char>(d.text._data, d.text.capacity);
auto sz = patch_player->get_display_text(d.module_id, d.light_id, text);
d.text._data[sz] = '\0';
}
}

for (auto &p : ui.watched_params().active_watched_params()) {
if (p.is_active()) {
p.value = patch_player->get_param(p.module_id, p.param_id);
}
}

ui.new_patch_data = true;
}

SMPThread::signal_done();
});
AuxPlayer aux_player{*A7SharedMemoryS::ptrs.patch_player, ui};

// Wait for M4 to be ready (so USB and SD are available)
while (mdrivlib::HWSemaphore<M4CoreReady>::is_locked())
Expand Down
96 changes: 96 additions & 0 deletions firmware/src/core_a7/aux_core_player.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#pragma once
#include "core_a7/smp_api.hh"
#include "drivers/interrupt.hh"
#include "drivers/smp.hh"
#include "gui/ui.hh"
#include "patch_play/patch_player.hh"
#include "util/fixed_vector.hh"

namespace MetaModule
{

struct AuxPlayer {
PatchPlayer &patch_player;
Ui &ui;

FixedVector<unsigned, 64> module_ids;

AuxPlayer(PatchPlayer &patch_player, Ui &ui)
: patch_player{patch_player}
, ui{ui} {
using namespace mdrivlib;

constexpr auto NewModuleListIRQn = SMPControl::IRQn(SMPCommand::NewModuleList);
InterruptManager::register_and_start_isr(NewModuleListIRQn, 0, 0, [this]() { assign_module_list(); });

constexpr auto PlayModuleListIRQn = SMPControl::IRQn(SMPCommand::PlayModuleList);
InterruptManager::register_and_start_isr(PlayModuleListIRQn, 1, 0, [this]() { play_modules(); });

constexpr auto ReadPatchLightsIRQn = SMPControl::IRQn(SMPCommand::ReadPatchLights);
InterruptManager::register_and_start_isr(ReadPatchLightsIRQn, 2, 0, [this]() { read_patch_gui_elements(); });
}

void play_modules() {

for (auto module_i : module_ids) {
patch_player.process_module_outputs(module_i);
}

for (auto module_i : module_ids) {
patch_player.step_module(module_i);
}

mdrivlib::SMPThread::signal_done();
}

void assign_module_list() {
using namespace mdrivlib;

module_ids.clear();

auto num_modules = SMPControl::read<SMPRegister::NumModulesInPatch>();

if (num_modules < module_ids.max_size()) {
for (auto i = 0u; i < num_modules; i++) {
auto id = SMPControl::read(i + 2);
module_ids.push_back(id);
}

} else
pr_err("Error: %u modules requested to run on core 2, max is %z\n", num_modules, module_ids.size());

SMPThread::signal_done();
}

void read_patch_gui_elements() {
if (ui.new_patch_data == false) {

for (auto &w : ui.lights().watch_lights) {
if (w.is_active()) {
auto val = patch_player.get_module_light(w.module_id, w.light_id);
w.value = val;
}
}

for (auto &d : ui.displays().watch_displays) {
if (d.is_active()) {
auto text = std::span<char>(d.text._data, d.text.capacity);
auto sz = patch_player.get_display_text(d.module_id, d.light_id, text);
d.text._data[sz] = '\0';
}
}

for (auto &p : ui.watched_params().active_watched_params()) {
if (p.is_active()) {
p.value = patch_player.get_param(p.module_id, p.param_id);
}
}

ui.new_patch_data = true;
}

SMPThread::signal_done();
}
};

} // namespace MetaModule
6 changes: 0 additions & 6 deletions firmware/src/core_a7/smp_api.hh
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ namespace SMPRegister
{
enum : uint32_t {
DoneZero,
ModuleID,
ParamID,
ParamVal,
FunctionAddress,
NumModulesInPatch,
UpdateModuleOffset,
Unused,
};
} // namespace SMPRegister
73 changes: 73 additions & 0 deletions firmware/src/patch_play/balance_modules.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#pragma once
#include "CoreModules/CoreProcessor.hh"
#include "drivers/cycle_counter.hh"
#include "patch/module_type_slug.hh"
#include "util/partition.hh"
#include <memory>
#include <vector>

#include "console/pr_dbg.hh"

namespace MetaModule
{

template<size_t NumCores, size_t MaxModules>
struct Balancer {
Partition<NumCores, MaxModules> cores;

std::vector<unsigned>
measure_modules(std::span<std::unique_ptr<CoreProcessor>> modules, unsigned num_modules, auto run) {

mdrivlib::CycleCounter counter;

constexpr size_t NumIterations = 512;
constexpr size_t DropFirst = 32;

std::vector<unsigned> times(num_modules - 1, 0);

for (auto iter_i = 0u; iter_i < NumIterations + DropFirst; iter_i++) {

for (size_t module_i = 1; module_i < num_modules; module_i++) {

counter.start_measurement();
run(module_i);
counter.end_measurement();

if (iter_i >= DropFirst)
times[module_i - 1] += counter.get_last_measurement_raw();
}
}

return times;
}

void balance_loads(std::span<unsigned> times) {
if (NumCores == 2) {
// Core 2 needs extra time to respond to its interrupt
// units is 1/24MHz
auto bias = std::array<unsigned, 2>{0, 1000};
cores.calc_partitions(times, bias);
} else
cores.calc_partitions(times);

// Adjust indices since we skip module 0
for (auto &part : cores.parts) {
for (auto &idx : part)
idx++;
}
}

void print_times(std::span<unsigned> times, std::span<BrandModuleSlug> slugs) {
// Debug output:
for (auto core = 0u; core < NumCores; core++) {
unsigned sum = 0;
for (auto idx : cores.parts[core]) {
pr_dbg("Core %d: Module %u (%s): %u\n", core, idx, slugs[idx].c_str(), times[idx - 1]);
sum += times[idx - 1];
}
pr_dbg("Core %d Total: %u\n", core, sum);
}
}
};

} // namespace MetaModule
64 changes: 64 additions & 0 deletions firmware/src/patch_play/cable_cache.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once
#include "conf/patch_conf.hh"
#include "patch/patch_data.hh"
#include <span>

namespace MetaModule
{

struct CableCache {
CableCache() = default;

struct CableOut {
float val;
uint16_t jack_id;
};

struct CableIn {
uint16_t jack_id;
uint16_t out_module_id;
uint16_t out_cache_idx;
//todo: profile using this instead:
// CableOut *out;
};

void clear() {
for (auto &out : outs)
out.clear();
for (auto &in : ins)
in.clear();
}

void build(std::span<const InternalCable> cables) {
clear();

for (auto &cable : cables) {
if (cable.out.module_id >= outs.size())
continue;

auto &out = outs[cable.out.module_id];
auto out_idx = out.size();
out.emplace_back(0.f, cable.out.jack_id);

for (auto &in : cable.ins) {
if (in.module_id < ins.size()) {
ins[in.module_id].emplace_back(in.jack_id, cable.out.module_id, out_idx);
}
}
}
}

void add(Jack injack, Jack outjack) {
if (injack.module_id < ins.size() && outjack.module_id < outs.size()) {
auto &out = outs[outjack.module_id];
auto out_idx = out.size();
out.emplace_back(0.f, outjack.jack_id);
ins[injack.module_id].emplace_back(injack.jack_id, outjack.module_id, out_idx);
}
}

// outs[N] and ins[N] are the cables connected to module id N
std::array<std::vector<CableOut>, MAX_MODULES_IN_PATCH> outs;
std::array<std::vector<CableIn>, MAX_MODULES_IN_PATCH> ins;
};
} // namespace MetaModule
Loading

0 comments on commit 782604e

Please sign in to comment.