private IList <CtfStreamPlayback> GeneratePlaybackStreams(ICtfInput source, CtfPlaybackOptions playbackOptions) { var playbackStreams = new List <CtfStreamPlayback>(); // Initialize packets from all streams, and sort by times foreach (var trace in source.Traces) { var metadataParser = customization.CreateMetadataParser(trace); ICtfMetadata metadata = metadataParser.Parse(trace.MetadataStream.Stream); for (int streamIndex = 0; streamIndex < trace.EventStreams.Count; streamIndex++) { var stream = trace.EventStreams[streamIndex]; var eventStream = new CtfEventStream(stream, metadata, customization); var streamPlayback = new CtfStreamPlayback(eventStream, playbackOptions, cancellationToken); if (eventStream.ByteCount > 0 && streamPlayback.MoveToNextEvent()) { Debug.Assert(streamPlayback.CurrentEvent != null); playbackStreams.Add(streamPlayback); this.streamToTrace.Add(streamPlayback, trace); this.totalBytesToProcess += stream.ByteCount; } else { Debug.Assert(false, eventStream.StreamSource + " appears to have no data.\n\n Ignoring the error will cause the trace to be partially loaded."); } } } return(playbackStreams); }
/// <inheritdoc /> public ICtfEventDescriptor GetEventDescriptor( ICtfEvent ctfEvent, ICtfMetadata metadata) { uint id = this.GetEventId(ctfEvent); ICtfEventDescriptor eventDescriptor; if (metadata is PerfMetadata typedMetadata) { // optimization if we get our own metadata back // we'll check this below typedMetadata.EventByEventId.TryGetValue(id, out eventDescriptor); } else { eventDescriptor = metadata.Events.FirstOrDefault(x => x.Id == id); } if (eventDescriptor == null) { throw new PerfPlaybackException($"Unable to find event descriptor for event id={id}."); } return(eventDescriptor); }
public virtual CtfTimestamp GetTimestampFromEventHeader(ICtfEvent ctfEvent, ICtfMetadata metadata, CtfTimestamp previousTimestamp) { var variantStruct = GetStreamEventHeaderStructure(ctfEvent); Debug.Assert(variantStruct != null); if (!variantStruct.FieldsByName.TryGetValue("timestamp", out var timestampValue)) { throw new LTTngPlaybackException("stream.event.header variant 'v' struct has no 'timestamp' field"); } if (!(timestampValue is CtfIntegerValue timestampInteger)) { throw new LTTngPlaybackException("stream.event.header variant 'v' struct field 'timestamp'" + " is not an integer"); } if (previousTimestamp is null) { // todo:I think we need to do something else for this case, especially if the integer size is < 64 // not sure what yet. maybe base it on the clock's offset? return(new CtfTimestamp(this.MetadataCustomization, metadata, timestampInteger)); } // Timestamps aren't actually absolute values. To quote from CTF spec 1.8.2 section 8: // For a N-bit integer type referring to a clock, if the integer overflows compared to the N low order bits // of the clock prior value found in the same stream, then it is assumed that one, and only one, overflow // occurred. It is therefore important that events encoding time on a small number of bits happen frequently // enough to detect when more than one N-bit overflow occurs. // So to determine a timestamp, we must know the previous timestamp. If they're all the same number of bits, it // wouldn't be necessary (I don't think so anyways). But some timestamps are smaller than others. if (timestampInteger.Descriptor.Size < 64) { if (!timestampInteger.Value.TryGetInt64(out long thisTimestamp)) { Debug.Assert(false); throw new CtfPlaybackException("Unable to retrieve timestamp as long."); } long previous = (long)previousTimestamp.NanosecondsFromClockBase; long oneBitBeyondBitsUsed = 1L << (byte)timestampInteger.Descriptor.Size; long bitMask = ~(oneBitBeyondBitsUsed - 1); long highBitsFromPreviousTimestamp = previous & bitMask; long newTimestamp = highBitsFromPreviousTimestamp | thisTimestamp; if (newTimestamp < previous) { // handle the overflow case newTimestamp += oneBitBeyondBitsUsed; Debug.Assert(newTimestamp > previous); } return(new CtfTimestamp(this.MetadataCustomization, metadata, timestampInteger, newTimestamp)); } return(new CtfTimestamp(this.MetadataCustomization, metadata, timestampInteger)); }
public CtfEventStream( ICtfInputStream inputStream, ICtfMetadata metadata, ICtfPlaybackCustomization playbackCustomization) { this.InputStream = inputStream; this.Metadata = metadata; this.PlaybackCustomization = playbackCustomization; }
internal TraceContext(ICtfMetadata metadata) { if (metadata.EnvironmentDescriptor.Properties.TryGetValue("hostname", out string hostName)) { this.HostName = hostName; } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("domain", out string domain)) { this.Domain = domain; } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("sysname", out string sysName)) { this.SysName = sysName; } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("kernel_release", out string kernelRelease)) { this.KernelRelease = kernelRelease; } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("kernel_version", out string kernelVersion)) { this.KernelVersion = kernelVersion; } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("tracer_name", out string tracerName)) { this.TracerName = tracerName; } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("tracer_major", out string tracerMajor)) { if (uint.TryParse(tracerMajor, out uint majorTracerVersion)) { this.TracerMajor = majorTracerVersion; } } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("tracer_minor", out string tracerMinor)) { if (uint.TryParse(tracerMinor, out uint minorTracerVersion)) { this.TracerMinor = minorTracerVersion; } } if (metadata.EnvironmentDescriptor.Properties.TryGetValue("tracer_patchlevel", out string tracerPatchLevel)) { if (uint.TryParse(tracerPatchLevel, out uint patchLevelTracerVersion)) { this.TracerMajor = patchLevelTracerVersion; } } }
/// <summary> /// Constructor /// </summary> /// <param name="metadataCustomization">Extensibility points</param> /// <param name="metadata">The active metadata relevant to this timestamp</param> /// <param name="integerValue">Integer representation of the timestamp</param> /// <param name="timestampValue">Timestamp value in units specified by the ClockDescriptor</param> public CtfTimestamp(ICtfMetadataCustomization metadataCustomization, ICtfMetadata metadata, CtfIntegerValue integerValue, long timestampValue) : this(metadataCustomization, metadata, integerValue) { if (timestampValue < 0) { throw new ArgumentException("Negative timestamp value is not supported.", nameof(timestampValue)); } this.NanosecondsFromClockBase = ConvertTimeToNanoseconds((ulong)timestampValue); }
/// <summary> /// Constructor /// </summary> /// <param name="metadataCustomization">Extensibility points</param> /// <param name="metadata">The active metadata relevant to this timestamp</param> /// <param name="integerValue">integer representation of the timestamp</param> public CtfTimestamp(ICtfMetadataCustomization metadataCustomization, ICtfMetadata metadata, CtfIntegerValue integerValue) { this.BaseIntegerValue = integerValue; string clockName = metadataCustomization.GetTimestampClockName(integerValue); if (string.IsNullOrWhiteSpace(clockName)) { if (!string.IsNullOrWhiteSpace(integerValue.MapValue)) { throw new CtfPlaybackException($"Unable to parse integer map value as a clock: {integerValue.MapValue}"); } if (metadata.Clocks?.Count == 1) { clockName = metadata.Clocks[0].Name; } else { Debug.Assert(false, "Add support for default clock that increments once per nanosecond: ctf spec 1.8.2 section 8"); throw new NotImplementedException("This library doesn't currently support a default clock."); } } if (!metadata.ClocksByName.TryGetValue(clockName, out var clockDescriptor)) { throw new CtfPlaybackException($"Unable to retrieve clock descriptor for timestamp value: {integerValue.MapValue}"); } this.ClockDescriptor = clockDescriptor; if (!this.BaseIntegerValue.Value.TryGetInt64(out long value)) { throw new CtfPlaybackException("Unable to retrieve timestamp as long."); } this.NanosecondsFromClockBase = ConvertIntegerValueToNanoseconds(this.BaseIntegerValue); this.ClockName = metadataCustomization.GetTimestampClockName(integerValue); this.ClockOffsetFromPosixEpochInNanoseconds = ConvertTimeToNanoseconds(this.ClockDescriptor.Offset); }
public bool GetTimestampsFromPacketContext( ICtfPacket ctfPacket, ICtfMetadata metadata, out CtfTimestamp start, out CtfTimestamp end) { start = null; end = null; if (!(ctfPacket.StreamPacketContext is CtfStructValue packetContextStruct)) { throw new PerfPlaybackException("The stream.packet.context is not a structure."); } if (!packetContextStruct.FieldsByName.TryGetValue("timestamp_begin", out var startFieldValue)) { return(false); } if (!packetContextStruct.FieldsByName.TryGetValue("timestamp_end", out var endFieldValue)) { return(false); } if (!(startFieldValue is CtfIntegerValue startFieldInteger)) { return(false); } if (!(endFieldValue is CtfIntegerValue endFieldInteger)) { return(false); } start = new CtfTimestamp(this.MetadataCustomization, metadata, startFieldInteger); end = new CtfTimestamp(this.MetadataCustomization, metadata, endFieldInteger); return(true); }
public void ProcessEvent(ICtfEvent ctfEvent, ICtfPacket eventPacket, ICtfTraceInput traceInput, ICtfInputStream ctfEventStream, ICtfMetadata metadata) { var eventDescriptor = ctfEvent.EventDescriptor as EventDescriptor; Debug.Assert(eventDescriptor != null); if (eventDescriptor == null) { throw new PerfPlaybackException("EventDescriptor is not an Perf descriptor."); } if (!this.streamToCpu.TryGetValue(ctfEventStream, out var cpuId)) { var cpuIndex = ctfEventStream.StreamSource.LastIndexOf('_'); string cpu = ctfEventStream.StreamSource.Substring(cpuIndex + 1); if (!uint.TryParse(cpu, out cpuId)) { Debug.Assert(false, "Unable to parse cpu from Perf stream channel"); cpuId = uint.MaxValue; } this.streamToCpu.Add(ctfEventStream, cpuId); } if (!this.traceContexts.TryGetValue(traceInput, out var traceContext)) { traceContext = new TraceContext(metadata); this.traceContexts.Add(traceInput, traceContext); } var callbackEvent = new PerfEvent(ctfEvent); var callbackContext = new PerfContext(this.metadataCustomization, ctfEventStream, traceContext) { // todo: when supporting multiple traces, this timestamp needs to become relative to the earliest timestamp all traces // todo: when supporting multiple traces, this one event number needs to become cumulative across traces, and one specific to the current trace CurrentCpu = cpuId, Timestamp = (long)ctfEvent.Timestamp.NanosecondsFromClockBase,/// - this.baseTimestamp, CurrentEventNumber = this.eventNumber, CurrentEventNumberWithinTrace = this.eventNumber, }; foreach (var callback in this.eventCallbacks) { callback(callbackEvent, callbackContext); } ++this.eventNumber; }
public CtfEvent(PacketReader packetReader, ICtfMetadata metadata, ICtfPacket owningPacket) { this.packetReader = packetReader; this.owningPacket = owningPacket; this.metadata = metadata; }