Skip to content

Commit 39578b0

Browse files
committed
Merge branch 'monitor-cpu-load' into pablito
2 parents 6aa546d + df2cdf6 commit 39578b0

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
@@ -305,6 +305,7 @@ enum PostPonedEventType {
305305
POSTPONED_PARAM_SET,
306306
POSTPONED_PARAM_STATE,
307307
POSTPONED_AUDIO_MONITOR,
308+
POSTPONED_CPU_MONITOR,
308309
POSTPONED_OUTPUT_MONITOR,
309310
POSTPONED_MIDI_CONTROL_CHANGE,
310311
POSTPONED_MIDI_PROGRAM_CHANGE,
@@ -467,6 +468,10 @@ typedef struct EFFECT_T {
467468
bool jack_activated;
468469
bool lv2_activated;
469470

471+
bool monitor_cpu;
472+
bool monitor_cpu_reset;
473+
float cpu_load;
474+
470475
// previous transport state
471476
bool transport_rolling;
472477
uint32_t transport_frame;
@@ -644,6 +649,11 @@ typedef struct POSTPONED_AUDIO_MONITOR_EVENT_T {
644649
float value;
645650
} postponed_audio_monitor_event_t;
646651

652+
typedef struct POSTPONED_CPU_MONITOR_EVENT_T {
653+
int effect_id;
654+
float cpu_load;
655+
} postponed_cpu_monitor_event_t;
656+
647657
typedef struct POSTPONED_MIDI_CONTROL_CHANGE_EVENT_T {
648658
int8_t channel;
649659
int8_t control;
@@ -694,6 +704,7 @@ typedef struct POSTPONED_EVENT_T {
694704
postponed_parameter_event_t parameter;
695705
postponed_parameter_state_t state;
696706
postponed_audio_monitor_event_t audio_monitor;
707+
postponed_cpu_monitor_event_t cpu_monitor;
697708
postponed_midi_control_change_event_t control_change;
698709
postponed_midi_program_change_event_t program_change;
699710
postponed_midi_map_event_t midi_map;
@@ -790,7 +801,7 @@ static jack_client_t *g_jack_global_client;
790801
static jack_nframes_t g_sample_rate, g_max_allowed_midi_delta;
791802
static float g_sample_rate_f;
792803
static const char **g_capture_ports, **g_playback_ports;
793-
static int32_t g_midi_buffer_size, g_block_length;
804+
static int32_t g_midi_buffer_size, g_block_length, g_block_time_us;
794805
static int32_t g_thread_policy, g_thread_priority;
795806
#ifdef MOD_IO_PROCESSING_ENABLED
796807
static jack_port_t *g_audio_in1_port;
@@ -1104,6 +1115,7 @@ static void AllocatePortBuffers(effect_t* effect, int in_size, int out_size)
11041115
static int BufferSize(jack_nframes_t nframes, void* data)
11051116
{
11061117
g_block_length = nframes;
1118+
g_block_time_us = nframes * 1e6 / g_sample_rate;
11071119
g_midi_buffer_size = jack_port_type_get_buffer_size(g_jack_global_client, JACK_DEFAULT_MIDI_TYPE);
11081120

11091121
if (data)
@@ -1354,10 +1366,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
13541366
// cached data, to make sure we only handle similar events once
13551367
bool got_midi_program = false;
13561368
bool got_transport = false;
1357-
postponed_cached_effect_events cached_audio_monitor, cached_process_out_buf;
1369+
postponed_cached_effect_events cached_audio_monitor, cached_cpu_monitor, cached_process_out_buf;
13581370
postponed_cached_symbol_events cached_param_set, cached_param_state, cached_output_mon;
13591371

13601372
cached_audio_monitor.last_effect_id = -1;
1373+
cached_cpu_monitor.last_effect_id = -1;
13611374
cached_process_out_buf.last_effect_id = -1;
13621375
cached_param_set.last_effect_id = -1;
13631376
cached_param_set.last_symbol[0] = '\0';
@@ -1369,6 +1382,7 @@ static void RunPostPonedEvents(int ignored_effect_id)
13691382
cached_output_mon.last_symbol[0] = '\0';
13701383
cached_output_mon.last_symbol[MAX_CHAR_BUF_SIZE] = '\0';
13711384
INIT_LIST_HEAD(&cached_audio_monitor.effects.siblings);
1385+
INIT_LIST_HEAD(&cached_cpu_monitor.effects.siblings);
13721386
INIT_LIST_HEAD(&cached_process_out_buf.effects.siblings);
13731387
INIT_LIST_HEAD(&cached_param_set.symbols.siblings);
13741388
INIT_LIST_HEAD(&cached_param_state.symbols.siblings);
@@ -1455,6 +1469,18 @@ static void RunPostPonedEvents(int ignored_effect_id)
14551469
cached_audio_monitor.last_effect_id = eventptr->event.audio_monitor.index;
14561470
break;
14571471

1472+
case POSTPONED_CPU_MONITOR:
1473+
if (ShouldIgnorePostPonedEffectEvent(eventptr->event.audio_monitor.index, &cached_audio_monitor))
1474+
continue;
1475+
1476+
snprintf(buf, FEEDBACK_BUF_SIZE, "cpu_monitor %i %f", eventptr->event.cpu_monitor.effect_id,
1477+
eventptr->event.cpu_monitor.cpu_load);
1478+
socket_send_feedback_debug(buf);
1479+
1480+
// save for fast checkup next time
1481+
cached_cpu_monitor.last_effect_id = eventptr->event.cpu_monitor.effect_id;
1482+
break;
1483+
14581484
case POSTPONED_OUTPUT_MONITOR:
14591485
if (eventptr->event.parameter.effect_id == ignored_effect_id)
14601486
continue;
@@ -1751,6 +1777,11 @@ static void RunPostPonedEvents(int ignored_effect_id)
17511777
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
17521778
free(peffect);
17531779
}
1780+
list_for_each_safe(it, it2, &cached_cpu_monitor.effects.siblings)
1781+
{
1782+
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
1783+
free(peffect);
1784+
}
17541785
list_for_each_safe(it, it2, &cached_process_out_buf.effects.siblings)
17551786
{
17561787
peffect = list_entry(it, postponed_cached_effect_list_data, siblings);
@@ -2073,10 +2104,15 @@ static int ProcessPlugin(jack_nframes_t nframes, void *arg)
20732104
}
20742105

20752106
/* common variables */
2107+
const bool monitor_cpu = effect->monitor_cpu;
20762108
bool needs_post = false;
20772109
const float *buffer_in;
20782110
float *buffer_out;
20792111
float value;
2112+
uint64_t time_start;
2113+
2114+
if (monitor_cpu)
2115+
time_start = time_ns_get();
20802116

20812117
/* transport */
20822118
uint8_t stack_buf[MAX_CHAR_BUF_SIZE+1];
@@ -2618,6 +2654,37 @@ static int ProcessPlugin(jack_nframes_t nframes, void *arg)
26182654
if (effect->hints & HINT_STATE_UNSAFE)
26192655
pthread_mutex_unlock(&effect->state_restore_mutex);
26202656

2657+
if (monitor_cpu)
2658+
{
2659+
if (effect->monitor_cpu_reset)
2660+
{
2661+
effect->cpu_load = 0.f;
2662+
effect->monitor_cpu_reset = false;
2663+
}
2664+
2665+
float cpu_load = ((int32_t)(time_ns_get() - time_start) / g_block_time_us) * 0.001f;
2666+
2667+
if (cpu_load > effect->cpu_load)
2668+
{
2669+
effect->cpu_load = cpu_load;
2670+
2671+
postponed_event_list_data* const posteventptr = rtsafe_memory_pool_allocate_atomic(g_rtsafe_mem_pool);
2672+
2673+
if (posteventptr != NULL)
2674+
{
2675+
posteventptr->event.type = POSTPONED_CPU_MONITOR;
2676+
posteventptr->event.cpu_monitor.effect_id = effect->instance;
2677+
posteventptr->event.cpu_monitor.cpu_load = cpu_load;
2678+
2679+
pthread_mutex_lock(&g_rtsafe_mutex);
2680+
list_add_tail(&posteventptr->siblings, &g_rtsafe_list);
2681+
pthread_mutex_unlock(&g_rtsafe_mutex);
2682+
2683+
needs_post = true;
2684+
}
2685+
}
2686+
}
2687+
26212688
if (needs_post)
26222689
sem_post(&g_postevents_semaphore);
26232690

@@ -4460,6 +4527,8 @@ int effects_init(void* client)
44604527
return ERR_JACK_CLIENT_CREATION;
44614528
}
44624529

4530+
time_ns_init();
4531+
44634532
/* Register jack ports */
44644533
g_midi_in_port = jack_port_register(g_jack_global_client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
44654534

@@ -4531,6 +4600,7 @@ int effects_init(void* client)
45314600
/* Get buffers size */
45324601
g_block_length = jack_get_buffer_size(g_jack_global_client);
45334602
g_sample_rate = jack_get_sample_rate(g_jack_global_client);
4603+
g_block_time_us = g_block_length * 1e6 / g_sample_rate;
45344604
g_sample_rate_f = g_sample_rate;
45354605
g_midi_buffer_size = jack_port_type_get_buffer_size(g_jack_global_client, JACK_DEFAULT_MIDI_TYPE);
45364606
g_max_allowed_midi_delta = (jack_nframes_t)(g_sample_rate * 0.2); // max 200ms of allowed delta
@@ -9512,6 +9582,30 @@ int effects_monitor_audio_levels(const char *source_port_name, int enable)
95129582
return SUCCESS;
95139583
}
95149584

9585+
int effects_monitor_cpu_load(int enable, int num_effects, int *effects)
9586+
{
9587+
if (num_effects <= 0)
9588+
return ERR_INVALID_OPERATION;
9589+
9590+
effect_t *effect;
9591+
9592+
for (int i = 0, effect_id; i < num_effects; i++)
9593+
{
9594+
effect_id = effects[i];
9595+
if (InstanceExist(effect_id))
9596+
{
9597+
effect = &g_effects[effect_id];
9598+
9599+
if (enable != 0)
9600+
effect->monitor_cpu_reset = true;
9601+
9602+
effect->monitor_cpu = enable != 0;
9603+
}
9604+
}
9605+
9606+
return SUCCESS;
9607+
}
9608+
95159609
int effects_monitor_midi_control(int channel, int enable)
95169610
{
95179611
if (channel < 0 || channel > 15)
@@ -9676,6 +9770,20 @@ void effects_output_data_ready(void)
96769770

96779771
if (! g_postevents_ready)
96789772
{
9773+
// recalculate max cpu usage again
9774+
for (int i = 0; i < MAX_PLUGIN_INSTANCES; ++i)
9775+
{
9776+
effect_t *effect = &g_effects[i];
9777+
9778+
if (effect->lilv_instance == NULL)
9779+
continue;
9780+
if (effect->lilv_plugin == NULL)
9781+
continue;
9782+
9783+
if (effect->monitor_cpu)
9784+
effect->monitor_cpu_reset = true;
9785+
}
9786+
96799787
g_postevents_ready = true;
96809788
sem_post(&g_postevents_semaphore);
96819789
}

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)