hrtimer repeating task in the Linux kernel - timer

My goal is to create a recurring task in the linux kernel using the hrtimer struct. I would like it to recur every 500 ms.
However, I'm a little confused about how hrtimer works in the linux kernel (see linux/hrtimer.h). I know that the time is specified, and the callback should return either HRTIMER_RESTART or HRTIMER_NORESTART. I've found some sources online that state that the timer needs to be reset in the callback using the hrtimer_forward method. However, the sources I've seen are a little unclear on how adding the time works. Here's the code I have so far:
static struct hrtimer timer;
static enum hrtimer_restart timer_callback(struct hrtimer *timer)
{
printk(KERN_ERR "Callback\n");
//I know something needs to go here to reset the timer
return HRTIMER_RESTART;
}
static int init_timer(void)
{
ktime_t ktime;
unsigned long delay_in_ms = 500L;
printk(KERN_ERR "Timer being set up\n");
ktime = ktime_set(0,delay_in_ms*1E6L);
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
timer.function = &timer_callback;
printk(KERN_ERR "Timer starting to fire\n");
printk(KERN_ERR "in %ldms %ld\n", delay_in_ms, jiffies);
hrtimer_start(&timer, ktime, HRTIMER_MODE_REL);
return 0;
}
static void clean_load_balancing_timer(void)
{
int cancelled = hrtimer_cancel(&timer);
if (cancelled)
printk(KERN_ERR "Timer still running\n");
else
printk(KERN_ERR "Timer cancelled\n");
}
Can someone explain exactly how resetting the timer would work in the callback function? Thanks!

If you look in kernel/sched.c around line 170 in the function sched_rt_period_timer, you will see an example usage. The essential lines are
now = hrtimer_cb_get_time(timer);
overrun = hrtimer_forward(timer, now, rt_b->rt_period);
Now get's the timer's current time as a ktime_t and rt_b->rt_period is another ktime_t specifying the period at which to advance timer. The expiration time of the hrtimer will be continuously incremented by the period until it is greater than the current time. If it took more than one addition of the period to get the expiration time greater than the current time, the return value will greater than 1 (indicating more overrruns). It can be zero, if the timer expire didn't get advanced at all.
Reference: http://lwn.net/Articles/167897/
The API it uses is from a different version of the kernel so some of the arguments have changed. The basic idea is still the same.

Below is the simple solution,
#include <linux/slab.h>
#include <linux/time.h>
#include <asm/string.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#define NSEC_PER_MSEC 1000000L
static struct hrtimer hr_timer;
enum hrtimer_restart enHRTimer=HRTIMER_NORESTART;
s64 i64TimeInNsec = 500 * NSEC_PER_MSEC;
enum hrtimer_restart my_hrtimer_callback( struct hrtimer *timer )
{
hrtimer_forward(timer,hrtimer_cb_get_time(timer),ktime_set(0,i64TimeInNsec));
return enHRTimer;
}
void hrtimer_event_init_module(void)
{
ktime_t kt;
enHRTimer = HRTIMER_RESTART;
//HRT init
kt = ktime_set(0, i64TimeInNsec);
hrtimer_init( &hr_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
hrtimer_set_expires(&hr_timer, kt);
hr_timer.function = &my_hrtimer_callback;
hrtimer_start( &hr_timer, kt, HRTIMER_MODE_ABS);
}
void hrtimer_event_cleanup_module( void )
{
//Reset
hrtimer_cancel(&hr_timer);
enHRTimer = HRTIMER_NORESTART;
printk("HR-Timer module uninstalized\n");
}

Related

Run code for x amount of time

To preface, I am on a Unix (linux) system using gcc.
What I am stuck on is how to accurately implement a way to run a section of code for a certain amount of time.
Here is an example of something I have been working with:
struct timeb start, check;
int64_t duration = 10000;
int64_t elapsed = 0;
ftime(&start);
while ( elapsed < duration ) {
// do a set of tasks
ftime(&check);
elapsed += ((check.time - start.time) * 1000) + (check.millitm - start.millitm);
}
I was thinking this would have carried on for 10000ms or 10 seconds, but it didn't, almost instantly. I was basing this off other questions such as How to get the time elapsed in C in milliseconds? (Windows) . But then I thought that if upon the first call of ftime, the struct is time = 1, millitm = 999 and on the second call time = 2, millitm = 01 it would be calculating the elapsed time as being 1002 milliseconds. Is there something I am missing?
Also the suggestions in the various stackoverflow questions, ftime() and gettimeofday(), are listed as deprecated or legacy.
I believe I could convert the start time into milliseconds, and the check time into millseconds, then subtract start from check. But milliseconds since the epoch requires 42 bits and I'm trying to keep everything in the loop as efficient as possible.
What approach could I take towards this?
Code is incorrect calculating elapsed time.
// elapsed += ((check.time - start.time) * 1000) + (check.millitm - start.millitm);
elapsed = ((check.time - start.time) * (int64_t)1000) + (check.millitm - start.millitm);
There is some concern about check.millitm - start.millitm. On systems with struct timeb *tp, it can be expected that the millitm will be promoted to int before subtraction occurs. So the difference will be in the range [-1000 ... 1000].
struct timeb {
time_t time;
unsigned short millitm;
short timezone;
short dstflag;
};
IMO, more robust code would handle ms conversion in a separate helper function. This matches OP's "I believe I could convert the start time into milliseconds, and the check time into millseconds, then subtract start from check."
int64_t timeb_to_ms(struct timeb *t) {
return (int64_t)t->time * 1000 + t->millitm;
}
struct timeb start, check;
ftime(&start);
int64_t start_ms = timeb_to_ms(&start);
int64_t duration = 10000 /* ms */;
int64_t elapsed = 0;
while (elapsed < duration) {
// do a set of tasks
struct timeb check;
ftime(&check);
elapsed = timeb_to_ms(&check) - start_ms;
}
If you want efficiency, let the system send you a signal when a timer expires.
Traditionally, you can set a timer with a resolution in seconds with the alarm(2) syscall.
The system then sends you a SIGALRM when the timer expires. The default disposition of that signal is to terminate.
If you handle the signal, you can longjmp(2) from the handler to another place.
I don't think it gets much more efficient than SIGALRM + longjmp (with an asynchronous timer, your code basically runs undisturbed without having to do any extra checks or calls).
Below is an example for you:
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
static jmp_buf jmpbuf;
void hndlr();
void loop();
int main(){
/*sisv_signal handlers get reset after a signal is caught and handled*/
if(SIG_ERR==sysv_signal(SIGALRM,hndlr)){
perror("couldn't set SIGALRM handler");
return 1;
}
/*the handler will jump you back here*/
setjmp(jmpbuf);
if(0>alarm(3/*seconds*/)){
perror("couldn't set alarm");
return 1;
}
loop();
return 0;
}
void hndlr(){
puts("Caught SIGALRM");
puts("RESET");
longjmp(jmpbuf,1);
}
void loop(){
int i;
for(i=0; ; i++){
//print each 100-milionth iteration
if(0==i%100000000){
printf("%d\n", i);
}
}
}
If alarm(2) isn't enough, you can use timer_create(2) as EOF suggests.

Why does my hrtimer callback return too early after forwarding it?

I want to use a hrtimer to control two hardware gpio pins to do some bus signalling. I set up a hrtimer in a kernel module like this
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
#define PIN_A_HIGH_TO_A_LOW_US 48 /* microseconds */
#define PIN_A_LOW_TO_B_LOW_US 24 /* microseconds */
static struct kt_data {
struct hrtimer timer;
ktime_t period;
} *data;
typedef enum {
eIdle = 0,
eSetPinALow,
eSetPinBLow,
} teControlState;
static enum hrtimer_restart TimerCallback(struct hrtimer *var);
static void StopTimer(void);
static teControlState cycle_state = eIdle;
static enum hrtimer_restart TimerCallback(struct hrtimer *var)
{
local_irq_disable();
switch (cycle_state) {
case eSetPinALow:
SetPinA_Low();
data->period = ktime_set(0, PIN_A_LOW_TO_B_LOW_US * 1000);
cycle_state = eSetPinBLow;
break;
case eSetPinBLow:
SetPinB_Low();
/* Do Stuff */
/* no break */
default:
cycle_state = eIdle;
break;
}
if (cycle_state != eIdle) {
hrtimer_forward_now(var, data->period);
local_irq_enable();
return HRTIMER_RESTART;
}
local_irq_enable();
return HRTIMER_NORESTART;
}
void StartBusCycleControl(void)
{
SetPinA_High();
SetPinB_High();
data->period = ktime_set(0, PIN_A_HIGH_TO_A_LOW_US * 1000);
cycle_state = eSetPinALow;
hrtimer_start(&data->timer, data->period, HRTIMER_MODE_REL);
}
int InitTimer(void)
{
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (data) {
hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
data->timer.function = TimerCallback;
printk(KERN_INFO DRV_NAME
": %s hr timer successfully initialized\n", __func__);
return 0;
} else {
printk(KERN_CRIT DRV_NAME
": %s failed to initialize the hr timer\n", __func__);
return -ENOMEM;
}
}
So the idea is that
both pins are high at the start
hrtimer is set to expire after 48 microseconds
in the callback function, pin A is pulled to low
the timer is pushed forward 24 microseconds
the second time the callback is triggered, pin B is pulled to low
I use a BeagleBoneBlack with Kernel 4.1.2 with the rt-preempt patches.
What I see at the scope is that the first timer works like a charm with about 65-67 microseconds (I can live with that).
but the forwarding seems to malfunction because the times I measure between pin A going low and pin B going low are between 2 and 50 microseconds.
So in essence, the second time the callback is triggered sometimes happens before the 24 microseconds I defined.
And that timing doesn't work for my use case.
Any pointers to what I am doing wrong?
So to answer this myself: This is a problem of wrong expectations.
What we expected here is to set the timer forward during the callback by the amount we set (24us). But if we take a look at the kernel implementation of hrtimer_forward_now()we can see that the time is actually added to the last event/occurrence of the timer (see the calculation of delta):
From Linux/kernel/time/hrtimer.c
833 u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
834 {
835 u64 orun = 1;
836 ktime_t delta;
837
838 delta = ktime_sub(now, hrtimer_get_expires(timer));
839
840 if (delta.tv64 < 0)
841 return 0;
842
843 if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED))
844 return 0;
845
846 if (interval.tv64 < hrtimer_resolution)
847 interval.tv64 = hrtimer_resolution;
848
849 if (unlikely(delta.tv64 >= interval.tv64)) {
850 s64 incr = ktime_to_ns(interval);
851
852 orun = ktime_divns(delta, incr);
853 hrtimer_add_expires_ns(timer, incr * orun);
854 if (hrtimer_get_expires_tv64(timer) > now.tv64)
855 return orun;
856 /*
857 * This (and the ktime_add() below) is the
858 * correction for exact:
859 */
860 orun++;
861 }
862 hrtimer_add_expires(timer, interval);
863
864 return orun;
865 }
That means that the time delay it took between the timer firing and the callback actually executing is not taken into account here. The hrtimers are meant to be precise in interval timing and not be influenced by the usual delays between firing and the callback.
Where our expectancy was to include that time into the calculation because we wanted the timer to restart from the moment we executed an action in the timer callback.
I tried to draw this into the following diagram:
Following the red numbered bubbles we get:
timer is started with X time to fire
time X has passed, the timer is triggered
after "delay X" depending on the load of the system and other factors, the callback function for the hrtimer is called
hrtimer_forward_now sets the new timer forward based on the last event plus the new expected time (which might be only 2us in the future instead of 24)
Here is the discrepancy of expectation vs reality. The hrtimer fires 24us after the last event when we expect it to fire 24us after the call to forward_now()
To sum it all up, we completely trashed the above code example and went with a usleep_range() call between triggering the two GPIO pins. The underlying implementation of that function is also done with hrtimer but it is hidden from the user and it acts as we expect in this case.
I also encounter this problem.Thank you for TabascoEye's answer.I just want to add some code as an example for easier understand.
In my application, I have a hardware interrupt(30ms+-3ms interval) to call reactive_hrtimer() and then timer_do() will be called after 10ms. Since the time enter the interrupt is not regular, I need to implement the input for hrtimer_add_expires() myself.
For irregular time interval:
enum hrtimer_restart timer_do(struct hrtimer *timer)
{
/**something**/
return HRTIMER_NORESTART;
}
void reactive_hrtimer( struct hrtimer *hr_timer, ktime_t ktime_interval)
{
ktime_t delta;
ktime_t now;
now = hrtimer_cb_get_time(hr_timer);
delta = ktime_sub(now, hrtimer_get_expires(hr_timer));
hrtimer_add_expires(hr_timer, ktime_add(ktime_interval, delta));
hrtimer_restart(hr_timer);
}
These code can be put in anywhere instead of inside the callback

Is it possible to modify hrtimer parameters from within a custom kernel module?

Is there a way to adjust an hrtimer's parameters (specifically I want to adjust min_delta_ns) from within a kernel module?
I'm writing a kernel module that has some outputs driven by an hrtimer. Here's a rough outline of the basic code:
#include <linux/hrtimer.h>
#include <linux/sched.h>
#define MAXRUNS 300000
#define PERIOD_IN_NS 100000
static struct hrtimer hr_timer;
static ktime_t ktime_period_ns;
static volatile int runcount = 0;
static int some_function(parameters) {
ktime_period_ns= ktime_set( 0, PERIOD_IN_NS );
hrtimer_init ( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
htimer.function = timer_callback;
hrtimer_start( &hr_timer, ktime_period_ns, HRTIMER_MODE_REL );
return 0;
}
static enum hrtimer_restart timer_callback(struct hrtimer *timer)
{
runcount++;
if (runcount < MAXRUNS) {
// do stuff
hrtimer_forward_now(&hr_timer, ktime_period_ns);
return HRTIMER_RESTART;
} else {
runcount = 0;
return HRTIMER_NORESTART;
}
}
When I run it with PERIOD_IN_NS of 100,000 or greater everything works great. However, if I drop that value to say, 50,000, the period of my clamps at around 90,000 (ish) and output becomes unpredictable.
I ran cat /proc/timer_list to get the details of my timers and here are the details what I believe is the relevant timer:
Tick Device: mode: 1
Per CPU device: 0
Clock Event Device: mxc_timer1
max_delta_ns: 1431655752223
min_delta_ns: 85000
mult: 6442451
shift: 31
mode: 3
next_event: 13571723000000 nsecs
set_next_event: v2_set_next_event
set_mode: mxc_set_mode
event_handler: hrtimer_interrupt
retries: 0
From what I've read about how hrtimer works, that min_delta_ns of 85000 means that I can't run interrupts with a period any smaller than 85,000 nanoseconds. I'd like to try to decrease that value to see if I can get my code to cycle any faster without detrimental effects to the system (I'm running this on Raspberry-Pi-like dev board called the HummingBoard).
It looks like this clock is being initially configured in my specific architecture's version of time.c (line 180), but I can't figure out how to access and modify the values outside of that context in my custom kernel module.
Is there a way to adjust the values of an hrtimer's parameters from within my kernel module?
The min_delta_ns value describes a property of the hardware device.
Even if you were able to change this value (which you cannot), the timer event would not actually arrive any faster.

I did a High Resolution Timing in C on Windows? could anyone guide me to call a specific function at 2ms?

hr_time.h:
----------
#include <windows.h>
typedef struct {
LARGE_INTEGER start;
LARGE_INTEGER stop;
} stopWatch;
void startTimer( stopWatch *timer);
void stopTimer( stopWatch *timer);
double LIToSecs( LARGE_INTEGER * L);
double getElapsedTime( stopWatch *timer);
------------------------------------------------------
hr_time.c:
------------
#include <windows.h>
#ifndef hr_timer
#include "hr_time.h"
#define hr_timer
#endif
void startTimer( stopWatch *timer) {
QueryPerformanceCounter(&timer->start);
}
void stopTimer( stopWatch *timer) {
QueryPerformanceCounter(&timer->stop);
}
double LIToSecs( LARGE_INTEGER * L) {
LARGE_INTEGER frequency;
QueryPerformanceFrequency( &frequency );
return ((double)L->QuadPart /(double)frequency.QuadPart);
}
double getElapsedTime( stopWatch *timer) {
LARGE_INTEGER time;
time.QuadPart = timer->stop.QuadPart - timer->start.QuadPart;
return LIToSecs( &time) ;
}
#include "TIMER1.h"
void main()
{
/**
* how to make This task is activated every 2ms ??
*/
TASK( Task2ms )
{
stopWatch s;
startTimer(&s);
if( XCPEVENT_DAQ_OVERLOAD & Xcp_DoDaqForEvent_2msRstr() )
{
}
if( XCPEVENT_MISSING_DTO & Xcp_DoStimForEvent_2msRstr() )
{
}
stopTimer(&s);
getElapsedTime(&s);
}
}
if we take two readings at TimeStart and then TimeEnd then the difference is the number of counts. Divide this by the frequency of the counter- a value expressed as ticks per second and the result is the length of time that the timed code took to execute.
The above code is working fine but need some suggestions to call the function at 2ms or 10ms. could anyone help me in this ??
Declare a variable of type stopWatch eg s. Then before the code you wish to time, insert a startTimer( &s) function call and after the code, a stopTimer(&s) call. You can then call getElapsedTime(&s) to return the time in seconds accurate to microseconds.
Myquestion : How to call a specific function at 2ms or 10ms ?? Where to modify in the above code ??
I modified the code and added main function: Is it possible call the function (like: XCPEVENT_DAQ_OVERLOAD & Xcp_DoDaqForEvent_2msRstr() and XCPEVENT_MISSING_DTO & Xcp_DoStimForEvent_2msRstr()) for every 2ms ??
The code excerpts in your question show how to measure elapsed time to high resolution. They do not show how to schedule periodic execution. That would require a timer.
As you no doubt know, the standard Win32 timer is a low resolution timer. You need a high resolution timer. The most commonly used example of which is a multimedia timer. More recently these have been deprecated in favour of timer queues.

itimer expiration

I was using a periodic timer and taking times between when two SIGALRM signals are received. what I observed was that itimer might expires a little before or little after the time I set. e.g. if I set it for 1m sec , it might expires at 0.9998msec or 1.0023msec.
Shouldn't the timer expiration would always be greater than what is set? less time taken is what I dont understand.
here's my code:
enter code here
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <stdlib.h>
#include <time.h>
#define INTERVAL 1000
struct timespec ti[100];
int s=0;
void ex(int i)
{int d=0;
struct timespec t[100],s1,s2;
for(d=0;d<99;d++)
{
s1= ti[d];
s2= ti[d+1];
printf("%u:%u\t%u:%u\t", s1.tv_sec, s1.tv_nsec, s2.tv_sec, s2.tv_nsec);
if ((s2.tv_nsec- s1.tv_nsec)<0) {
t[d].tv_sec = s2.tv_sec-s1.tv_sec-1;
t[d].tv_nsec = 1000000000 +s2.tv_nsec -s1.tv_nsec;
} else {
t[d].tv_sec = s2.tv_sec-s1.tv_sec;
t[d].tv_nsec = s2.tv_nsec-s1.tv_nsec;
}
printf("%u:%u\n",t[d].tv_sec,t[d].tv_nsec);
}
exit(0);
}
void alarm_wakeup (int i)
{
clock_gettime(CLOCK_MONOTONIC, &ti[s]);
s++;
if(s==100)
{ ex(0);
}
}
void main ()
{
struct itimerval tout_val;
tout_val.it_interval.tv_sec = 0;
tout_val.it_interval.tv_usec = INTERVAL;
tout_val.it_value.tv_sec = 0;
tout_val.it_value.tv_usec = INTERVAL;
setitimer(ITIMER_REAL, &tout_val,0);
signal(SIGALRM,alarm_wakeup); /* set the Alarm signal capture */
signal(SIGINT,ex);
while (1)
{
}
}
When the timer expires, the signal is raised and the timer is rescheduled.
However, there can be a delay between the signal being raised and the signal being handled - if the process isn't running already, it has to be rescheduled. This means that there is a potentially variable delay between the actual expiration of the timer and when the clock_gettime() call in your signal handler runs.
If this delay before the clock_gettime() call is higher one iteration than the next, then the time between the clock_gettime() calls will be slightly less than 1ms even though there was a 1ms gap between the subsequent timer expiries.
In diagrammatic form:
time: 0ms...............1ms...............2ms...............3ms
timer expiry: X X X X
signal handler runs: S S S S
You can see that the longer delay before the second signal handler ran made the third signal appear to be "early", even though the underlying timer was not.

Resources