[ltt-dev] [RFC] CTF TSDL: clocks and dynamic enumerations

Cruickshank, Brian bcruickshank at ti.com
Wed Jun 8 10:19:03 EDT 2011


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:aspear at vmware.com] 
Sent: May 17, 2011 4:49 PM
To: Mathieu Desnoyers; tiwg at multicore-association.org; ltt-dev at lists.casi.polymtl.ca
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




More information about the lttng-dev mailing list