X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Fltt%2Ftracefile.c;h=8ac4b5061de96a70269dfedc3a539642d55c11cd;hb=f63ebe5196f36fcf40385d29cfc37288c4d70817;hp=f28a1b21e25c5414ae798739a4a8498c15c161dc;hpb=83e160f2269f77a175b026a4b008a6dd18533d93;p=lttv.git diff --git a/ltt/branches/poly/ltt/tracefile.c b/ltt/branches/poly/ltt/tracefile.c index f28a1b21..8ac4b506 100644 --- a/ltt/branches/poly/ltt/tracefile.c +++ b/ltt/branches/poly/ltt/tracefile.c @@ -34,6 +34,7 @@ #include #include #include +#include // For realpath #include @@ -53,7 +54,8 @@ /* Facility names used in this file */ GQuark LTT_FACILITY_NAME_HEARTBEAT, - LTT_EVENT_NAME_HEARTBEAT; + LTT_EVENT_NAME_HEARTBEAT, + LTT_EVENT_NAME_HEARTBEAT_FULL; GQuark LTT_TRACEFILE_NAME_FACILITIES; #ifndef g_open @@ -232,6 +234,7 @@ int parse_trace_header(void *header, LttTracefile *tf, LttTrace *t) t->ltt_minor_version = any->minor_version; t->flight_recorder = any->flight_recorder; t->has_heartbeat = any->has_heartbeat; + t->compact_facilities = NULL; } @@ -256,6 +259,11 @@ int parse_trace_header(void *header, LttTracefile *tf, LttTrace *t) tf->buffer_header_size = sizeof(struct ltt_block_start_header) + sizeof(struct ltt_trace_header_0_7); + tf->tsc_lsb_truncate = 0; + tf->tscbits = 32; + tf->tsc_msb_cutoff = 32 - tf->tsc_lsb_truncate - tf->tscbits; + tf->tsc_mask = (1ULL<<32)-1; + tf->tsc_mask_next_bit = (1ULL<<32); if(t) { t->start_freq = ltt_get_uint64(LTT_GET_BO(tf), &vheader->start_freq); @@ -272,7 +280,47 @@ int parse_trace_header(void *header, LttTracefile *tf, LttTrace *t) t->start_time.tv_nsec *= 1000; /* microsec to nanosec */ t->start_time_from_tsc = ltt_time_from_uint64( - (double)t->start_tsc * 1000000.0 / (double)t->start_freq); + (double)t->start_tsc + * (1000000000.0 / tf->trace->freq_scale) + / (double)t->start_freq); + t->compact_event_bits = 0; + } + } + break; + case 8: + { + struct ltt_trace_header_0_8 *vheader = + (struct ltt_trace_header_0_8 *)header; + tf->buffer_header_size = + sizeof(struct ltt_block_start_header) + + sizeof(struct ltt_trace_header_0_8); + tf->tsc_lsb_truncate = vheader->tsc_lsb_truncate; + tf->tscbits = vheader->tscbits; + tf->tsc_msb_cutoff = 32 - tf->tsc_lsb_truncate - tf->tscbits; + tf->tsc_mask = ((1ULL << (tf->tscbits))-1); + tf->tsc_mask = tf->tsc_mask << tf->tsc_lsb_truncate; + tf->tsc_mask_next_bit = (1ULL<<(tf->tscbits)); + tf->tsc_mask_next_bit = tf->tsc_mask_next_bit << tf->tsc_lsb_truncate; + if(t) { + t->start_freq = ltt_get_uint64(LTT_GET_BO(tf), + &vheader->start_freq); + t->freq_scale = ltt_get_uint32(LTT_GET_BO(tf), + &vheader->freq_scale); + t->start_tsc = ltt_get_uint64(LTT_GET_BO(tf), + &vheader->start_tsc); + t->start_monotonic = ltt_get_uint64(LTT_GET_BO(tf), + &vheader->start_monotonic); + t->start_time.tv_sec = ltt_get_uint64(LTT_GET_BO(tf), + &vheader->start_time_sec); + t->start_time.tv_nsec = ltt_get_uint64(LTT_GET_BO(tf), + &vheader->start_time_usec); + t->start_time.tv_nsec *= 1000; /* microsec to nanosec */ + + t->start_time_from_tsc = ltt_time_from_uint64( + (double)t->start_tsc + * (1000000000.0 / tf->trace->freq_scale) + / (double)t->start_freq); + t->compact_event_bits = 0; } } break; @@ -664,6 +712,7 @@ int get_tracefile_name_number(gchar *raw_name, if(i==-1) { /* Either not found or name length is 0 */ /* This is a userspace tracefile */ strncpy(char_name, raw_name, raw_name_len); + char_name[raw_name_len] = '\0'; *name = g_quark_from_string(char_name); *num = 0; /* unknown cpu */ for(i=0;itracefiles, name); if(group == NULL) { /* Elements are automatically cleared when the array is allocated. @@ -1081,7 +1134,7 @@ static int ltt_process_facility_tracefile(LttTracefile *tf) g_debug("Doing LTT_EVENT_FACILITY_LOAD of facility %s", fac_name); pos = (tf->event.data + strlen(fac_name) + 1); - pos += ltt_align((size_t)pos, sizeof(guint32), tf->has_alignment); + pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment); fac_load_data = (struct LttFacilityLoad *)pos; fac = &g_array_index (tf->trace->facilities_by_num, LttFacility, @@ -1137,7 +1190,7 @@ static int ltt_process_facility_tracefile(LttTracefile *tf) g_debug("Doing LTT_EVENT_STATE_DUMP_FACILITY_LOAD of facility %s", fac_name); pos = (tf->event.data + strlen(fac_name) + 1); - pos += ltt_align((size_t)pos, sizeof(guint32), tf->has_alignment); + pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment); fac_state_dump_load_data = (struct LttStateDumpFacilityLoad *)pos; fac = &g_array_index (tf->trace->facilities_by_num, LttFacility, @@ -1181,10 +1234,13 @@ static int ltt_process_facility_tracefile(LttTracefile *tf) fac_ids, ltt_fac_ids_destroy); } g_array_append_val(fac_ids, fac->id); + g_debug("fac id : %u", fac->id); break; case LTT_EVENT_HEARTBEAT: break; + case LTT_EVENT_HEARTBEAT_FULL: + break; default: g_warning("Error in processing facility file %s, " "unknown event id %hhu in core facility.", @@ -1295,7 +1351,31 @@ LttTrace *ltt_trace_open(const gchar *pathname) if(ltt_process_facility_tracefile(tf)) goto facilities_error; } - + t->compact_facilities = ltt_trace_facility_get_by_name(t, + g_quark_from_string("compact")); + if(!t->compact_facilities) + t->compact_facilities = ltt_trace_facility_get_by_name(t, + g_quark_from_string("flight-compact")); + if (t->compact_facilities) { + /* FIXME : currently does not support unload/load of compact + * facility during tracing. Should check for the currently loaded + * version of the facility. */ + g_assert(t->compact_facilities->len == 1); + g_assert(t->compact_facilities); + { + guint facility_id = g_array_index(t->compact_facilities, guint, 0); + LttFacility *fac = ltt_trace_facility_by_id(t, facility_id); + unsigned int num = ltt_facility_eventtype_number(fac); + /* Could be done much quicker, but not on much used code path */ + if(num) { + t->compact_event_bits = 1; + while(num >>= 1) + t->compact_event_bits++; + } else + t->compact_event_bits = 0; + } + } + return t; /* Error handling */ @@ -1817,47 +1897,99 @@ int ltt_tracefile_read_update_event(LttTracefile *tf) /* Read event header */ /* Align the head */ - pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment); + if(!tf->compact) + pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment); + else { + g_assert(tf->trace->has_heartbeat); + pos += ltt_align((size_t)pos, sizeof(uint32_t), tf->has_alignment); + } 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; - } + if(!tf->compact) { + /* 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; + event->compact_data = 0; + } + } else { + /* Compact header */ + /* We keep the LSB of the previous timestamp, to make sure + * we never go back */ + event->event_id = event->timestamp >> tf->tscbits; + event->event_id = event->event_id & ((1 << tf->trace->compact_event_bits) - 1); + event->compact_data = event->timestamp >> + (tf->trace->compact_event_bits + tf->tscbits); + //printf("tsc bits %u, ev bits %u init data %u\n", + // tf->tscbits, tf->trace->compact_event_bits, event->compact_data); + /* Put the compact data back in original endianness */ + event->compact_data = ltt_get_uint32(LTT_GET_BO(tf), &event->compact_data); + event->event_size = 0xFFFF; + //printf("Found compact event %d\n", event->event_id); + //printf("Compact data %d\n", event->compact_data); + event->timestamp = event->timestamp << tf->tsc_lsb_truncate; + event->timestamp = event->timestamp & tf->tsc_mask; + //printf("timestamp 0x%lX\n", event->timestamp); + //printf("mask 0x%llX\n", tf->tsc_mask); + //printf("mask_next 0x%llX\n", tf->tsc_mask_next_bit); + //printf("previous tsc 0x%llX\n", tf->buffer.tsc); + //printf("previous tsc&mask 0x%llX\n", tf->tsc_mask&tf->buffer.tsc); + //printf("previous tsc&(~mask) 0x%llX\n", tf->buffer.tsc&(~tf->tsc_mask)); + if(event->timestamp < (tf->tsc_mask&tf->buffer.tsc)) { + //printf("wrap\n"); + tf->buffer.tsc = ((tf->buffer.tsc&(~tf->tsc_mask)) + + tf->tsc_mask_next_bit) + | (guint64)event->timestamp; + event->tsc = tf->buffer.tsc; + } else { + //printf("no wrap\n"); + /* no overflow */ + tf->buffer.tsc = (tf->buffer.tsc&(~tf->tsc_mask)) + | (guint64)event->timestamp; + event->tsc = tf->buffer.tsc; + } + //printf("current tsc 0x%llX\n", tf->buffer.tsc); + event->facility_id = g_array_index(tf->trace->compact_facilities, guint, 0); + } pos += sizeof(guint32); } else { event->tsc = ltt_get_uint64(LTT_GET_BO(tf), pos); tf->buffer.tsc = event->tsc; + event->compact_data = 0; pos += sizeof(guint64); } event->event_time = ltt_interpolate_time(tf, event); - event->facility_id = *(guint8*)pos; - pos += sizeof(guint8); - event->event_id = *(guint8*)pos; - pos += sizeof(guint8); + if(!tf->compact) { + event->facility_id = *(guint8*)pos; + pos += sizeof(guint8); - event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos); - pos += sizeof(guint16); - + event->event_id = *(guint8*)pos; + pos += sizeof(guint8); + + event->event_size = ltt_get_uint16(LTT_GET_BO(tf), pos); + pos += sizeof(guint16); + } else { + /* Compact event */ + } /* Align the head */ - pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment); + if(!tf->compact) + pos += ltt_align((size_t)pos, tf->trace->arch_size, tf->has_alignment); event->data = pos; /* get the data size and update the event fields with the current - * information */ + * information. Also update the time if a heartbeat_full event is found. */ ltt_update_event_size(tf); return 0; @@ -2001,71 +2133,83 @@ map_error: void ltt_update_event_size(LttTracefile *tf) { off_t size = 0; - - /* Specific handling of core events : necessary to read the facility control - * tracefile. */ LttFacility *f = ltt_trace_get_facility_by_num(tf->trace, tf->event.facility_id); - - if(likely(tf->event.facility_id == LTT_FACILITY_CORE)) { - switch((enum ltt_core_events)tf->event.event_id) { - case LTT_EVENT_FACILITY_LOAD: - size = strlen((char*)tf->event.data) + 1; - //g_debug("Update Event facility load of facility %s", (char*)tf->event.data); - size += ltt_align(size, sizeof(guint32), tf->has_alignment); - size += sizeof(struct LttFacilityLoad); - break; - case LTT_EVENT_FACILITY_UNLOAD: - //g_debug("Update Event facility unload"); - size = sizeof(struct LttFacilityUnload); - break; - case LTT_EVENT_STATE_DUMP_FACILITY_LOAD: - size = strlen((char*)tf->event.data) + 1; - size += ltt_align(size, sizeof(guint32), tf->has_alignment); - //g_debug("Update Event facility load state dump of facility %s", - // (char*)tf->event.data); - size += sizeof(struct LttStateDumpFacilityLoad); - break; - case LTT_EVENT_HEARTBEAT: - //g_debug("Update Event heartbeat"); - size = sizeof(TimeHeartbeat); - break; - default: - g_warning("Error in getting event size : tracefile %s, " - "unknown event id %hhu in core facility.", - g_quark_to_string(tf->name), - tf->event.event_id); - goto event_id_error; - - } - } else { - if(!f->exists) { + char *tscdata; + + if(!f->exists) { + /* Specific handling of core events : necessary to read the facility control + * tracefile. */ + + if(likely(tf->event.facility_id == LTT_FACILITY_CORE)) { + switch((enum ltt_core_events)tf->event.event_id) { + case LTT_EVENT_FACILITY_LOAD: + size = strlen((char*)tf->event.data) + 1; + //g_debug("Update Event facility load of facility %s", (char*)tf->event.data); + size += ltt_align(size, sizeof(guint32), tf->has_alignment); + size += sizeof(struct LttFacilityLoad); + break; + case LTT_EVENT_FACILITY_UNLOAD: + //g_debug("Update Event facility unload"); + size = sizeof(struct LttFacilityUnload); + break; + case LTT_EVENT_STATE_DUMP_FACILITY_LOAD: + size = strlen((char*)tf->event.data) + 1; + size += ltt_align(size, sizeof(guint32), tf->has_alignment); + //g_debug("Update Event facility load state dump of facility %s", + // (char*)tf->event.data); + size += sizeof(struct LttStateDumpFacilityLoad); + break; + case LTT_EVENT_HEARTBEAT: + //g_debug("Update Event heartbeat"); + size = sizeof(TimeHeartbeat); + break; + case LTT_EVENT_HEARTBEAT_FULL: + //g_debug("Update Event heartbeat full"); + tscdata = (char*)(tf->event.data); + tf->event.tsc = ltt_get_uint64(LTT_GET_BO(tf), tscdata); + tf->buffer.tsc = tf->event.tsc; + tf->event.event_time = ltt_interpolate_time(tf, &tf->event); + size = sizeof(TimeHeartbeatFull); + size += ltt_align(size, sizeof(guint64), tf->has_alignment); + break; + default: + g_warning("Error in getting event size : tracefile %s, " + "unknown event id %hhu in core facility.", + g_quark_to_string(tf->name), + tf->event.event_id); + goto event_id_error; + + } + goto no_offset; /* Skip the field computation */ + } else { g_warning("Unknown facility %hhu (0x%hhx) in tracefile %s", tf->event.facility_id, tf->event.facility_id, g_quark_to_string(tf->name)); goto facility_error; } + } - LttEventType *event_type = - ltt_facility_eventtype_get(f, tf->event.event_id); + LttEventType *event_type = + ltt_facility_eventtype_get(f, tf->event.event_id); - if(!event_type) { - g_warning("Unknown event id %hhu in facility %s in tracefile %s", - tf->event.event_id, - g_quark_to_string(f->name), - g_quark_to_string(tf->name)); - goto event_type_error; - } - - /* Compute the dynamic offsets */ - compute_offsets(tf, f, event_type, &size, tf->event.data); - - //g_debug("Event root field : f.e %hhu.%hhu size %zd", - // tf->event.facility_id, - // tf->event.event_id, size); + if(!event_type) { + g_warning("Unknown event id %hhu in facility %s in tracefile %s", + tf->event.event_id, + g_quark_to_string(f->name), + g_quark_to_string(tf->name)); + goto event_type_error; } + /* Compute the dynamic offsets */ + compute_offsets(tf, f, event_type, &size, tf->event.data); + + //g_debug("Event root field : f.e %hhu.%hhu size %zd", + // tf->event.facility_id, + // tf->event.event_id, size); + +no_offset: tf->event.data_size = size; /* Check consistency between kernel and LTTV structure sizes */ @@ -2073,7 +2217,13 @@ void ltt_update_event_size(LttTracefile *tf) /* Event size too big to fit in the event size field */ tf->event.event_size = tf->event.data_size; } - g_assert(tf->event.data_size == tf->event.event_size); + if (tf->event.data_size != tf->event.event_size) { + g_error("Kernel/LTTV event size differs for event %s.%s: kernel %u, LTTV %u", + g_quark_to_string(f->name), g_quark_to_string(event_type->name), + tf->event.event_size, tf->event.data_size); + exit(-1); + } + //g_assert(tf->event.data_size == tf->event.event_size); return; @@ -2386,9 +2536,22 @@ void field_compute_static_size(LttFacility *fac, LttField *field) ****************************************************************************/ -gint precompute_fields_offsets(LttFacility *fac, LttField *field, off_t *offset) +gint precompute_fields_offsets(LttFacility *fac, LttField *field, off_t *offset, gint is_compact) { LttType *type = &field->field_type; + + if(unlikely(is_compact)) { + g_assert(field->field_size != 0); + /* FIXME THIS IS A HUUUUUGE hack : + * offset is between the compact_data field in struct LttEvent + * and the address of the field root in the memory map. + * ark. Both will stay at the same addresses while the event + * is readable, so it's ok. + */ + field->offset_root = 0; + field->fixed_root = FIELD_FIXED; + return 0; + } switch(type->type_class) { case LTT_INT_FIXED: @@ -2463,7 +2626,7 @@ gint precompute_fields_offsets(LttFacility *fac, LttField *field, off_t *offset) field->fixed_root = FIELD_FIXED; child = &g_array_index(type->fields, LttField, 0); - ret = precompute_fields_offsets(fac, child, offset); + ret = precompute_fields_offsets(fac, child, offset, is_compact); g_assert(ret == 0); /* Seq len cannot have variable len */ child = &g_array_index(type->fields, LttField, 1); @@ -2492,7 +2655,7 @@ gint precompute_fields_offsets(LttFacility *fac, LttField *field, off_t *offset) for(i=0; i< type->fields->len; i++) { child = &g_array_index(type->fields, LttField, i); - ret = precompute_fields_offsets(fac, child, offset); + ret = precompute_fields_offsets(fac, child, offset, is_compact); if(ret) break; } @@ -2514,7 +2677,7 @@ gint precompute_fields_offsets(LttFacility *fac, LttField *field, off_t *offset) for(i=0; i< type->fields->len; i++) { *offset = field->offset_root; child = &g_array_index(type->fields, LttField, i); - ret = precompute_fields_offsets(fac, child, offset); + ret = precompute_fields_offsets(fac, child, offset, is_compact); if(ret) break; } @@ -2556,7 +2719,10 @@ void precompute_offsets(LttFacility *fac, LttEventType *event) /* Precompute all known offsets */ for(i=0; ifields->len; i++) { LttField *field = &g_array_index(event->fields, LttField, i); - ret = precompute_fields_offsets(fac, field, &offset); + if(event->has_compact_data && i == 0) + ret = precompute_fields_offsets(fac, field, &offset, 1); + else + ret = precompute_fields_offsets(fac, field, &offset, 0); if(ret) break; } } @@ -2856,7 +3022,7 @@ gint check_fields_compatibility(LttEventType *event_type1, break; case LTT_NONE: default: - g_error("precompute_fields_offsets : unknown type"); + g_error("check_fields_compatibility : unknown type"); } end: @@ -3102,6 +3268,7 @@ static void __attribute__((constructor)) init(void) { LTT_FACILITY_NAME_HEARTBEAT = g_quark_from_string("heartbeat"); LTT_EVENT_NAME_HEARTBEAT = g_quark_from_string("heartbeat"); + LTT_EVENT_NAME_HEARTBEAT_FULL = g_quark_from_string("heartbeat_full"); LTT_TRACEFILE_NAME_FACILITIES = g_quark_from_string("/control/facilities"); }