Some further thoughts about clocks:

It would be helpful if the clock definition could provide some info on how to 
translate the clock value fields into time values.  e.g. 'monotonic' sequence 
numbers, wall-clock values, O/S Tick counts or c-time values would all need to 
be interpreted and decoded differently.  In some cases, it would be possible to 
convert them into time values with units such as ns, ms, s, etc. allowing 
further processing for elapsed time between events, etc.

Also, it would be useful to log the various clock frequencies as part of the 
sync point event to ensure that all required time correlation information is 
always logged at the same moment in time.  We could define two different sync 
point events, one for use when a clock frequency is changing and one for use 
when the clock frequencies have not changed, but since these events should be 
relatively infrequent, perhaps a single event that can be used for both 
situations would simplify things.

Here's a rough first cut at trying to describe this in CTF (is this correct 
syntax??) with some additional thoughts and questions injected as comments:

/* Device-independent stuff associated with the application: [...*/
        
        /* It would be useful to allow metadata to be emitted for the 
           device-independent application and for each of the device-specific
         clock modules separately, and simply written to the same file to
         compose the metadata for the application.  (I can provide an
         example using javascript scripts that shows how to do this if this
         idea is of interest to anyone). */

/* ...] end of device-independent stuff */

/* Device-specific stuff:  [... */

/* The sync_point event contains a 'snapshot' of the timestamp values at the   
same moment in time, as well as the frequency \ values for each of the   clocks 
at that time.  It is written infrequently, but at 'a useful moment   in time' - 
e.g. when the application first starts up, when a clock   frequency changes, 
when a critical event buffer used to log events wraps   around, just before 
some multicore operation that is being monitored, etc. 

The sync_point event itself contains device-specific fields, so it would need 
to be logged by a function in a library that could be linked with the 
application (e.g. allowing the application to call a "LogSyncPointEvent() API 
or something).  In many cases, the 'framework' that was being used to
run the application could take care of logging the sync point event when 
required so that the application code would not have to call this API at all.
*/

event {
        name = sync_point;
        id = 3;
        /* Referencing the clocks by name in the sync-point event fields would 
           allow metadata to be emitted for the clock modules separately, and 
           simply written to the same file to compose the overall 
         device-specific metadata for the application.  
        */
        fields := {
            uint64_t monotonic_value;
                uint64_t monotonic_freq_value;
            uint64_t cpu_timestamp_value;
                uint64_t cpu_timestamp_freq_value;
            uint32_t global_timestamp_value;
                uint64_t global_timestamp_freq_value;
                /* user_defined_tag_value can be used for e.g. 
               injecting correlation sequence numbers
               into trace streams */
                uint32_t user_defined_tag_value;  
        };
};

/* Define a set of 'well-known' enumeration values that
 * would have implicit meaning and would allow tooling
 * to 'know' how to interpret a clock value (e.g.
 * whether it could be turned into a time value or 
 * was a simple sequence number, etc.  
 * 
 * Should we provide more extensibility than this by declaring
 * concepts such as 'is a sequence number' or 'is a device clock'
 * explicitly in the metadata somehow, or is a simple naming
 * convention such as this sufficient? 
 */
enum clock_type : unsigned int {
        SEQUENCE_NUMBER,
        CTIME,
        CLOCK_TICK
};

clock {
      name = monotonic;
        type = SEQUENCE_NUMBER;
        uuid = 12345; 
        /* The 'metaname' fields would be only used for display 
           purposes in order to make it easier for users to determine 
           which clock a clock value or frequency value was for. */ 
      metaname = "Monotonic sequence number";
};
                
clock {
      name = cpu_timestamp;
        type = CLOCK_TICK;
      uuid = 23456;/* some unique identifier specific to this CPU's clock */ 
      metaname = "Local CPU timestamp";
        /* (should the following be located in  struct?? )*/
/* the following fields are only required for clocks of type CLOCK_TICK: */
        max_freq = 1000000000;
        cpu_cycles_per_tick = 1;
        can_freq_be_changed = true;
        can_cycles_per_tick_be_changed = true;
};  
clock {
        name = global_timestamp;
        type = CLOCK_TICK;
        /* the UUID provides a unique identifier specific to this 
           device's clock.  Having the same script used to emit 
           metadata for this clock for all  applications and all 
           cores on the device would ensure that the same UUID 
           was used in all cases. */ 
        uuid = 34567; 
        metaname = "Global timestamp";
        /* (should the following be located in a struct?? )*/
/* the following fields are only required for clocks of type CLOCK_TICK: */
        max_freq = 250000000;
        cpu_cycles_per_tick = 4;
        can_freq_be_changed = true;
        can_cycles_per_tick_be_changed = true;  
};

/* From Aaron's email:  */
clock_access {
        name = global_timestamp;
        metaname = "Shared system clock accessed via PCI";
        clock_uuid = 23456; /* reference to the UUID of the clock we are 
accessing */;
        uuid = 1111112; /* some unique identifier specific to this particular 
access method for this particular clock */;
        latency_min = 5us;   /* what is the minimum time it takes to read this 
clock? */
        latency_max = 500us; /* what is the maximum time it takes to read this 
clock? */ };
}

/* Would the following be a valid way of defining the relationships between 
clocks, in this case showing that they would all be correlated via the global 
timestamp value?
*/
clock_maps {
    uuid = /* some unique identifier specific to this board's clock */; 
    map {
        parent.clock = monotonic;
        parent.value = event.sync_point.monotonic_value;
        value = event.sync_point.global_timestamp_value;
    };
    map {
        parent.clock = cpu_timestamp;
        parent.value = event.sync_point.cpu_timestamp;
        value = event.sync_point.global_timestamp_value;
    };
    map {
        parent.clock = global_timestamp;
        parent.value = event.sync_point.global_timestamp;
        value = event.sync_point.global_timestamp_value;
    };
}
/* ...] end of device specific stuff */

Any thoughts / suggestions / questions / comments?

Regards,
  Brian

-----Original Message-----
From: Aaron Spear [mailto:[email protected]] 
Sent: May 17, 2011 4:49 PM
To: Mathieu Desnoyers; [email protected]; 
[email protected]
Cc: Cruickshank, Brian
Subject: RE: [RFC] CTF TSDL: clocks and dynamic enumerations

Hi Mathieu,

Some thoughts about clocks below:

> * Clock description
> 
> So now about the clock description, I talked a little bit with Brian
> about this. The idea is to describe the relationship between the various
> time and ordering references available on a system as a simple
> description in the TSDL metadata. Some ideas on how to express this
> (note: the "clock {}" description is just made up as I thought it.
> Feedback would be welcome)
> 
> 
> event {
>         name = timer_tick;      /* or sync_point... */
>         id = 3;
>         fields := {
>                 uint64_t monotonic_value;
>                 uint64_t tsc_value;
>                 uint32_t seqnum;
>         };
> };
> 
> event {
>         name = freq_change;
>         id = 4;
>         fields := {
>                 uint64_t new_freq;
>         };
> };
> 
> clock {
>         name = monotonic;
>         uuid = /* some unique identifier specific to this board's clock */;
> };
> 
> clock {
>         name = seqnum;
>         uuid = /* some unique identifier specific to this board's clock */;
> };
> 
> clock {
>         name = tsc;
>         sync_points = {
>                 map {
>                         parent.clock = monotonic;
>                         parent.value = event.timer_tick.monotonic_value;
>                         value = event.timer_tick.tsc_value;
>                 };
>                 map {
>                         parent.clock = seqnum;
>                         parent.value = event.timer_tick.seqnum;
>                         value = event.timer_tick.tsc_value;
>                 };
>         };
> 
>         freq = {
>                 update = event.freq_change.new_freq;
>         };
>         uuid = /* some unique identifier specific to this board's clock */;
> };

One thing you did not describe is how a given stream of events references a 
given clock.  Do they refer to a clocks UUID?  One concept that I think is 
important here is to articulate different methods to access the same clock.  
i.e. what if you have a shared global clock in a system but for one trace 
stream access is very fast and for another there is some delay possible (e.g. 
having to cross a slow bus).  I have been thinking it would be useful to 
decompose the clocks into a declaration and then an access for that clock.  
Event streams then would be declared to reference a given clock_access.  E.g.

clock {
        name = shared_sys_clock;
        freq = /* some constant or attribute like you have above */;
        uuid = 12345; /* some unique identifier specific to this clock */;
};

clock_access {
    name = shared_sys_clock_via_pci;
    clock_uuid = 12345; /* reference to the UUID of the clock we are accessing 
*/;
    uuid = 23456; /* some unique identifier specific to this particular access 
method for this particular clock */;
    latency_min = 5us;   /* what is the minimum time it takes to read this 
clock? */
    latency_max = 500us; /* what is the maximum time it takes to read this 
clock? */
};

If you do this, then you can have the possibility of knowing that two different 
trace streams reference the same clock source and the possible error involved 
with accessing those clocks.

I must confess that I am not clear on your intent with how the sync point 
events would work.  That said, wouldn't we want to actually decouple the sync 
points from the clock declarations?  It seems like it might be better to have 
those outside of the clock declaration so that it is possible for information 
outside of the OS for example to declare relationships.  Or perhaps one 
component (e.g. power management) might know the relationship between the 
clocks, but another one might not.  Perhaps just specifying a type of event 
that is known to be a clock sync event, and then attributes that are UUIDs of 
the clocks and the corresponding values.  Note that I am thinking that a sync 
event is the synchronization of multiple clocks as opposed to changing the 
values of the clocks (i.e. changing the frequency or the current count)

Regards,
Aaron Spear
VMware

_______________________________________________
ltt-dev mailing list
[email protected]
http://lists.casi.polymtl.ca/cgi-bin/mailman/listinfo/ltt-dev

Reply via email to