Skip to content

Commit 74e0363

Browse files
committed
Add monitor_cpu_load command
Signed-off-by: falkTX <falktx@falktx.com>
1 parent e50c17d commit 74e0363

7 files changed

Lines changed: 179 additions & 2 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ The commands supported by mod-host are:
235235
* monitor audio levels for a specific jack port (on the feedback port)
236236
e.g.: monitor_audio_levels "system:capture_1" 1
237237

238+
monitor_cpu_load <enable> <instance_count> <instance_number...>
239+
* monitor cpu load for specific instances
240+
e.g.: monitor_cpu_load 1 2 0 1
241+
238242
monitor_midi_control <midi_channel> <enable>
239243
* listen to MIDI control change messages (on the feedback port)
240244
e.g.: monitor_midi_control 7 1

src/effects.c

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ enum PostPonedEventType {
300300
POSTPONED_PARAM_SET,
301301
POSTPONED_PARAM_STATE,
302302
POSTPONED_AUDIO_MONITOR,
303+
POSTPONED_CPU_MONITOR,
303304
POSTPONED_OUTPUT_MONITOR,
304305
POSTPONED_MIDI_CONTROL_CHANGE,
305306
POSTPONED_MIDI_PROGRAM_CHANGE,
@@ -461,6 +462,10 @@ typedef struct EFFECT_T {
461462

462463
bool activated;
463464

465+
bool monitor_cpu;
466+
bool monitor_cpu_reset;
467+
float cpu_load;
468+
464469
// previous transport state
465470
bool transport_rolling;
466471
uint32_t transport_frame;
@@ -637,6 +642,11 @@ typedef struct POSTPONED_AUDIO_MONITOR_EVENT_T {
637642
float value;
638643
} postponed_audio_monitor_event_t;
639644

645+
typedef struct POSTPONED_CPU_MONITOR_EVENT_T {
646+
int effect_id;
647+
float cpu_load;
648+
} postponed_cpu_monitor_event_t;
649+
640650
typedef struct POSTPONED_MIDI_CONTROL_CHANGE_EVENT_T {
641651
int8_t channel;
642652
int8_t control;
@@ -687,6 +697,7 @@ typedef struct POSTPONED_EVENT_T {
687697
postponed_parameter_event_t parameter;
688698
postponed_parameter_state_t state;
689699
postponed_audio_monitor_event_t audio_monitor;
700+
postponed_cpu_monitor_event_t cpu_monitor;
690701
postponed_midi_control_change_event_t control_change;
691702
postponed_midi_program_change_event_t program_change;
692703
postponed_midi_map_event_t midi_map;
@@ -783,7 +794,7 @@ static jack_client_t *g_jack_global_client;
783794
static jack_nframes_t g_sample_rate, g_max_allowed_midi_delta;
784795
static float g_sample_rate_f;
785796
static const char **g_capture_ports, **g_playback_ports;
786-
static int32_t g_midi_buffer_size, g_block_length;
797+
static int32_t g_midi_buffer_size, g_block_length, g_block_time_us;
787798
static int32_t g_thread_policy, g_thread_priority;
788799
#ifdef MOD_IO_PROCESSING_ENABLED
789800
static jack_port_t *g_audio_in1_port;
@@ -1097,6 +1108,7 @@ static void AllocatePortBuffers(effect_t* effect, int in_size, int out_size)
10971108
static int BufferSize(jack_nframes_t nframes, void* data)
10981109
{
10991110
g_block_length = nframes;
1111+
g_block_time_us = nframes * 1e6 / g_sample_rate;
11001112
g_midi_buffer_size = jack_port_type_get_buffer_size(g_jack_global_client, JACK_DEFAULT_MIDI_TYPE);
11011113

11021114
if (data)
@@ -1347,10 +1359,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
13471359
// cached data, to make sure we only handle similar events once
13481360
bool got_midi_program = false;
13491361
bool got_transport = false;
1350-
postponed_cached_effect_events cached_audio_monitor, cached_process_out_buf;
1362+
postponed_cached_effect_events cached_audio_monitor, cached_cpu_monitor, cached_process_out_buf;
13511363
postponed_cached_symbol_events cached_param_set, cached_param_state, cached_output_mon;
13521364

13531365
cached_audio_monitor.last_effect_id = -1;
1366+
cached_cpu_monitor.last_effect_id = -1;
13541367
cached_process_out_buf.last_effect_id = -1;
13551368
cached_param_set.last_effect_id = -1;
13561369
cached_param_set.last_symbol[0] = '\0';
@@ -1362,6 +1375,7 @@ static void RunPostPonedEvents(int ignored_effect_id)
13621375
cached_output_mon.last_symbol[0] = '\0';
13631376
cached_output_mon.last_symbol[MAX_CHAR_BUF_SIZE] = '\0';
13641377
INIT_LIST_HEAD(&cached_audio_monitor.effects.siblings);
1378+
INIT_LIST_HEAD(&cached_cpu_monitor.effects.siblings);
13651379
INIT_LIST_HEAD(&cached_process_out_buf.effects.siblings);
13661380
INIT_LIST_HEAD(&cached_param_set.symbols.siblings);
13671381
INIT_LIST_HEAD(&cached_param_state.symbols.siblings);
@@ -1448,6 +1462,18 @@ static void RunPostPonedEvents(int ignored_effect_id)
14481462
cached_audio_monitor.last_effect_id = eventptr->event.audio_monitor.index;
14491463
break;
14501464

1465+
case POSTPONED_CPU_MONITOR:
1466+
if (ShouldIgnorePostPonedEffectEvent(eventptr->event.audio_monitor.index, &cached_audio_monitor))
1467+
continue;
1468+
1469+
snprintf(buf, FEEDBACK_BUF_SIZE, "cpu_monitor %i %f", eventptr->event.cpu_monitor.effect_id,
1470+
eventptr->event.cpu_monitor.cpu_load);
1471+
socket_send_feedback_debug(buf);
1472+
1473+
// save for fast checkup next time
1474+
cached_cpu_monitor.last_effect_id = eventptr->event.cpu_monitor.effect_id;
1475+
break;
1476+
14511477
case POSTPONED_OUTPUT_MONITOR:
14521478
if (eventptr->event.parameter.effect_id == ignored_effect_id)
14531479
continue;
@@ -1744,6 +1770,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
17441770
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
17451771
free(peffect);
17461772
}
1773+
list_for_each_safe(it, it2, &cached_cpu_monitor.effects.siblings)
1774+
{
1775+
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
1776+
free(peffect);
1777+
}
17471778
list_for_each_safe(it, it2, &cached_process_out_buf.effects.siblings)
17481779
{
17491780
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
@@ -2066,10 +2097,15 @@ static int ProcessPlugin(jack_nframes_t nframes, void *arg)
20662097
}
20672098

20682099
/* common variables */
2100+
const bool monitor_cpu = effect->monitor_cpu;
20692101
bool needs_post = false;
20702102
const float *buffer_in;
20712103
float *buffer_out;
20722104
float value;
2105+
uint64_t time_start;
2106+
2107+
if (monitor_cpu)
2108+
time_start = time_ns_get();
20732109

20742110
/* transport */
20752111
uint8_t stack_buf[MAX_CHAR_BUF_SIZE+1];
@@ -2611,6 +2647,37 @@ static int ProcessPlugin(jack_nframes_t nframes, void *arg)
26112647
if (effect->hints & HINT_STATE_UNSAFE)
26122648
pthread_mutex_unlock(&effect->state_restore_mutex);
26132649

2650+
if (monitor_cpu)
2651+
{
2652+
if (effect->monitor_cpu_reset)
2653+
{
2654+
effect->cpu_load = 0.f;
2655+
effect->monitor_cpu_reset = false;
2656+
}
2657+
2658+
float cpu_load = ((int32_t)(time_ns_get() - time_start) / g_block_time_us) * 0.001f;
2659+
2660+
if (cpu_load > effect->cpu_load)
2661+
{
2662+
effect->cpu_load = cpu_load;
2663+
2664+
postponed_event_list_data* const posteventptr = rtsafe_memory_pool_allocate_atomic(g_rtsafe_mem_pool);
2665+
2666+
if (posteventptr != NULL)
2667+
{
2668+
posteventptr->event.type = POSTPONED_CPU_MONITOR;
2669+
posteventptr->event.cpu_monitor.effect_id = effect->instance;
2670+
posteventptr->event.cpu_monitor.cpu_load = cpu_load;
2671+
2672+
pthread_mutex_lock(&g_rtsafe_mutex);
2673+
list_add_tail(&posteventptr->siblings, &g_rtsafe_list);
2674+
pthread_mutex_unlock(&g_rtsafe_mutex);
2675+
2676+
needs_post = true;
2677+
}
2678+
}
2679+
}
2680+
26142681
if (needs_post)
26152682
sem_post(&g_postevents_semaphore);
26162683

@@ -4453,6 +4520,8 @@ int effects_init(void* client)
44534520
return ERR_JACK_CLIENT_CREATION;
44544521
}
44554522

4523+
time_ns_init();
4524+
44564525
/* Register jack ports */
44574526
g_midi_in_port = jack_port_register(g_jack_global_client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
44584527

@@ -4524,6 +4593,7 @@ int effects_init(void* client)
45244593
/* Get buffers size */
45254594
g_block_length = jack_get_buffer_size(g_jack_global_client);
45264595
g_sample_rate = jack_get_sample_rate(g_jack_global_client);
4596+
g_block_time_us = g_block_length * 1e6 / g_sample_rate;
45274597
g_sample_rate_f = g_sample_rate;
45284598
g_midi_buffer_size = jack_port_type_get_buffer_size(g_jack_global_client, JACK_DEFAULT_MIDI_TYPE);
45294599
g_max_allowed_midi_delta = (jack_nframes_t)(g_sample_rate * 0.2); // max 200ms of allowed delta
@@ -9467,6 +9537,30 @@ int effects_monitor_audio_levels(const char *source_port_name, int enable)
94679537
return SUCCESS;
94689538
}
94699539

9540+
int effects_monitor_cpu_load(int enable, int num_effects, int *effects)
9541+
{
9542+
if (num_effects <= 0)
9543+
return ERR_INVALID_OPERATION;
9544+
9545+
effect_t *effect;
9546+
9547+
for (int i = 0, effect_id; i < num_effects; i++)
9548+
{
9549+
effect_id = effects[i];
9550+
if (InstanceExist(effect_id))
9551+
{
9552+
effect = &g_effects[effect_id];
9553+
9554+
if (enable != 0)
9555+
effect->monitor_cpu_reset = true;
9556+
9557+
effect->monitor_cpu = enable != 0;
9558+
}
9559+
}
9560+
9561+
return SUCCESS;
9562+
}
9563+
94709564
int effects_monitor_midi_control(int channel, int enable)
94719565
{
94729566
if (channel < 0 || channel > 15)
@@ -9631,6 +9725,20 @@ void effects_output_data_ready(void)
96319725

96329726
if (! g_postevents_ready)
96339727
{
9728+
// recalculate max cpu usage again
9729+
for (int i = 0; i < MAX_PLUGIN_INSTANCES; ++i)
9730+
{
9731+
effect_t *effect = &g_effects[i];
9732+
9733+
if (effect->lilv_instance == NULL)
9734+
continue;
9735+
if (effect->lilv_plugin == NULL)
9736+
continue;
9737+
9738+
if (effect->monitor_cpu)
9739+
effect->monitor_cpu_reset = true;
9740+
}
9741+
96349742
g_postevents_ready = true;
96359743
sem_post(&g_postevents_semaphore);
96369744
}

src/effects.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ int effects_cpu_load_enable(int enable);
203203
int effects_freewheeling_enable(int enable);
204204
int effects_processing_enable(int enable);
205205
int effects_monitor_audio_levels(const char *source_port_name, int enable);
206+
int effects_monitor_cpu_load(int enable, int num_effects, int *effects);
206207
int effects_monitor_midi_control(int channel, int enable);
207208
int effects_monitor_midi_program(int channel, int enable);
208209
void effects_transport(int rolling, double beats_per_bar, double beats_per_minute);

src/mod-host.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,34 @@ static void monitor_audio_levels_cb(proto_t *proto)
431431
protocol_response_int(resp, proto);
432432
}
433433

434+
static void monitor_cpu_load_cb(proto_t *proto)
435+
{
436+
int instance_count = atoi(proto->list[2]);
437+
if (instance_count == 0)
438+
{
439+
protocol_response_int(ERR_ASSIGNMENT_INVALID_OP, proto);
440+
return;
441+
}
442+
443+
int *instances = malloc(sizeof(int) * instance_count);
444+
if (instances != NULL)
445+
{
446+
for (int i = 0; i < instance_count; i++)
447+
instances[i] = atoi(proto->list[3 + i]);
448+
}
449+
else
450+
{
451+
free(instances);
452+
protocol_response_int(ERR_MEMORY_ALLOCATION, proto);
453+
return;
454+
}
455+
456+
int resp = effects_monitor_cpu_load(atoi(proto->list[1]), instance_count, instances);
457+
protocol_response_int(resp, proto);
458+
459+
free(instances);
460+
}
461+
434462
static void monitor_midi_control_cb(proto_t *proto)
435463
{
436464
int resp;
@@ -1157,6 +1185,7 @@ static int mod_host_init(jack_client_t* client, int socket_port, int feedback_po
11571185
protocol_add_command(MONITOR_OUTPUT, monitor_output_cb);
11581186
protocol_add_command(MONITOR_OUTPUT_OFF, monitor_output_off_cb);
11591187
protocol_add_command(MONITOR_AUDIO_LEVELS, monitor_audio_levels_cb);
1188+
protocol_add_command(MONITOR_CPU_LOAD, monitor_cpu_load_cb);
11601189
protocol_add_command(MONITOR_MIDI_CONTROL, monitor_midi_control_cb);
11611190
protocol_add_command(MONITOR_MIDI_PROGRAM, monitor_midi_program_cb);
11621191
protocol_add_command(MIDI_LEARN, midi_learn_cb);

src/mod-host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#define MONITOR_OUTPUT "monitor_output %i %s"
8080
#define MONITOR_OUTPUT_OFF "monitor_output_off %i %s"
8181
#define MONITOR_AUDIO_LEVELS "monitor_audio_levels %i %s"
82+
#define MONITOR_CPU_LOAD "monitor_cpu_load %i %i ..."
8283
#define MONITOR_MIDI_CONTROL "monitor_midi_control %i %i"
8384
#define MONITOR_MIDI_PROGRAM "monitor_midi_program %i %i"
8485
#define MIDI_LEARN "midi_learn %i %s %f %f"

src/utils.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "utils.h"
2626
#include <math.h>
2727
#include <string.h>
28+
#include <time.h>
2829

2930

3031
/*
@@ -244,3 +245,32 @@ char *str_duplicate(const char *str)
244245
strcpy(copy, str);
245246
return copy;
246247
}
248+
249+
250+
#if defined(__ARM_ARCH_8A) && !defined(_MOD_DEVICE_DUOX)
251+
static uint64_t _cntfrq_ratio = 0;
252+
#endif
253+
254+
void time_ns_init()
255+
{
256+
#if defined(__ARM_ARCH_8A) && !defined(_MOD_DEVICE_DUOX)
257+
uint64_t r;
258+
asm volatile("mrs %0, CNTFRQ_EL0" : "=r"(r));
259+
// 1e6 for MHz clock speed, then converted to nano-seconds ratio
260+
_cntfrq_ratio = 1000 / (r / 1e6);
261+
#endif
262+
}
263+
264+
265+
uint64_t time_ns_get()
266+
{
267+
#if defined(__ARM_ARCH_8A) && !defined(_MOD_DEVICE_DUOX)
268+
uint64_t r;
269+
asm volatile("mrs %0, CNTVCT_EL0" : "=r"(r));
270+
return r * _cntfrq_ratio;
271+
#else
272+
struct timespec time;
273+
clock_gettime(CLOCK_MONOTONIC_RAW, &time);
274+
return (uint64_t) time.tv_sec * 1e9 + (uint64_t) time.tv_nsec;
275+
#endif
276+
}

src/utils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ float clampf(float value, float min, float max)
130130
return value < min ? min : (value > max ? max : value);
131131
}
132132

133+
// get time in nanoseconds
134+
void time_ns_init();
135+
uint64_t time_ns_get();
136+
133137

134138
/*
135139
************************************************************************************************************************

0 commit comments

Comments
 (0)