提交 1efeb493 编写于 作者: V Victor "Nate" Graf 提交者: GitHub

Remove unnecessary buffer copy from EventPipe::WriteEvent pipeline (dotnet/coreclr#13347)

* [WIP] Eliminate extra buffer copy with new api path

* Copy blobs to a flat buffer is Rundown is on

* Refactor to use payload class and dedupe code

* Add contracts

* Fix many small errors

* Make names unambiguous

* Add EventPipe::WriteEventBlob to ecalllist.h

* Address code review

* Add test and fix a buffer copy bug

* Copy data instead of data pointer

* Add optional output file arg to tests

* Change failure return code

* Renamed variables for clarity


Commit migrated from https://github.com/dotnet/coreclr/commit/421f9e7c64b05c71db6ef71791998c06249953f6
上级 2bd43c30
......@@ -171,5 +171,9 @@ internal static class EventPipeInternal
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
internal static extern unsafe void WriteEvent(IntPtr eventHandle, uint eventID, void* pData, uint length, Guid* activityId, Guid* relatedActivityId);
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
internal static extern unsafe void WriteEventData(IntPtr eventHandle, uint eventID, EventProvider.EventData** pEventData, uint dataCount, Guid* activityId, Guid* relatedActivityId);
}
}
......@@ -62,28 +62,11 @@ uint IEventProvider.EventUnregister(long registrationHandle)
{
if (userDataCount == 0)
{
EventPipeInternal.WriteEvent(eventHandle, eventID, null, 0, activityId, relatedActivityId);
EventPipeInternal.WriteEventData(eventHandle, eventID, null, 0, activityId, relatedActivityId);
return 0;
}
uint length = 0;
for (int i = 0; i < userDataCount; i++)
{
length += userData[i].Size;
}
byte[] data = new byte[length];
fixed (byte *pData = data)
{
uint offset = 0;
for (int i = 0; i < userDataCount; i++)
{
byte * singleUserDataPtr = (byte *)(userData[i].Ptr);
uint singleUserDataSize = userData[i].Size;
WriteToBuffer(pData, length, ref offset, singleUserDataPtr, singleUserDataSize);
}
EventPipeInternal.WriteEvent(eventHandle, eventID, pData, length, activityId, relatedActivityId);
}
EventPipeInternal.WriteEventData(eventHandle, eventID, &userData, (uint) userDataCount, activityId, relatedActivityId);
}
return 0;
}
......
......@@ -110,7 +110,7 @@ def generateClrEventPipeWriteEventsImpl(
WriteEventImpl.append(
" EventPipe::WriteEvent(*EventPipeEvent" +
eventName +
", nullptr, 0);\n")
", (BYTE*) nullptr, 0);\n")
WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n")
......
......@@ -1245,6 +1245,7 @@ FCFuncStart(gEventPipeInternalFuncs)
QCFuncElement("DefineEvent", EventPipeInternal::DefineEvent)
QCFuncElement("DeleteProvider", EventPipeInternal::DeleteProvider)
QCFuncElement("WriteEvent", EventPipeInternal::WriteEvent)
QCFuncElement("WriteEventData", EventPipeInternal::WriteEventData)
FCFuncEnd()
#endif // FEATURE_PERFTRACING
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include "clrtypes.h"
#include "safemath.h"
#include "common.h"
#include "eventpipe.h"
#include "eventpipebuffermanager.h"
......@@ -38,6 +40,146 @@ extern "C" void InitProvidersAndEvents();
extern "C" void InitProvidersAndEvents();
#endif
EventPipeEventPayload::EventPipeEventPayload(BYTE *pData, unsigned int length)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
m_pData = pData;
m_pEventData = NULL;
m_eventDataCount = 0;
m_allocatedData = false;
m_size = length;
}
EventPipeEventPayload::EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
m_pData = NULL;
m_pEventData = pEventData;
m_eventDataCount = eventDataCount;
m_allocatedData = false;
S_UINT32 tmp_size = S_UINT32(0);
for (unsigned int i=0; i<m_eventDataCount; i++)
{
tmp_size += S_UINT32(m_pEventData[i]->Size);
}
if (tmp_size.IsOverflow())
{
// If there is an overflow, drop the data and create an empty payload
m_pEventData = NULL;
m_eventDataCount = 0;
m_size = 0;
}
else
{
m_size = tmp_size.Value();
}
}
EventPipeEventPayload::~EventPipeEventPayload()
{
CONTRACTL
{
NOTHROW;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
if(m_allocatedData && m_pData != NULL)
{
delete[] m_pData;
m_pData = NULL;
}
}
void EventPipeEventPayload::Flatten()
{
CONTRACTL
{
NOTHROW;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
if(m_size > 0)
{
if (!IsFlattened())
{
BYTE* tmp_pData = new (nothrow) BYTE[m_size];
if (tmp_pData != NULL)
{
m_allocatedData = true;
CopyData(tmp_pData);
m_pData = tmp_pData;
}
}
}
}
void EventPipeEventPayload::CopyData(BYTE *pDst)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
if(m_size > 0)
{
if(IsFlattened())
{
memcpy(pDst, m_pData, m_size);
}
else if(m_pEventData != NULL)
{
unsigned int offset = 0;
for(unsigned int i=0; i<m_eventDataCount; i++)
{
memcpy(pDst + offset, (BYTE*)m_pEventData[i]->Ptr, m_pEventData[i]->Size);
offset += m_pEventData[i]->Size;
}
}
}
}
BYTE* EventPipeEventPayload::GetFlatData()
{
CONTRACTL
{
NOTHROW;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
if (!IsFlattened())
{
Flatten();
}
return m_pData;
}
void EventPipe::Initialize()
{
STANDARD_VM_CONTRACT;
......@@ -283,6 +425,34 @@ void EventPipe::DeleteProvider(EventPipeProvider *pProvider)
}
void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
EventPipeEventPayload payload(pData, length);
EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
}
void EventPipe::WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
EventPipeEventPayload payload(pEventData, eventDataCount);
EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
}
void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
{
CONTRACTL
{
......@@ -309,7 +479,7 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng
if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
{
if(!s_pBufferManager->WriteEvent(pThread, event, pData, length, pActivityId, pRelatedActivityId))
if(!s_pBufferManager->WriteEvent(pThread, event, payload, pActivityId, pRelatedActivityId))
{
// This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
return;
......@@ -317,19 +487,23 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng
}
else if(s_pConfig->RundownEnabled())
{
// Write synchronously to the file.
// We're under lock and blocking the disabling thread.
EventPipeEventInstance instance(
event,
pThread->GetOSThreadId(),
pData,
length,
pActivityId,
pRelatedActivityId);
if(s_pFile != NULL)
BYTE *pData = payload.GetFlatData();
if (pData != NULL)
{
s_pFile->WriteEvent(instance);
// Write synchronously to the file.
// We're under lock and blocking the disabling thread.
EventPipeEventInstance instance(
event,
pThread->GetOSThreadId(),
pData,
payload.GetSize(),
pActivityId,
pRelatedActivityId);
if(s_pFile != NULL)
{
s_pFile->WriteEvent(instance);
}
}
}
......@@ -337,25 +511,29 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng
{
GCX_PREEMP();
// Create an instance of the event for the synchronous path.
EventPipeEventInstance instance(
event,
pThread->GetOSThreadId(),
pData,
length,
pActivityId,
pRelatedActivityId);
// Write to the EventPipeFile if it exists.
if(s_pSyncFile != NULL)
BYTE *pData = payload.GetFlatData();
if (pData != NULL)
{
s_pSyncFile->WriteEvent(instance);
}
// Create an instance of the event for the synchronous path.
EventPipeEventInstance instance(
event,
pThread->GetOSThreadId(),
pData,
payload.GetSize(),
pActivityId,
pRelatedActivityId);
// Write to the EventPipeFile if it exists.
if(s_pSyncFile != NULL)
{
s_pSyncFile->WriteEvent(instance);
}
// Write to the EventPipeJsonFile if it exists.
if(s_pJsonFile != NULL)
{
s_pJsonFile->WriteEvent(instance);
// Write to the EventPipeJsonFile if it exists.
if(s_pJsonFile != NULL)
{
s_pJsonFile->WriteEvent(instance);
}
}
}
#endif // _DEBUG
......@@ -371,12 +549,14 @@ void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent
}
CONTRACTL_END;
EventPipeEventPayload payload(pData, length);
// Write the event to the thread's buffer.
if(s_pBufferManager != NULL)
{
// Specify the sampling thread as the "current thread", so that we select the right buffer.
// Specify the target thread so that the event gets properly attributed.
if(!s_pBufferManager->WriteEvent(pSamplingThread, *pEvent, pData, length, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents))
if(!s_pBufferManager->WriteEvent(pSamplingThread, *pEvent, payload, NULL /* pActivityId */, NULL /* pRelatedActivityId */, pTargetThread, &stackContents))
{
// This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
return;
......@@ -595,4 +775,22 @@ void QCALLTYPE EventPipeInternal::WriteEvent(
END_QCALL;
}
void QCALLTYPE EventPipeInternal::WriteEventData(
INT_PTR eventHandle,
unsigned int eventID,
EventData **pEventData,
unsigned int eventDataCount,
LPCGUID pActivityId,
LPCGUID pRelatedActivityId)
{
QCALL_CONTRACT;
BEGIN_QCALL;
_ASSERTE(eventHandle != NULL);
EventPipeEvent *pEvent = reinterpret_cast<EventPipeEvent *>(eventHandle);
EventPipe::WriteEvent(*pEvent, pEventData, eventDataCount, pActivityId, pRelatedActivityId);
END_QCALL;
}
#endif // FEATURE_PERFTRACING
......@@ -29,6 +29,69 @@ typedef void (*EventPipeCallback)(
void *FilterData,
void *CallbackContext);
struct EventData
{
public:
unsigned long Ptr;
unsigned int Size;
unsigned int Reserved;
};
class EventPipeEventPayload
{
private:
BYTE *m_pData;
EventData **m_pEventData;
unsigned int m_eventDataCount;
unsigned int m_size;
bool m_allocatedData;
// If the data is stored only as an array of EventData objects, create a flat buffer and copy into it
void Flatten();
public:
// Build this payload with a flat buffer inside
EventPipeEventPayload(BYTE *pData, unsigned int length);
// Build this payload to contain an array of EventData objects
EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount);
// If a buffer was allocated internally, delete it
~EventPipeEventPayload();
// Copy the data (whether flat or array of objects) into a flat buffer at pDst
// Assumes that pDst points to an appropriatly sized buffer
void CopyData(BYTE *pDst);
// Get the flat formatted data in this payload
// This method will allocate a buffer if it does not already contain flattened data
// This method will return NULL on OOM if a buffer needed to be allocated
BYTE* GetFlatData();
// Return true is the data is stored in a flat buffer
bool IsFlattened() const
{
LIMITED_METHOD_CONTRACT;
return m_pData != NULL;
}
// The the size of buffer needed to contain the stored data
unsigned int GetSize() const
{
LIMITED_METHOD_CONTRACT;
return m_size;
}
EventData** GetEventDataArray() const
{
LIMITED_METHOD_CONTRACT;
return m_pEventData;
}
};
class StackContents
{
private:
......@@ -186,10 +249,14 @@ class EventPipe
// Delete a provider.
static void DeleteProvider(EventPipeProvider *pProvider);
// Write out an event.
// Write out an event from a flat buffer.
// Data is written as a serialized blob matching the ETW serialization conventions.
static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
// Write out an event from an EventData array.
// Data is written as a serialized blob matching the ETW serialization conventions.
static void WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
// Write out a sample profile event.
static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0);
......@@ -199,6 +266,11 @@ class EventPipe
// Get the managed call stack for the specified thread.
static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents);
protected:
// The counterpart to WriteEvent which after the payload is constructed
static void WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
private:
// Callback function for the stack walker. For each frame walked, this callback is invoked.
......@@ -307,6 +379,13 @@ public:
void *pData,
unsigned int length,
LPCGUID pActivityId, LPCGUID pRelatedActivityId);
static void QCALLTYPE WriteEventData(
INT_PTR eventHandle,
unsigned int eventID,
EventData **pEventData,
unsigned int eventDataCount,
LPCGUID pActivityId, LPCGUID pRelatedActivityId);
};
#endif // FEATURE_PERFTRACING
......
......@@ -4,6 +4,7 @@
#include "common.h"
#include "eventpipe.h"
#include "eventpipeeventinstance.h"
#include "eventpipebuffer.h"
......@@ -46,7 +47,7 @@ EventPipeBuffer::~EventPipeBuffer()
}
}
bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int dataLength, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack)
bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack)
{
CONTRACTL
{
......@@ -58,7 +59,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *p
CONTRACTL_END;
// Calculate the size of the event.
unsigned int eventSize = sizeof(EventPipeEventInstance) + dataLength;
unsigned int eventSize = sizeof(EventPipeEventInstance) + payload.GetSize();
// Make sure we have enough space to write the event.
if(m_pCurrent + eventSize >= m_pLimit)
......@@ -77,7 +78,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *p
event,
pThread->GetOSThreadId(),
pDataDest,
dataLength,
payload.GetSize(),
pActivityId,
pRelatedActivityId);
......@@ -89,9 +90,9 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *p
}
// Write the event payload data to the buffer.
if(dataLength > 0)
if(payload.GetSize() > 0)
{
memcpy(pDataDest, pData, dataLength);
payload.CopyData(pDataDest);
}
// Save the most recent event timestamp.
......
......@@ -7,6 +7,7 @@
#ifdef FEATURE_PERFTRACING
#include "eventpipe.h"
#include "eventpipeevent.h"
#include "eventpipeeventinstance.h"
......@@ -81,7 +82,7 @@ public:
// Returns:
// - true: The write succeeded.
// - false: The write failed. In this case, the buffer should be considered full.
bool WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int dataLength, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack = NULL);
bool WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack = NULL);
// Get the timestamp of the most recent event in the buffer.
LARGE_INTEGER GetMostRecentTimeStamp() const;
......
......@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
#include "common.h"
#include "eventpipe.h"
#include "eventpipeconfiguration.h"
#include "eventpipebuffer.h"
#include "eventpipebuffermanager.h"
......@@ -217,7 +218,7 @@ void EventPipeBufferManager::DeAllocateBuffer(EventPipeBuffer *pBuffer)
}
}
bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread, StackContents *pStack)
bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread, StackContents *pStack)
{
CONTRACTL
{
......@@ -276,7 +277,7 @@ bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event,
else
{
// Attempt to write the event to the buffer. If this fails, we should allocate a new buffer.
allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, pData, length, pActivityId, pRelatedActivityId, pStack);
allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, payload, pActivityId, pRelatedActivityId, pStack);
}
}
......@@ -290,7 +291,7 @@ bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event,
// However, the GC is waiting on this call to return so that it can make forward progress. Thus it is not safe
// to switch to preemptive mode here.
unsigned int requestSize = sizeof(EventPipeEventInstance) + length;
unsigned int requestSize = sizeof(EventPipeEventInstance) + payload.GetSize();
pBuffer = AllocateBufferForThread(pThread, requestSize);
}
......@@ -299,7 +300,7 @@ bool EventPipeBufferManager::WriteEvent(Thread *pThread, EventPipeEvent &event,
// This is the second time if this thread did have one or more buffers, but they were full.
if(allocNewBuffer && pBuffer != NULL)
{
allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, pData, length, pActivityId, pRelatedActivityId, pStack);
allocNewBuffer = !pBuffer->WriteEvent(pEventThread, event, payload, pActivityId, pRelatedActivityId, pStack);
}
// Mark that the thread is no longer writing an event.
......
......@@ -7,6 +7,7 @@
#ifdef FEATURE_PERFTRACING
#include "eventpipe.h"
#include "eventpipefile.h"
#include "eventpipebuffer.h"
#include "spinlock.h"
......@@ -67,7 +68,7 @@ public:
// This is because the thread that writes the events is not the same as the "event thread".
// An optional stack trace can be provided for sample profiler events.
// Otherwise, if a stack trace is needed, one will be automatically collected.
bool WriteEvent(Thread *pThread, EventPipeEvent &event, BYTE *pData, unsigned int length, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread = NULL, StackContents *pStack = NULL);
bool WriteEvent(Thread *pThread, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, Thread *pEventThread = NULL, StackContents *pStack = NULL);
// Write the contents of the managed buffers to the specified file.
// The stopTimeStamp is used to determine when tracing was stopped to ensure that we
......
......@@ -10,11 +10,19 @@ class EventPipeSmoke
{
private static int allocIterations = 10000;
private static int trivialSize = 0x100000;
private static bool keepOutput = false;
static int Main(string[] args)
{
string outputFilename = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".netperf";
bool keepOutput = false;
// Use the first arg as an output filename if there is one
string outputFilename = null;
if (args.Length >= 1) {
outputFilename = args[0];
keepOutput = true;
}
else {
outputFilename = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".netperf";
}
Console.WriteLine("\tStart: Enable tracing.");
TraceControl.EnableDefault(outputFilename);
......@@ -49,7 +57,7 @@ static int Main(string[] args)
System.IO.File.Delete(outputFilename);
}
return pass ? 100 : 0;
return pass ? 100 : -1;
}
}
}
using System;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics.Tracing;
using Tracing.Tests.Common;
namespace Tracing.Tests
{
[EventSource(Name = "SimpleEventSource")]
class SimpleEventSource : EventSource
{
public SimpleEventSource() : base(true) { }
[Event(1)]
internal void Message(string msg) { this.WriteEvent(1, msg); }
}
class EventPipeSmoke
{
private static int messageIterations = 10000;
private static int trivialSize = 0x100000;
public static TraceConfiguration GetConfig(EventSource eventSource, string outputFile="default.netperf")
{
// Setup the configuration values.
uint circularBufferMB = 1024; // 1 GB
uint level = 5;//(uint)EventLevel.Informational;
TimeSpan profSampleDelay = TimeSpan.FromMilliseconds(1);
// Create a new instance of EventPipeConfiguration.
TraceConfiguration config = new TraceConfiguration(outputFile, circularBufferMB);
// Setup the provider values.
// Public provider.
string providerName = eventSource.Guid.ToString("D");
UInt64 keywords = 0xffffffffffffffff;
// Enable the provider.
config.EnableProvider(providerName, keywords, level);
// Set the sampling rate.
config.SetSamplingRate(profSampleDelay);
return config;
}
static int Main(string[] args)
{
bool keepOutput = false;
// Use the first arg as an output filename if there is one
string outputFilename = null;
if (args.Length >= 1) {
outputFilename = args[0];
keepOutput = true;
}
else {
outputFilename = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".netperf";
}
SimpleEventSource eventSource = new SimpleEventSource();
Console.WriteLine("\tStart: Enable tracing.");
TraceControl.Enable(GetConfig(eventSource, outputFilename));
Console.WriteLine("\tEnd: Enable tracing.\n");
Console.WriteLine("\tStart: Messaging.");
// Send messages
// Use random numbers and addition as a simple, human readble checksum
Random generator = new Random();
for(int i=0; i<messageIterations; i++)
{
int x = generator.Next(1,1000);
int y = generator.Next(1,1000);
string result = String.Format("{0} + {1} = {2}", x, y, x+y);
eventSource.Message(result);
}
Console.WriteLine("\tEnd: Messaging.\n");
Console.WriteLine("\tStart: Disable tracing.");
TraceControl.Disable();
Console.WriteLine("\tEnd: Disable tracing.\n");
FileInfo outputMeta = new FileInfo(outputFilename);
Console.WriteLine("\tCreated {0} bytes of data", outputMeta.Length);
bool pass = false;
if (outputMeta.Length > trivialSize){
pass = true;
}
if (keepOutput)
{
Console.WriteLine(String.Format("\tOutput file: {0}", outputFilename));
}
else
{
System.IO.File.Delete(outputFilename);
}
return pass ? 100 : -1;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid>
<OutputType>Exe</OutputType>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
<CLRTestKind>BuildAndRun</CLRTestKind>
<DefineConstants>$(DefineConstants);STATIC</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
</PropertyGroup>
<ItemGroup>
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
<Visible>False</Visible>
</CodeAnalysisDependentAssemblyPaths>
</ItemGroup>
<ItemGroup>
<Compile Include="EventSourceSmoke.cs" />
<ProjectReference Include="../common/common.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册