0

我想知道您在将 EventSource 用于常见且可以在同一流程中多次使用的组件方面的经验。

一个简单的例子。我的共享组件是 TestQueue,我想在我的进程中使用它几次,并在 PerfView 中再次使用它来查看哪个事件属于哪个队列。

public class TestQueue<T>
{
    private readonly IEtwQueue _etwQueue;
    private readonly Queue<T> _instance = new Queue<T>();

    public TestQueue(IEtwQueue etwQueue)
    {
        _etwQueue = etwQueue;
    }

    public void Enqueue(T item)
    {
        _instance.Enqueue(item);
        _etwQueue.CommandEnqueued(_instance.Count);
    }

    public T Dequeue()
    {
        _etwQueue.CommandDequed(_instance.Count);
        return _instance.Dequeue();
    }
}

public interface IEtwQueue
{
    void CommandEnqueued(int items);
    void CommandDequed(int items);
}

[EventSource(Name = "Test-ETW-Queue")]
public class EtwQueue : EventSource, IEtwQueue
{
    public static EtwQueue Log = new EtwQueue();

    private EtwQueue() { }

    [Event(1)]
    public void CommandEnqueued(int items) { if (IsEnabled()) WriteEvent(1, items); }

    [Event(2)]
    public void CommandDequed(int items) { if (IsEnabled()) WriteEvent(2, items); }
}

我想这样使用它:

TestQueue<string> testStringQueue = new TestQueue<string>(EtwQueue.Log);
TestQueue<int> testIntQueue = new TestQueue<int>(EtwQueue.Log);
testIntQueue.Enqueue(15);
testStringQueue.Enqueue("X");

这是我在 PerfView 中的内容:

在此处输入图像描述

这两个事件之间没有区别。我想知道如何识别它们,以便某些名称(字符串)或 ID 成为事件名称的一部分?我知道我可以使用任务对事件进行逻辑分组,但这不是我所期望的,特别是因为它们必须在事件源中预定义。Activity ID 在用例中也是一样的。

干杯!


实现两个 EventSource 的一种更好的方法是通过自定义实现的构造函数传递事件源名称。也许这就是这样做的方法:)

所以自定义事件源类没有 EventSource 属性,构造函数有事件源名称参数:

public class EtwQueueEventSource : EventSource, IEtwQueue
{
    public EtwQueueEventSource(string sourceName) : base(sourceName) { }

    [Event(1)]
    public void CommandEnqueued(int items) { if (IsEnabled()) WriteEvent(1, items); }

    [Event(2)]
    public void CommandDequed(int items) { if (IsEnabled()) WriteEvent(2, items); }
}

所以之前的使用示例变成了这样:

TestQueue<string> testStringQueue = new TestQueue<string>(new EtwQueueEventSource("Test-ETW-Queue-String"));
TestQueue<int> testIntQueue = new TestQueue<int>(new EtwQueueEventSource("Test-ETW-Queue-Integer"));
testIntQueue.Enqueue(15);
testStringQueue.Enqueue("X");

性能视图

4

1 回答 1

1

我将添加一个参数,而不是使用两个源,您可以在其中传递队列的名称和对象的 ToString 表示。

public class TestQueue<T>
{
    private readonly IEtwQueue _etwQueue;
    private readonly string _queueName;
    private readonly Queue<T> _instance = new Queue<T>();

    public TestQueue(IEtwQueue etwQueue, string queueName)
    {
        _etwQueue = etwQueue;
        _queueName = queueName;
    }

    public void Enqueue(T item)
    {
        _instance.Enqueue(item);

        if(_etwQueue.IsEnabled()) //So we only call item.ToString() if the queue is enabled.
        {
            _etwQueue.CommandEnqueued(_instance.Count, item.ToString(), queueName);
        }
    }

    public T Dequeue()
    {
        T item = _instance.Dequeue();
        if(_etwQueue.IsEnabled()) //So we only call item.ToString() if the queue is enabled.
        {
            _etwQueue.CommandDequed(_instance.Count, item.ToString(), queueName);
        }
        return 
    }
}

public interface IEtwQueue
{
    void CommandEnqueued(int items, string itemDescription, string queueName);
    void CommandDequed(int items, string itemDescription, string queueName);
}

[EventSource(Name = "Test-ETW-Queue")]
public class EtwQueue : EventSource, IEtwQueue
{
    public static EtwQueue Log = new EtwQueue();

    private EtwQueue() { }

    [Event(1)]
    public void CommandEnqueued(int items, string itemDescription, string queueName) 
    { 
        if (IsEnabled()) WriteEvent(1, items, itemDescription, queueName); 
    }

    [Event(2)]
    public void CommandDequed(int items, string itemDescription, string queueName)
    { 
        if (IsEnabled()) WriteEvent(2, items, itemDescription, queueName); 
    }

但是,如果您希望引发> 1000 / 秒的事件,您可能希望通过调用不安全代码来提高性能,WriteEventCore以使重载WriteEvent将 aint, int, string, string作为 4 个参数,而不是使用较慢的int, params object[]` 重载。

[EventSource(Name = "Test-ETW-Queue")]
public class EtwQueue : EventSource
{
    public static EtwQueue Log = new EtwQueue();

    private EtwQueue() { }

    [Event(1)]
    public void CommandEnqueued(int items, string itemDescription, string queueName)
    {
        if (IsEnabled()) WriteEvent(1, items, itemDescription, queueName);
    }

    [Event(2)]
    public void CommandDequed(int items, string itemDescription, string queueName)
    {
        if (IsEnabled()) WriteEvent(2, items, itemDescription, queueName);
    }

    [NonEvent]
    public unsafe void WriteEvent(int eventId, int arg1, string arg2, string arg3)
    {
        if (arg2 == null) arg2 = "";
        if (arg3 == null) arg3 = "";

        fixed (char* string2Bytes = arg2)
        fixed (char* string3Bytes = arg3)
        {
            EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
            descrs[0].DataPointer = (IntPtr)(&arg1);
            descrs[0].Size = 4;
            descrs[1].DataPointer = (IntPtr)string2Bytes;
            descrs[1].Size = ((arg2.Length + 1) * 2);
            descrs[2].DataPointer = (IntPtr)string3Bytes;
            descrs[2].Size = ((arg3.Length + 1) * 2);
            WriteEventCore(eventId, 3, descrs);
        }
    }
}
于 2017-04-12T16:32:26.060 回答