public long Run(ThroughputSessionContext sessionContext) { _eventHandler.Reset(_iterations - 1); _consumer.Start(); sessionContext.Start(); var spinWait = new SpinWait(); for (long i = 0; i < _iterations; i++) { var data = new PerfEvent { Value = i }; while (!_channel.Writer.TryWrite(data)) { spinWait.SpinOnce(); } spinWait.Reset(); } _eventHandler.Latch.WaitOne(); sessionContext.Stop(); _consumer.Stop(); sessionContext.SetBatchData(_eventHandler.BatchesProcessedCount.Value, _iterations); PerfTestUtil.FailIfNot(_expectedResult, _eventHandler.Value, $"Handler should have processed {_expectedResult} events, but was: {_eventHandler.Value}"); return(_iterations); }
public long Run(ThroughputSessionContext sessionContext) { _eventHandler.Reset(_iterations - 1); _consumer.Start(); sessionContext.Start(); var spinWait = new SpinWait(); for (long i = 0; i < _iterations; i++) { var data = new PerfEvent { Value = i }; while (_queue.Count == _bufferSize) { spinWait.SpinOnce(); } _queue.Enqueue(data); spinWait.Reset(); } _eventHandler.WaitForSequence(); sessionContext.Stop(); _consumer.Stop(); sessionContext.SetBatchData(_eventHandler.BatchesProcessed, _iterations); PerfTestUtil.FailIfNot(_expectedResult, _eventHandler.Value, $"Handler should have processed {_expectedResult} events, but was: {_eventHandler.Value}"); return(_iterations); }
public PerfGenericEvent(PerfEvent data, PerfContext context) { this.EventName = data.Name; this.Timestamp = data.Timestamp; this.Id = data.Id; this.CpuId = context.CurrentCpu; if (!(data.Payload is CtfStructValue payload)) { throw new CtfPlaybackException("Event data is corrupt."); } // As this is being written, all columns are of type 'T', so all rows are the same. For generic events, // where columns have different types for different rows, this means everything becomes a string. // // We don't want to keep around each event in memory, that would use too much memory. So for now convert // each field value to a string, which would happen anyways. // // If the consumer is smarter in the future and allows for multi-type columns, we can re-evaluate this // approach. We could probably generate a type from each event descriptor, and convert to that type. // this.FieldCount = payload.Fields.Count; this.events = new List <PerfGenericEventField>(this.FieldCount); foreach (var field in payload.Fields) { this.events.Add(new PerfGenericEventField(field.FieldName, field.GetValueAsString())); } }
private async Task PublishOneByOne() { for (long i = 0; i < _iterations; i++) { var data = new PerfEvent { Value = i }; await _channel.Writer.WriteAsync(data); } }
public CpuClockEvent(PerfEvent data, PerfContext context, SortedList <ulong, KernelSymbol> kernelSymbols) { this.Timestamp = data.Timestamp; this.Cpu = context.CurrentCpu; if (data.Payload != null) { if (data.Payload.FieldsByName.ContainsKey("perf_ip")) { Ip = data.Payload.ReadFieldAsUInt64("perf_ip"); if (kernelSymbols.Count > 0) { Ip_Symbol = FindSymbolForIp(Ip, kernelSymbols); } } if (data.Payload.FieldsByName.ContainsKey("perf_tid")) { Tid = data.Payload.ReadFieldAsUInt64("perf_tid"); } if (data.Payload.FieldsByName.ContainsKey("perf_pid")) { Pid = data.Payload.ReadFieldAsUInt64("perf_pid"); } if (data.Payload.FieldsByName.ContainsKey("perf_id")) { Id = data.Payload.ReadFieldAsUInt64("perf_id"); } if (data.Payload.FieldsByName.ContainsKey("perf_period")) { Perf_Period = data.Payload.ReadFieldAsUInt64("perf_period"); } if (data.Payload.FieldsByName.ContainsKey("perf_callchain_size")) { Perf_Callchain_Size = data.Payload.ReadFieldAsUInt64("perf_callchain_size"); } if (Perf_Callchain_Size > 0 && data.Payload.FieldsByName.ContainsKey("perf_callchain") && Perf_Callchain_Size < Int32.MaxValue) { CallStack = new string[Perf_Callchain_Size + 1]; var perf_Callchain = data.Payload.ReadFieldAsArray("perf_callchain").ReadAsUInt64Array(); CallStack[0] = "[Root]"; for (ulong stackIdx = 1; stackIdx <= Perf_Callchain_Size; stackIdx++) { var sym = FindSymbolForIp(perf_Callchain[Perf_Callchain_Size - stackIdx], kernelSymbols); CallStack[stackIdx] = sym != null ? sym.Name : null; } } } }
public void ProcessEvent(ICtfEvent ctfEvent, ICtfPacket eventPacket, ICtfTraceInput traceInput, ICtfInputStream ctfEventStream) { 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(this.metadataCustomization.PerfMetadata); 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; }
private bool OnEvent(PerfEvent @event, long sequence, bool endOfBatch) { _value.Value = _value.Value + @event.Value; if (endOfBatch) { BatchesProcessedCount.Value++; } if (_count == sequence) { _signal.Set(); } return(true); }
public override DataProcessingResult CookDataElement( PerfEvent data, PerfContext context, CancellationToken cancellationToken) { try { Events.AddEvent(new PerfGenericEvent(data, context)); this.MaximumEventFieldCount = Math.Max(data.Payload.Fields.Count, this.MaximumEventFieldCount); } catch (CtfPlaybackException e) { Console.Error.WriteLine($"Error consuming event: {e.Message}"); return(DataProcessingResult.CorruptData); } return(DataProcessingResult.Processed); }
public override DataProcessingResult CookDataElement(PerfEvent data, PerfContext context, CancellationToken cancellationToken) { lock (symProcessLock) { if (!attemptedProcessSymbols) { try { // TODO: This is hard-coded for now. We don't seem to have a good way to know/infer the trace path or choose this in the UI. CTF SDK change needed? var kallsymsFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "kallsyms"); if (File.Exists(kallsymsFile)) { using (StreamReader sr = new StreamReader(kallsymsFile)) { string line; while ((line = sr.ReadLine()) != null) { var ks = new KernelSymbol(line); if (KernelSymbols.ContainsKey(ks.Address)) { Console.Out.WriteLine($"Unable to add {line}. There is already an entry this address"); } else { KernelSymbols.Add(ks.Address, ks); } } } } } catch (Exception e) { Console.WriteLine($"Exception processing symbols: {e.Message}"); } finally { attemptedProcessSymbols = true; } } } try { if (data.Name == "cpu-clock") { CpuClockEvents.Add(new CpuClockEvent(data, context, KernelSymbols)); return(DataProcessingResult.Processed); } else { return(DataProcessingResult.Ignored); } } catch (CtfPlaybackException e) { Console.Error.WriteLine(e); return(DataProcessingResult.CorruptData); } }
public void Handle(PerfEvent message) { LastValue = message.Value; Interlocked.Increment(ref CallCount); }