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;
 }
示例#5
0
        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;
        }
示例#10
0
 public CtfEvent(PacketReader packetReader, ICtfMetadata metadata, ICtfPacket owningPacket)
 {
     this.packetReader = packetReader;
     this.owningPacket = owningPacket;
     this.metadata     = metadata;
 }