Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions docs/src/config/core-components.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,8 @@ change or removal at any time.
* 'motion.debug-float-3' - (float, RO) This is used for debugging purposes.
* 'motion.debug-s32-0' - (s32, RO) This is used for debugging purposes.
* 'motion.debug-s32-1' - (s32, RO) This is used for debugging purposes.
* 'motion.servo.last-period' - (u32, RO) The number of CPU cycles between invocations of the servo thread.
Typically, this number divided by the CPU speed gives the time in seconds,
and can be used to determine whether the realtime motion controller is meeting its timing constraints
* 'motion.servo.last-period-ns' - (float, RO)
* 'motion.servo.last-period' - (u32, RO) The time in ns between invocations of the servo thread.
This number can be used to determine whether the realtime motion controller is meeting its timing constraints

=== Functions

Expand Down
9 changes: 5 additions & 4 deletions docs/src/hal/basic-hal.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -373,12 +373,13 @@ If you used the Stepper Config Wizard to generate your config you will have up t
== HAL Parameter

(((HAL Parameters)))
Two parameters are automatically added to each HAL component when it is created.
These parameters allow you to scope the execution time of a component.
One pin and two parameters are automatically added to each HAL component when it is created.
These allow you to scope the execution time of a component.

[horizontal]
`.time`(((HAL time))):: Time is the number of CPU cycles it took to execute the function.
`.tmax`(((HAL tmax))):: Tmax is the maximum number of CPU cycles it took to execute the function.
`.time`(((HAL time))):: Pin time shows in ns how long it took to execute the function.
`.tmax`(((HAL tmax))):: Parameter tmax is the maximum time in ns it took to execute the function.
`.tmax-increased`(((HAL tmax-increased))):: This parameter is set to true for one cycle if tmax increased.

`tmax` is a read/write parameter so the user can set it to 0 to get rid of the first time initialization on the function's execution time.

Expand Down
1 change: 0 additions & 1 deletion docs/src/hal/components.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,6 @@ rtapi_clock_set_period.3
rtapi_delay.3
rtapi_delay_max.3
rtapi_exit.3
rtapi_get_clocks.3
rtapi_get_msg_level.3
rtapi_get_time.3
rtapi_inb.3
Expand Down
43 changes: 3 additions & 40 deletions docs/src/man/man3/rtapi_get_time.3.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

== NAME

rtapi_get_time, rtapi_get_clocks - get the current time
rtapi_get_time - get the current time in ns

== SYNTAX

[source,c]
----
long long rtapi_get_time();
long long rtapi_get_clocks();
----

== DESCRIPTION
Expand All @@ -25,55 +24,19 @@ resolution of the returned value may be as good as one nano-second, or
as poor as several microseconds. May be called from init/cleanup code,
and from within realtime tasks.

*rtapi_get_clocks* returns the current time in CPU clocks. It is fast,
since it just reads the TSC in the CPU instead of calling a kernel or
RTOS function. Of course, times measured in CPU clocks are not as
convenient, but for relative measurements this works fine. Its absolute
value means nothing, but it is monotonically increasing and can be used
to schedule future events, or to time the duration of some activity. (On
SMP machines, the two TSC's may get out of sync, so if a task reads the
TSC, gets swapped to the other CPU, and reads again, the value may
decrease. RTAPI tries to force all RT tasks to run on one CPU.) Returns
a 64 bit value. The resolution of the returned value is one CPU clock,
which is usually a few nanoseconds to a fraction of a nanosecond. Note
that _long long_ math may be poorly supported on some platforms,
especially in kernel space. Also note that rtapi_print() will NOT print
__long long__s. Most time measurements are relative, and should be done
like this:

[source,c]
----
deltat = (long int)(end_time - start_time);
----

where end_time and start_time are longlong values returned from
rtapi_get_time, and deltat is an ordinary long int (32 bits). This will
work for times up to a second or so, depending on the CPU clock
frequency. It is best used for millisecond and microsecond scale
work for times up to 2.1s. It is best used for millisecond and microsecond scale
measurements though.

== RETURN VALUE

Returns the current time in nanoseconds or CPU clocks.

== NOTES

Certain versions of the Linux kernel provide a global variable *cpu_khz*. Computing

[source,c]
----
deltat = (end_clocks - start_clocks) / cpu_khz:
----

gives the duration measured in milliseconds. Computing

[source,c]
----
deltat = (end_clocks - start_clocks) * 1000000 / cpu_khz:
----

gives the duration measured in nanoseconds for deltas less than about 9
trillion clocks (e.g., 3000 seconds at 3 GHz).
Returns the current time in nanoseconds.

== REALTIME CONSIDERATIONS

Expand Down
2 changes: 1 addition & 1 deletion docs/src/man/man9/encoder.9.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ The *encoder*.__N__. format is shown in the following descriptions.
for counting the output of a single channel (non-quadrature) sensor.
When false (the default), it counts in quadrature mode.
**encoder**.__N__.**capture-position.tmax** s32 rw::
Maximum number of CPU cycles it took to execute this function.
Maximum time in ns it took to execute this function.

== PARAMETERS

Expand Down
10 changes: 5 additions & 5 deletions docs/src/man/man9/motion.9.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ digital pins and two analog pins.
== MOTION PINS

*motion-command-handler.time* OUT S32::
Time (in CPU clocks) for the motion module motion-command-handler
Time (in ns) for the motion module motion-command-handler
*motion-controller.time* OUT S32::
Time (in CPU clocks) for the motion module motion-controller
Time (in ns) for the motion module motion-controller
*motion.adaptive-feed* IN FLOAT::
When adaptive feed is enabled with M52 P1, the commanded velocity is
multiplied by this value. This effect is multiplicative with the
Expand Down Expand Up @@ -246,7 +246,7 @@ Note: feed-inhibit applies to G-code commands -- not jogs.
possibly reduced to accommodate machine velocity and acceleration limits.
The value on this pin does not reflect the feed override or any other adjustments.
*motion.servo.last-period* OUT U32::
The number of CPU clocks between invocations of the servo thread.
Time (in ns) between invocations of the servo thread.
Typically, this number divided by the CPU speed gives the time in seconds,
and can be used to determine whether the realtime motion
controller is meeting its timing constraints
Expand Down Expand Up @@ -544,12 +544,12 @@ the M19 command fails with an error message.
Many of the parameters serve as debugging aids, and are subject to change or removal at any time.

*motion-command-handler.tmax* RW S32::
Show information about the execution time of these HAL functions in CPU clocks.
Show information about the execution time of these HAL functions in ns.

*motion-command-handler.tmax-increased* RO S32::

*motion-controller.tmax* RW S32::
Show information about the execution time of these HAL functions in CPU clocks.
Show information about the execution time of these HAL functions in ns.

*motion-controller.tmax-increased* RO BIT::
+
Expand Down
5 changes: 1 addition & 4 deletions src/emc/motion/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,9 @@ void emcmotController(void *arg, long period)

static long long int last = 0;

long long int now = rtapi_get_clocks();
long long int now = rtapi_get_time();
long int this_run = (long int)(now - last);
*(emcmot_hal_data->last_period) = this_run;
#ifdef HAVE_CPU_KHZ
*(emcmot_hal_data->last_period_ns) = this_run * 1e6 / cpu_khz;
#endif

// we need this for next time
last = now;
Expand Down
7 changes: 1 addition & 6 deletions src/emc/motion/mot_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,7 @@ typedef struct {
hal_float_t tc_acc[4]; /* RPA: traj internals, for debugging */

// realtime overrun detection
hal_u32_t *last_period; /* pin: last period in clocks */
hal_float_t *last_period_ns; /* pin: last period in nanoseconds */
hal_u32_t *last_period; /* pin: last period in nanoseconds */

hal_float_t *tooloffset_x;
hal_float_t *tooloffset_y;
Expand Down Expand Up @@ -348,8 +347,4 @@ int joint_is_lockable(int joint_num);

#define SET_JOINT_FAULT_FLAG(joint,fl) if (fl) (joint)->flag |= EMCMOT_JOINT_FAULT_BIT; else (joint)->flag &= ~EMCMOT_JOINT_FAULT_BIT;

#if defined(__KERNEL__)
#define HAVE_CPU_KHZ
#endif

#endif /* MOT_PRIV_H */
3 changes: 0 additions & 3 deletions src/emc/motion/motion.c
Original file line number Diff line number Diff line change
Expand Up @@ -593,9 +593,6 @@ static int init_hal_io(void)

// export timing related HAL pins so they can be scoped and/or connected
CALL_CHECK(hal_pin_u32_newf(HAL_OUT, &(emcmot_hal_data->last_period), mot_comp_id, "motion.servo.last-period"));
#ifdef HAVE_CPU_KHZ
CALL_CHECK(hal_pin_float_newf(HAL_OUT, &(emcmot_hal_data->last_period_ns), mot_comp_id, "motion.servo.last-period-ns"));
#endif
Comment on lines -596 to -598
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this could be a problem. Or, is nobody using it internally or externally?

Or, if the define HAVE_CPU_KHZ is not generally available, then it it would be a non-consistent pin and can/should be dealt with in some way.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HAVE_CPU_KHZ was only defined with RTAI: https://github.com/LinuxCNC/linuxcnc/blob/master/src/emc/motion/mot_priv.h#L352

I removed it all together. I grep'ed the repo for last_period_ns, no hits except the two I removed. If someone uses it with RTAI in his .hal file, he can change to use the pin last_period which was in clocks and is now in ns.

The change from clocks to ns for the .time / .last_period might confuse some users but I somewhat expect that most users expected these signals to be in ns. But they where in tsc clocks before this PR.

Is there any reference in the doc about this .time pin's? I did not find anything the last time I searched it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The (small) catch is that last-period is integer and last-period-ns is floating point.

The pins are (wrongly) documented as parameters in docs/src/config/core-components.adoc in line 173-176.

There may be some history here to this pin/param confusion that may need some investigation. Commit 2b22052 in 2017 changed both from params to pins.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah of course, i grepped for last_period instead of last-period. There are only occurrences in the doc's, nowhere in code or hal files. I fixed the doc for this pin.

However, I am completely new to adoc / po translations. Is there any way to update the .po files in an automated way?

Thanks for the link. I did not even know hal-histogram exists. This commit was mainly about converting motion.servo.last-period from a parameter to a pin. motion.servo.last-period-ns was added but it works only with RTAI. Probably it was added as float, so the division by cpu_khz is straight forward. The other time pins are in s32.

I tested hal-histogram motion.servo.last-period which works. However, hal-histogram is quite slow in updating and doesn't scale nicely. Just to test, I changed the pin to float, same issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the right config, it works fine:
grafik

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I am completely new to adoc / po translations. Is there any way to update the .po files in an automated way?

Translations are done in weblate and they are synced once in a while. Just write text in English in the source adoc and they will be marked in weblate that they need attention for translation.

I tested hal-histogram motion.servo.last-period which works. However, hal-histogram is quite slow in updating and doesn't scale nicely. Just to test, I changed the pin to float, same issue.

The slowness of the histogram is how data is taken out of RT into non-RT. It sets an index to read the +/- binnumber[index] and that takes at least 1 thread cycle per bin. So, for +/- 200 bins it takes 0.2 seconds (on a 1kHz thread), just to get the data out (and it is race-tainted data). Actually, the delay is set default at 10 ms and then takes 2 seconds to get the data out.

There is work in progress to fix these histogram programs (none of them work on systems with Tcl9).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so it should be fine then. Just some help needed from others for testing.
@grandixximo fixed already the latency-histogram as I remember. It works perfectly now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only fixed the UI, @BsAtHome actually did the rework on the Hal component, credit goes to him for the response improvement 😁


// export timing related HAL pins so they can be scoped
CALL_CHECK(hal_pin_float_newf(HAL_OUT, &(emcmot_hal_data->tooloffset_x), mot_comp_id, "motion.tooloffset.x"));
Expand Down
17 changes: 3 additions & 14 deletions src/hal/drivers/hal_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ MODULE_AUTHOR("Andy Pugh");
MODULE_DESCRIPTION("GPIO driver using gpiod / libgpiod");
MODULE_LICENSE("GPL");

static unsigned long ns2tsc_factor;
#define ns2tsc(x) (((x) * (unsigned long long)ns2tsc_factor) >> 12)

// There isn't really any limit except for in the MP_ARRAY macros.
#define MAX_CHAN 128

Expand Down Expand Up @@ -358,14 +355,6 @@ int rtapi_app_main(void){
const char *line_name;

rtapi_print_msg(RTAPI_MSG_INFO, "Libgpiod is %i\n", LIBGPIOD_VER);

#ifdef __KERNEL__
// this calculation fits in a 32-bit unsigned
// as long as CPUs are under about 6GHz
ns2tsc_factor = (cpu_khz << 6) / 15625ul;
#else
ns2tsc_factor = 1ll<<12;
#endif

comp_id = hal_init("hal_gpio");
if (comp_id < 0) {
Expand Down Expand Up @@ -520,7 +509,7 @@ static void hal_gpio_write(void *arg, __attribute__((unused)) long period)
#endif
}
// store the time (in CPU clocks) for the reset function
last_reset = rtapi_get_clocks();
last_reset = rtapi_get_time();
}

static void hal_gpio_reset(void *arg, long period)
Expand All @@ -537,8 +526,8 @@ static void hal_gpio_reset(void *arg, long period)
}
}
if (*gpio->reset_ns > period/4) *gpio->reset_ns = period/4;
deadline = last_reset + ns2tsc(*gpio->reset_ns);
while(rtapi_get_clocks() < deadline) {} // busy-wait!
deadline = last_reset + *gpio->reset_ns;
while(rtapi_get_time() < deadline) {} // busy-wait!
#if LIBGPIOD_VER > 200
gpiod_line_request_set_values(gpio->out_chips[c].lines, gpio->out_chips[c].vals);
#else
Expand Down
27 changes: 7 additions & 20 deletions src/hal/drivers/hal_parport.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ static parport_t *port_data_array;
static int comp_id; /* component ID */
static int num_ports; /* number of ports configured */

static unsigned long ns2tsc_factor;
#define ns2tsc(x) (((x) * (unsigned long long)ns2tsc_factor) >> 12)

/***********************************************************************
* LOCAL FUNCTION DECLARATIONS *
************************************************************************/
Expand Down Expand Up @@ -199,15 +196,6 @@ int rtapi_app_main(void)
char *argv[MAX_TOK];
int n, retval;


#ifdef __KERNEL__
// this calculation fits in a 32-bit unsigned
// as long as CPUs are under about 6GHz
ns2tsc_factor = (cpu_khz << 6) / 15625ul;
#else
ns2tsc_factor = 1ll<<12;
#endif

/* test for config string */
if (cfg == 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "PARPORT: ERROR: no config string\n");
Expand Down Expand Up @@ -359,24 +347,23 @@ static void read_port(void *arg, long period)

static void reset_port(void *arg, long period) {
parport_t *port = arg;
long long deadline, reset_time_tsc;
long long deadline;
unsigned char outdata = (unsigned char)((port->outdata&~port->reset_mask) ^ port->reset_val);

if(port->reset_time > period/4) port->reset_time = period/4;
reset_time_tsc = ns2tsc(port->reset_time);

if(outdata != port->outdata) {
deadline = port->write_time + reset_time_tsc;
while(rtapi_get_clocks() < deadline) {}
deadline = port->write_time + port->reset_time;
while(rtapi_get_time() < deadline) {}
rtapi_outb(outdata, port->base_addr);
port->outdata = outdata;
}

outdata = (unsigned char)((port->outdata_ctrl&~port->reset_mask_ctrl)^port->reset_val_ctrl);

if(outdata != port->outdata_ctrl) {
deadline = port->write_time_ctrl + reset_time_tsc;
while(rtapi_get_clocks() < deadline) {}
deadline = port->write_time_ctrl + port->reset_time;
while(rtapi_get_time() < deadline) {}
/* correct for hardware inverters on pins 1, 14, & 17 */
rtapi_outb(outdata ^ 0x0B, port->base_addr + 2);
port->outdata_ctrl = outdata;
Expand Down Expand Up @@ -416,7 +403,7 @@ static void write_port(void *arg, long period)
{
/* write it to the hardware */
rtapi_outb(outdata, port->base_addr);
port->write_time = rtapi_get_clocks();
port->write_time = rtapi_get_time();
port->outdata = outdata;
}
port->reset_val = reset_val;
Expand Down Expand Up @@ -457,7 +444,7 @@ static void write_port(void *arg, long period)
/* write it to the hardware */
/* correct for hardware inverters on pins 1, 14, & 17 */
rtapi_outb(outdata ^ 0x0B, port->base_addr + 2);
port->write_time_ctrl = rtapi_get_clocks();
port->write_time_ctrl = rtapi_get_time();
port->outdata_ctrl = outdata;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/hal/drivers/mesa-hostmot2/hm2_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -808,11 +808,11 @@ static int eth_socket_recv(int sockfd, void *buffer, int len, int flags) {
}

static int eth_socket_recv_loop(int sockfd, void *buffer, int len, int flags, long timeout) {
long long end = rtapi_get_clocks() + timeout;
long long end = rtapi_get_time() + timeout;
int result;
do {
result = eth_socket_recv(sockfd, buffer, len, flags);
} while(result < 0 && rtapi_get_clocks() < end);
} while(result < 0 && rtapi_get_time() < end);
return result;
}

Expand Down
4 changes: 2 additions & 2 deletions src/hal/hal_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -3187,15 +3187,15 @@ static void thread_task(void *arg)
funct_root = (hal_funct_entry_t *) & (thread->funct_list);
funct_entry = SHMPTR(funct_root->links.next);
/* execution time logging */
start_time = rtapi_get_clocks();
start_time = rtapi_get_time();
end_time = start_time;
thread_start_time = start_time;
/* run thru function list */
while (funct_entry != funct_root) {
/* call the function */
funct_entry->funct(funct_entry->arg, thread->period);
/* capture execution time */
end_time = rtapi_get_clocks();
end_time = rtapi_get_time();
/* point to function structure */
funct = SHMPTR(funct_entry->funct_ptr);
/* update execution time data */
Expand Down
4 changes: 2 additions & 2 deletions src/hal/hal_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,8 @@ struct hal_thread_t {
long int period; /* period of the thread, in nsec */
int priority; /* priority of the thread */
int task_id; /* ID of the task that runs this thread */
hal_s32_t* runtime; /* (pin) duration of last run, in CPU cycles */
hal_s32_t maxtime; /* (param) duration of longest run, in CPU cycles */
hal_s32_t* runtime; /* (pin) duration of last run, in ns */
hal_s32_t maxtime; /* (param) duration of longest run, in ns */
hal_list_t funct_list; /* list of functions to run */
hal_list_t init_funct_list; /* list of init functions, run once before first cyclic cycle */
int init_done; /* 0 = init pending, 1 = init cycle has executed */
Expand Down
19 changes: 0 additions & 19 deletions src/rtapi/rtai_rtapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -527,24 +527,6 @@ long long int rtapi_get_time(void)
return rt_get_cpu_time_ns();
}

/* This returns a result in clocks instead of nS, and needs to be used
with care around CPUs that change the clock speed to save power and
other disgusting, non-realtime oriented behavior. But at least it
doesn't take a week every time you call it.
*/

long long int rtapi_get_clocks(void)
{
long long int retval;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
retval = rdtsc_ordered();
#else
rdtscll(retval);
#endif
return retval;
}

void rtapi_delay(long int nsec)
{
if (nsec > max_delay) {
Expand Down Expand Up @@ -1731,7 +1713,6 @@ EXPORT_SYMBOL(rtapi_set_msg_handler);
EXPORT_SYMBOL(rtapi_get_msg_handler);
EXPORT_SYMBOL(rtapi_clock_set_period);
EXPORT_SYMBOL(rtapi_get_time);
EXPORT_SYMBOL(rtapi_get_clocks);
EXPORT_SYMBOL(rtapi_delay);
EXPORT_SYMBOL(rtapi_delay_max);
EXPORT_SYMBOL(rtapi_prio_highest);
Expand Down
Loading
Loading