Wiki

Clone wiki

roseline / Roseline Clock Framework APIs

Motivation

The motivation behind this framework is to provide Clock abstractions to an application developer with quality associated with these clocks. An application should be able to create many Clocks bound to certain timelines with varying quality requirements. Alternatively, multiple devices should be able to bind their Clocks with a common timeline.

Clock Quality

When discussing Clocks, there are many quality metrics of interest, e.g,

Resolution: the smallest possible unit of time increment

Precision: the degree to which repeated time offset measurements under unchanged conditions show the same results (how consistent are the readings)

520px-Accuracy_and_precision.svg.png

Accuracy: closeness between the measured time and the reference time

Wander / stability / drift (ppm): difference in clock frequency

Jitter: difference in clock offsets w.r.t a reference (decreases with good and frequent drift control)

Reliability: the time duration for which time is kept within required accuracy determines reliability (proportional to drift control and drift derivative control through temperature and environmental factors compensation)

NOTE: A user or an application developer can specify a Clock's quality using it's accuracy. The other quality metrics are of more interest to the underlying synchronization daemon.

Clock Sources

The idea here is to create and maintain multiple Clocks. Traditionally, clock sources have been provided by the operating system limited by the underlying hardware (oscillators, counters etc.). Whereas, these APIs provide the applications with a flexibility of creating their own clocks with their own set of requirements.

We have defined three different phases for a Clock's life cycle, starting from creation of a clock, dynamically changing the quality metrics of this clock, binding a different reference timeline to the clock, schedule events based on this clock and then releasing the clock once the application is done with it.

Phase 1: Clock creation

The first phase includes the creation of a Clock bound to a timeline with some quality metrics,

#!c

typedef struct qot_clock_t {
     uint16_t timeline;
     struct timespec accuracy;
     struct timespec resolution;
} qot_clock;

This is a data structure for a Clock where,

timeline is the UUID of the reference timeline shared among all the collaborating entities. Note that the resulting hierarchy of clocks does not mirror the device network topology. The devices sharing a common timeline may not be neighbors in the network, still they share a common notion of time for the application they are running.

accuracy lets the application specify the range of acceptable deviation from the reference timeline. For example, 1000 nsec accuracy implies that the clock's tolerance with respect to the reference timeline could be +-1 microsecond.

resolution specifies the maximum clock resolution needed by the application. For example, it could be 1 nanosecond for high resolution applications or 1 second for applications that require coarse resolution.

NOTE: timespec is chosen as the units to define the accuracy and resolution. This is because,

  • it is consistent with the Linux kernel. PTP (timecounter, cyclecounter) also deals with timespecs

  • struct timespec {

    uint32_t sec;
    
    uint32_t nsec;
    

    };

timespec may not necessarily represent only UTC time. It is actually the epoch that distinguishes whether the timeline corresponds to UTC time or a grandmaster local time.

An application can create or initialize a Clock using the following API,

#!c++

qot_clock qot_init_clock(const char *timeline, struct timespec accuracy, struct timespec resolution);
This API returns the newly created clock.

Similarly, the application can also terminate or release the clock once it is finished with it, using the following API,

#!c++

void qot_release_clock(qot_clock clk);

Phase 2: Adaptive Clock Source Quality

If the application wishes to dynamically change and access the quality metrics of a clock, it can do so using the following APIs,

This sets the accuracy of an already initialized clock

#!c++

void qot_set_accuracy(qot_clock clk, struct timespec accuracy);

This sets the resolution of an already initialized clock

#!c++

void qot_set_resolution(qot_clock clk, struct timespec resolution);

It returns the mapped time according to the given clock

#!c++

struct timespec qot_get_time(qot_clock clk);
The structure used to send the query for current time and return the time query is,
#!c++

typedef struct qot_time_t {
    uint16_t clk_timeline;
    struct timespec current_time;   
} qot_time;

A clock can also unbind from one timeline and bind to another timeline dynamically using,

#!c++

void qot_set_timeline(qot_clock clk, const char *timeline);

Phase 3: Event Scheduling, Tracking & Ordering

Once a clock has been created, dynamically configured with a timeline and varying quality parameters, it is now ready for scheduling, tracking and ordering events.

The basic structure used to store scheduling parameters for an event is as follows,

#!c++

typedef struct qot_sched_t {
    uint16_t clk_timeline;
    struct timespec event_time;
    struct timespec high;
    struct timespec low;        
    uint16_t limit;     
} qot_sched;

Here, clk_timeline is the clock against which to schedule the event, event_time is the time for which the event is scheduled, high is time duration for high pulse and low is time duration for low pulse. limit defines the number of event repetitions.

The API to wait for a certain amount of time w.r.t a timeline is,

#!c++

void qot_wait_until(qot_clock clk, struct timespec eventtime);

We can also wait for certain number of ticks or cycles of a particular timeline,

#!c++

void qot_wait_until_cycles(qot_clock clk, uint64_t cycles);

The APIs used to schedule an event and later on manage those schedules are listed below, For example, the following API is used to schedule an event at event_time according to a clock

#!c++

qot_sched qot_schedule_event(qot_clock clk, struct timespec eventtime, struct timespec high, struct timespec low, uint16_t repetitions);

This returns the time for the upcoming event according to a particular clock

#!c++

struct timespec qot_get_next_event(qot_clock clk);

This returns all the scheduled events for a particular clock (needs to be discussed how the scheduler will return events list)

#!c++

qot_sched * qot_get_scheduled_events(qot_clock clk);

This cancels the specified event pointed to by schedpars (TBD)

#!c++

void qot_cancel_event(qot_clock clk, qot_sched *schedpars);

This API tracks an event locally which was timestamped according to a clock bound to a timeline. returns the inverse mapped time for a clock (TBD)

#!c++

struct timespec qot_track_event(qot_clock clk, struct timespec eventtime);

Updated