mirror of
https://github.com/Klipper3d/klipper.git
synced 2025-10-26 07:46:11 +01:00
stepcompress: Generate steps in a per-stepper background thread
Create a thread for each stepper and use it for step generation and step compression. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
@@ -36,7 +36,7 @@ defs_stepcompress = """
|
||||
int step_count, interval, add;
|
||||
};
|
||||
|
||||
struct stepcompress *stepcompress_alloc(uint32_t oid);
|
||||
struct stepcompress *stepcompress_alloc(uint32_t oid, char name[16]);
|
||||
void stepcompress_fill(struct stepcompress *sc, uint32_t max_error
|
||||
, int32_t queue_step_msgtag, int32_t set_next_step_dir_msgtag);
|
||||
void stepcompress_set_invert_sdir(struct stepcompress *sc
|
||||
@@ -66,10 +66,11 @@ defs_steppersync = """
|
||||
void steppersync_free(struct steppersync *ss);
|
||||
void steppersync_set_time(struct steppersync *ss
|
||||
, double time_offset, double mcu_freq);
|
||||
int32_t steppersync_generate_steps(struct steppersync *ss
|
||||
, double gen_steps_time, uint64_t flush_clock);
|
||||
void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock);
|
||||
int steppersync_flush(struct steppersync *ss, uint64_t move_clock);
|
||||
void steppersync_start_gen_steps(struct steppersync *ss
|
||||
, double gen_steps_time, uint64_t flush_clock);
|
||||
int32_t steppersync_finalize_gen_steps(struct steppersync *ss
|
||||
, uint64_t flush_clock);
|
||||
"""
|
||||
|
||||
defs_itersolve = """
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// efficiency - the repetitive integer math is vastly faster in C.
|
||||
|
||||
#include <math.h> // sqrt
|
||||
#include <pthread.h> // pthread_mutex_lock
|
||||
#include <stddef.h> // offsetof
|
||||
#include <stdint.h> // uint32_t
|
||||
#include <stdio.h> // fprintf
|
||||
@@ -47,8 +48,16 @@ struct stepcompress {
|
||||
// History tracking
|
||||
int64_t last_position;
|
||||
struct list_head history_list;
|
||||
// Itersolve reference
|
||||
// Thread for step generation
|
||||
struct stepper_kinematics *sk;
|
||||
char name[16];
|
||||
pthread_t tid;
|
||||
pthread_mutex_t lock; // protects variables below
|
||||
pthread_cond_t cond;
|
||||
int have_work;
|
||||
double bg_gen_steps_time;
|
||||
uint64_t bg_flush_clock;
|
||||
int32_t bg_result;
|
||||
};
|
||||
|
||||
struct step_move {
|
||||
@@ -244,9 +253,12 @@ check_line(struct stepcompress *sc, struct step_move move)
|
||||
* Step compress interface
|
||||
****************************************************************/
|
||||
|
||||
static int sc_thread_alloc(struct stepcompress *sc, char name[16]);
|
||||
static void sc_thread_free(struct stepcompress *sc);
|
||||
|
||||
// Allocate a new 'stepcompress' object
|
||||
struct stepcompress * __visible
|
||||
stepcompress_alloc(uint32_t oid)
|
||||
stepcompress_alloc(uint32_t oid, char name[16])
|
||||
{
|
||||
struct stepcompress *sc = malloc(sizeof(*sc));
|
||||
memset(sc, 0, sizeof(*sc));
|
||||
@@ -254,6 +266,10 @@ stepcompress_alloc(uint32_t oid)
|
||||
list_init(&sc->history_list);
|
||||
sc->oid = oid;
|
||||
sc->sdir = -1;
|
||||
|
||||
int ret = sc_thread_alloc(sc, name);
|
||||
if (ret)
|
||||
return NULL;
|
||||
return sc;
|
||||
}
|
||||
|
||||
@@ -299,6 +315,7 @@ stepcompress_free(struct stepcompress *sc)
|
||||
{
|
||||
if (!sc)
|
||||
return;
|
||||
sc_thread_free(sc);
|
||||
free(sc->queue);
|
||||
message_queue_free(&sc->msg_queue);
|
||||
stepcompress_history_expire(sc, UINT64_MAX);
|
||||
@@ -666,6 +683,11 @@ stepcompress_extract_old(struct stepcompress *sc, struct pull_history_steps *p
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Step generation thread
|
||||
****************************************************************/
|
||||
|
||||
// Store a reference to stepper_kinematics
|
||||
void __visible
|
||||
stepcompress_set_stepper_kinematics(struct stepcompress *sc
|
||||
@@ -682,7 +704,7 @@ stepcompress_get_stepper_kinematics(struct stepcompress *sc)
|
||||
}
|
||||
|
||||
// Generate steps (via itersolve) and flush
|
||||
int32_t
|
||||
static int32_t
|
||||
stepcompress_generate_steps(struct stepcompress *sc, double gen_steps_time
|
||||
, uint64_t flush_clock)
|
||||
{
|
||||
@@ -695,3 +717,96 @@ stepcompress_generate_steps(struct stepcompress *sc, double gen_steps_time
|
||||
// Flush steps
|
||||
return stepcompress_flush(sc, flush_clock);
|
||||
}
|
||||
|
||||
// Main background thread for generating steps
|
||||
static void *
|
||||
sc_background_thread(void *data)
|
||||
{
|
||||
struct stepcompress *sc = data;
|
||||
set_thread_name(sc->name);
|
||||
|
||||
pthread_mutex_lock(&sc->lock);
|
||||
for (;;) {
|
||||
if (!sc->have_work) {
|
||||
pthread_cond_wait(&sc->cond, &sc->lock);
|
||||
continue;
|
||||
}
|
||||
if (sc->have_work < 0)
|
||||
// Exit request
|
||||
break;
|
||||
|
||||
// Request to generate steps
|
||||
sc->bg_result = stepcompress_generate_steps(sc, sc->bg_gen_steps_time
|
||||
, sc->bg_flush_clock);
|
||||
sc->have_work = 0;
|
||||
pthread_cond_signal(&sc->cond);
|
||||
}
|
||||
pthread_mutex_unlock(&sc->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Signal background thread to start step generation
|
||||
void
|
||||
stepcompress_start_gen_steps(struct stepcompress *sc, double gen_steps_time
|
||||
, uint64_t flush_clock)
|
||||
{
|
||||
if (!sc->sk)
|
||||
return;
|
||||
pthread_mutex_lock(&sc->lock);
|
||||
while (sc->have_work)
|
||||
pthread_cond_wait(&sc->cond, &sc->lock);
|
||||
sc->bg_gen_steps_time = gen_steps_time;
|
||||
sc->bg_flush_clock = flush_clock;
|
||||
sc->have_work = 1;
|
||||
pthread_mutex_unlock(&sc->lock);
|
||||
pthread_cond_signal(&sc->cond);
|
||||
}
|
||||
|
||||
// Wait for background thread to complete last step generation request
|
||||
int32_t
|
||||
stepcompress_finalize_gen_steps(struct stepcompress *sc)
|
||||
{
|
||||
pthread_mutex_lock(&sc->lock);
|
||||
while (sc->have_work)
|
||||
pthread_cond_wait(&sc->cond, &sc->lock);
|
||||
int32_t res = sc->bg_result;
|
||||
pthread_mutex_unlock(&sc->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Internal helper to start thread
|
||||
static int
|
||||
sc_thread_alloc(struct stepcompress *sc, char name[16])
|
||||
{
|
||||
strncpy(sc->name, name, sizeof(sc->name));
|
||||
sc->name[sizeof(sc->name)-1] = '\0';
|
||||
int ret = pthread_mutex_init(&sc->lock, NULL);
|
||||
if (ret)
|
||||
goto fail;
|
||||
ret = pthread_cond_init(&sc->cond, NULL);
|
||||
if (ret)
|
||||
goto fail;
|
||||
ret = pthread_create(&sc->tid, NULL, sc_background_thread, sc);
|
||||
if (ret)
|
||||
goto fail;
|
||||
return 0;
|
||||
fail:
|
||||
report_errno("sc init", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Request background thread to exit
|
||||
static void
|
||||
sc_thread_free(struct stepcompress *sc)
|
||||
{
|
||||
pthread_mutex_lock(&sc->lock);
|
||||
while (sc->have_work)
|
||||
pthread_cond_wait(&sc->cond, &sc->lock);
|
||||
sc->have_work = -1;
|
||||
pthread_cond_signal(&sc->cond);
|
||||
pthread_mutex_unlock(&sc->lock);
|
||||
int ret = pthread_join(sc->tid, NULL);
|
||||
if (ret)
|
||||
report_errno("sc pthread_join", ret);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ struct pull_history_steps {
|
||||
int step_count, interval, add;
|
||||
};
|
||||
|
||||
struct stepcompress *stepcompress_alloc(uint32_t oid);
|
||||
struct stepcompress *stepcompress_alloc(uint32_t oid, char name[16]);
|
||||
void stepcompress_fill(struct stepcompress *sc, uint32_t max_error
|
||||
, int32_t queue_step_msgtag
|
||||
, int32_t set_next_step_dir_msgtag);
|
||||
@@ -43,8 +43,8 @@ void stepcompress_set_stepper_kinematics(struct stepcompress *sc
|
||||
, struct stepper_kinematics *sk);
|
||||
struct stepper_kinematics *stepcompress_get_stepper_kinematics(
|
||||
struct stepcompress *sc);
|
||||
int32_t stepcompress_generate_steps(struct stepcompress *sc
|
||||
, double gen_steps_time
|
||||
, uint64_t flush_clock);
|
||||
void stepcompress_start_gen_steps(struct stepcompress *sc, double gen_steps_time
|
||||
, uint64_t flush_clock);
|
||||
int32_t stepcompress_finalize_gen_steps(struct stepcompress *sc);
|
||||
|
||||
#endif // stepcompress.h
|
||||
|
||||
@@ -76,22 +76,6 @@ steppersync_set_time(struct steppersync *ss, double time_offset
|
||||
}
|
||||
}
|
||||
|
||||
// Generate steps and flush stepcompress objects
|
||||
int32_t __visible
|
||||
steppersync_generate_steps(struct steppersync *ss, double gen_steps_time
|
||||
, uint64_t flush_clock)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<ss->sc_num; i++) {
|
||||
struct stepcompress *sc = ss->sc_list[i];
|
||||
int32_t ret = stepcompress_generate_steps(sc, gen_steps_time
|
||||
, flush_clock);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Expire the stepcompress history before the given clock time
|
||||
void __visible
|
||||
steppersync_history_expire(struct steppersync *ss, uint64_t end_clock)
|
||||
@@ -129,7 +113,7 @@ heap_replace(struct steppersync *ss, uint64_t req_clock)
|
||||
}
|
||||
|
||||
// Find and transmit any scheduled steps prior to the given 'move_clock'
|
||||
int __visible
|
||||
static void
|
||||
steppersync_flush(struct steppersync *ss, uint64_t move_clock)
|
||||
{
|
||||
// Order commands by the reqclock of each pending command
|
||||
@@ -172,6 +156,34 @@ steppersync_flush(struct steppersync *ss, uint64_t move_clock)
|
||||
// Transmit commands
|
||||
if (!list_empty(&msgs))
|
||||
serialqueue_send_batch(ss->sq, ss->cq, &msgs);
|
||||
}
|
||||
|
||||
// Start generating steps in stepcompress objects
|
||||
void __visible
|
||||
steppersync_start_gen_steps(struct steppersync *ss, double gen_steps_time
|
||||
, uint64_t flush_clock)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<ss->sc_num; i++) {
|
||||
struct stepcompress *sc = ss->sc_list[i];
|
||||
stepcompress_start_gen_steps(sc, gen_steps_time, flush_clock);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize step generation and flush
|
||||
int32_t __visible
|
||||
steppersync_finalize_gen_steps(struct steppersync *ss, uint64_t flush_clock)
|
||||
{
|
||||
int i;
|
||||
int32_t res = 0;
|
||||
for (i=0; i<ss->sc_num; i++) {
|
||||
struct stepcompress *sc = ss->sc_list[i];
|
||||
int32_t ret = stepcompress_finalize_gen_steps(sc);
|
||||
if (ret)
|
||||
res = ret;
|
||||
}
|
||||
if (res)
|
||||
return res;
|
||||
steppersync_flush(ss, flush_clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@ struct steppersync *steppersync_alloc(
|
||||
void steppersync_free(struct steppersync *ss);
|
||||
void steppersync_set_time(struct steppersync *ss, double time_offset
|
||||
, double mcu_freq);
|
||||
int32_t steppersync_generate_steps(struct steppersync *ss, double gen_steps_time
|
||||
, uint64_t flush_clock);
|
||||
void steppersync_history_expire(struct steppersync *ss, uint64_t end_clock);
|
||||
int steppersync_flush(struct steppersync *ss, uint64_t move_clock);
|
||||
void steppersync_start_gen_steps(struct steppersync *ss, double gen_steps_time
|
||||
, uint64_t flush_clock);
|
||||
int32_t steppersync_finalize_gen_steps(struct steppersync *ss
|
||||
, uint64_t flush_clock);
|
||||
|
||||
#endif // steppersync.h
|
||||
|
||||
Reference in New Issue
Block a user