AC_PREREQ(2.57)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
#AC_WITH_LTDL # not needed ?
-AM_INIT_AUTOMAKE(LinuxTraceToolkitViewer,0.8.5-17012006)
+AM_INIT_AUTOMAKE(LinuxTraceToolkitViewer,0.8.6-20012006)
AM_CONFIG_HEADER(config.h)
AM_PROG_LIBTOOL
<PRE><TT>
begin
* the beginning of buffer information
- timestamp
- * Used only when no TSC is available.
- uint32 seconds
- uint32 microseconds
uint64 cycle_count
* TSC at the beginning of the buffer
uint64 freq
* frequency of the CPUs at the beginning of the buffer.
end
* the end of buffer information
- timestamp
- * Used only when no TSC is available.
- uint32 seconds
- uint32 microseconds
uint64 cycle_count
* TSC at the beginning of the buffer
uint64 freq
* Is the information in this trace aligned ?
Yes (1) -> aligned on min(arch size, atomic data size).
No (0) -> data is packed.
-uint8 has_tsc
- * Does the traced machine has a working TSC ?
- Yes (1) -> event time is calculated from :
- trace_start_time + ((event_tsc - trace_start_tsc) * freq)
- No (0) -> event time is calculated from :
- trace_start_time
- + (buffer start timestamp - trace start_monotonic)
- + (event_time_delta)
- (not supported)
+uint328 freq_scale
+ event time is always calculated from :
+ trace_start_time + ((event_tsc - trace_start_tsc) * (freq / freq_scale))
uint64 start_freq
* CPUs clock frequency at the beginnig of the trace.
uint64 start_tsc
uint64 timestamp }
* if has_heartbeat : 32 LSB of the cycle counter at the event record time.
* else : 64 bits complete cycle counter.
- * note : if there is no working TSC (has_tsc == 0), then this field contains
- either the complete monotonically increasing time or the time delta from the
- previous heartbeat event. (unsupported)
uint8 facility_id
* Numerical ID of the facility corresponding to the event. See the facility
tracefile to know which facility ID matches which facility name and
</td>
</tr>
+<tr>
+<td style="vertical-align: top;">
+0.8.6<br>
+</td>
+<td style="vertical-align: top;">
+0.5.7<br>
+</td>
+<td style="vertical-align: top;">0.4<br>
+</td>
+<td style="vertical-align: top;">
+0.7<br>
+</td>
+<td style="vertical-align: top;">0.6<br>
+</td>
+<td style="vertical-align: top;">
+2.6.15-i386 (git)<br>
+2.6.15-i386 (tarball)<br>
+</td>
+<td style="vertical-align: top;">
+Support for architectures without TSC.<br>
+<br>
+</td>
+</tr>
+
</tbody>
My suggestion is to go for a system call, but only call it :
-- when the process starts
-- when receiving a SIG_UPDTRACING
+- when the thread starts
+- when receiving a SIG_UPDTRACING (multithread ?)
+
+Note : save the thread ID (process ID) in the logging function and the update
+handler. Use it as a comparison to check if we are a forked child thread.
+Start a brand new buffer list in that case.
+
Two possibilities :
syscall get_tracing_info
-first parameter : active traces mask (32 bits : 32 traces).
+parameter 1 : trace buffer map address. (id)
+
+parameter 2 : active ? (int)
Concurrency
Multiple traces
By having the number of active traces, we can allocate as much buffers as we
-need. The only thing is that the buffers will only be allocated when receiving
-the signal/starting the process and getting the number of traces actives.
+need. Allocation is done in the kernel with relay_open. User space mapping is
+done when receiving the signal/starting the process and getting the number of
+traces actives.
It means that we must make sure to only update the data structures used by
tracing functions once the buffers are created.
-When adding a new buffer, we should call the set_tracing_info syscall and give
-the new buffers array to the kernel. It's an array of 32 pointers to user pages.
-They will be used by the kernel to get the last pages when the thread dies.
+We could have a syscall "get_next_buffer" that would basically mmap the next
+unmmapped buffer, or return NULL is all buffers are mapped.
If we remove a trace, the kernel should stop the tracing, and then get the last
buffer for this trace. What is important is to make sure no writers are still
accessing this memory area. When the control comes back to the writer, at the
end of the write in a trace, if the trace is marked for switch/delete and the
tracing_level is 0 (after the decrement of the writer itself), then the
- writer must buffer switch, set_tracing_info to NULL and then delete the
- memory area.
+ writer must buffer switch, and then delete the memory area.
Filter
The update tracing info signal will make the thread get the new filter
information. Getting this information will also happen upon process creation.
-parameter 2 for the get tracing info : array of 32 ints (32 bits).
-Each integer is the filter mask for a trace. As there are up to 32 active
-traces, we have 32 integers for filter.
+parameter 3 for the get tracing info : a integer containing the 32 bits mask.
Buffer switch
If a thread dies unexpectedly, we want the kernel to get the last bits of
information before the thread crashes.
-syscall set_tracing_info
-
-parameter 1 : array of 32 user space pointers to current pages or NULL.
-
-
Memory protection
-We want each process to be usable to make a trace unreadable, and each process
-to have its own memory space.
+If a process corrupt its own mmaped buffers, the rest of the trace will be
+readable, and each process have its own memory space.
Two possibilities :
+API :
+
+syscall 1 :
+
+int update_tracing_info(void *buffer, int *active, int *filter);
+
+
+syscall 2 :
+
+int tracing_buffer_switch(void *buffer);
+
+
+Signal :
+
+UPD_TRACING
+Default : SIG IGNORE
+(like hardware fault and expiring timer : to the thread, see p. 413 of Advances
+prog. in the UNIX env.)
+
+Will update for itself only : it will remove unnecessary concurrency.
+
+
+
+
+
+
+
+
uint8_t flight_recorder;
uint8_t has_heartbeat;
uint8_t has_alignment; /* Event header alignment */
- uint8_t has_tsc;
+ uint32_t freq_scale;
} LTT_PACKED_STRUCT;
uint8_t flight_recorder;
uint8_t has_heartbeat;
uint8_t has_alignment; /* Event header alignment */
- uint8_t has_tsc;
+ uint32_t freq_scale;
} LTT_PACKED_STRUCT;
-/* For version 0.6 */
+/* For version 0.7 */
-struct ltt_trace_header_0_6 {
+struct ltt_trace_header_0_7 {
uint32_t magic_number;
uint32_t arch_type;
uint32_t arch_variant;
uint8_t flight_recorder;
uint8_t has_heartbeat;
uint8_t has_alignment; /* Event header alignment */
- uint8_t has_tsc;
+ uint32_t freq_scale;
uint64_t start_freq;
uint64_t start_tsc;
uint64_t start_monotonic;
- //struct timespec start_time; // not portable
uint64_t start_time_sec;
uint64_t start_time_usec;
} LTT_PACKED_STRUCT;
struct ltt_block_start_header {
struct {
- //struct timeval timestamp;
- uint64_t timestamp_sec;
- uint64_t timestamp_usec;
uint64_t cycle_count;
uint64_t freq;
} begin;
struct {
- //struct timeval timestamp;
- uint64_t timestamp_sec;
- uint64_t timestamp_usec;
uint64_t cycle_count;
uint64_t freq;
} end;
/* End of LttEventPosition fields */
- union { /* choice by trace has_tsc */
- guint32 timestamp; /* truncated timestamp */
- LttTime delta;
- } time;
+ guint32 timestamp; /* truncated timestamp */
unsigned char facility_id; /* facility ID are never reused. */
unsigned char event_id;
guint8 ltt_minor_version;
guint8 flight_recorder;
guint8 has_heartbeat;
- guint8 has_tsc;
+ guint32 freq_scale;
uint64_t start_freq;
uint64_t start_tsc;
uint64_t start_monotonic;
t->ltt_minor_version = any->minor_version;
t->flight_recorder = any->flight_recorder;
t->has_heartbeat = any->has_heartbeat;
- t->has_tsc = any->has_tsc;
+ t->freq_scale = any->freq_scale;
}
return 1;
}
break;
- case 6:
+ case 7:
{
- struct ltt_trace_header_0_6 *vheader =
- (struct ltt_trace_header_0_6 *)header;
+ struct ltt_trace_header_0_7 *vheader =
+ (struct ltt_trace_header_0_7 *)header;
tf->buffer_header_size =
sizeof(struct ltt_block_start_header)
- + sizeof(struct ltt_trace_header_0_6);
+ + sizeof(struct ltt_trace_header_0_7);
if(t) {
t->start_freq = ltt_get_uint64(LTT_GET_BO(tf),
&vheader->start_freq);
{
LttTime time;
- g_assert(tf->trace->has_tsc);
-
// time = ltt_time_from_uint64(
// cycles_2_ns(tf, (guint64)(tf->buffer.tsc - tf->buffer.begin.cycle_count)));
time = ltt_time_from_uint64(
- (double)(tf->buffer.tsc - tf->trace->start_tsc) * 1000000.0
+ (double)(tf->buffer.tsc - tf->trace->start_tsc)
+ * (1000000000.0 / tf->trace->freq_scale)
/ (double)tf->trace->start_freq);
//time = ltt_time_add(tf->buffer.begin.timestamp, time);
time = ltt_time_add(tf->trace->start_time_from_tsc, time);
/* Align the head */
pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment);
- if(tf->trace->has_tsc) {
- if(tf->trace->has_heartbeat) {
- event->time.timestamp = ltt_get_uint32(LTT_GET_BO(tf),
- pos);
- /* 32 bits -> 64 bits tsc */
- /* note : still works for seek and non seek cases. */
- if(event->time.timestamp < (0xFFFFFFFFULL&tf->buffer.tsc)) {
- tf->buffer.tsc = ((tf->buffer.tsc&0xFFFFFFFF00000000ULL)
- + 0x100000000ULL)
- | (guint64)event->time.timestamp;
- event->tsc = tf->buffer.tsc;
- } else {
- /* no overflow */
- tf->buffer.tsc = (tf->buffer.tsc&0xFFFFFFFF00000000ULL)
- | (guint64)event->time.timestamp;
- event->tsc = tf->buffer.tsc;
- }
- pos += sizeof(guint32);
- } else {
- event->tsc = ltt_get_uint64(LTT_GET_BO(tf), pos);
- tf->buffer.tsc = event->tsc;
- pos += sizeof(guint64);
- }
-
- event->event_time = ltt_interpolate_time(tf, event);
- } else {
- event->time.delta.tv_sec = 0;
- event->time.delta.tv_nsec = ltt_get_uint32(LTT_GET_BO(tf),
- pos) * NSEC_PER_USEC;
- tf->buffer.tsc = 0;
- event->tsc = tf->buffer.tsc;
-
- event->event_time = ltt_time_add(tf->buffer.begin.timestamp,
- event->time.delta);
- pos += sizeof(guint32);
- }
-
+ if(tf->trace->has_heartbeat) {
+ event->timestamp = ltt_get_uint32(LTT_GET_BO(tf),
+ pos);
+ /* 32 bits -> 64 bits tsc */
+ /* note : still works for seek and non seek cases. */
+ if(event->timestamp < (0xFFFFFFFFULL&tf->buffer.tsc)) {
+ tf->buffer.tsc = ((tf->buffer.tsc&0xFFFFFFFF00000000ULL)
+ + 0x100000000ULL)
+ | (guint64)event->timestamp;
+ event->tsc = tf->buffer.tsc;
+ } else {
+ /* no overflow */
+ tf->buffer.tsc = (tf->buffer.tsc&0xFFFFFFFF00000000ULL)
+ | (guint64)event->timestamp;
+ event->tsc = tf->buffer.tsc;
+ }
+ pos += sizeof(guint32);
+ } else {
+ event->tsc = ltt_get_uint64(LTT_GET_BO(tf), pos);
+ tf->buffer.tsc = event->tsc;
+ pos += sizeof(guint64);
+ }
+
+ event->event_time = ltt_interpolate_time(tf, event);
event->facility_id = *(guint8*)pos;
pos += sizeof(guint8);