Imported Upstream version 4.8.0.309

Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-11-10 13:04:39 +00:00
parent ee1447783b
commit 94b2861243
4912 changed files with 390737 additions and 49310 deletions

View File

@@ -833,6 +833,15 @@ namespace System.Diagnostics.Tracing
{
collector.AddBinary(value);
}
public override object GetData(object value)
{
object val = base.GetData(value);
if (null == val)
val = "";
return val;
}
}
/// <summary>

View File

@@ -460,6 +460,7 @@ namespace System.Diagnostics.Tracing
}
this.WriteEventRaw(
eventName,
ref descriptor,
activityID,
childActivityID,
@@ -564,6 +565,7 @@ namespace System.Diagnostics.Tracing
}
this.WriteEventRaw(
eventName,
ref descriptor,
activityID,
childActivityID,
@@ -646,6 +648,7 @@ namespace System.Diagnostics.Tracing
eventTypes.typeInfo.WriteData(TraceLoggingDataCollector.Instance, ref data);
this.WriteEventRaw(
eventName,
ref descriptor,
pActivityId,
pRelatedActivityId,
@@ -665,7 +668,7 @@ namespace System.Diagnostics.Tracing
if (ex is EventSourceException)
throw;
else
ThrowEventSourceException(ex);
ThrowEventSourceException(eventName, ex);
}
finally
{
@@ -679,7 +682,7 @@ namespace System.Diagnostics.Tracing
if (ex is EventSourceException)
throw;
else
ThrowEventSourceException(ex);
ThrowEventSourceException(eventName, ex);
}
}
@@ -703,7 +706,7 @@ namespace System.Diagnostics.Tracing
eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>((IList<string>)payload.Keys);
}
DisptachToAllListeners(-1, pActivityId, eventCallbackArgs);
DispatchToAllListeners(-1, pActivityId, eventCallbackArgs);
}
#if !ES_BUILD_PCL

View File

@@ -99,7 +99,7 @@ namespace System.Diagnostics.Tracing
var newGroup = new FieldMetadata(
name,
TraceLoggingDataType.Struct,
0,
this.Tags,
this.BeginningBufferedArray);
this.AddField(newGroup);
result = new TraceLoggingMetadataCollector(this, newGroup);

View File

@@ -1,8 +1,6 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
#if !ES_BUILD_AGAINST_DOTNET_V35
using Contract = System.Diagnostics.Contracts.Contract;
#else
@@ -11,15 +9,16 @@ using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
#else
using System.Threading.Tasks;
namespace System.Diagnostics.Tracing
#endif
{
/// <summary>
/// Tracks activities. This is meant to be a singledon (accessed by the ActivityTracer.Instance static property)
/// Tracks activities. This is meant to be a singleton (accessed by the ActivityTracer.Instance static property)
///
/// Logically this is simply holds the m_current variable that holds the async local that holds the current ActivityInfo
/// An ActivityInfo is represents a actvity (which knows its creator and thus knows its path).
/// An ActivityInfo is represents a activity (which knows its creator and thus knows its path).
///
/// Most of the magic is in the async local (it gets copied to new tasks)
///
@@ -39,7 +38,7 @@ namespace System.Diagnostics.Tracing
/// On any normal event log the event with activityTracker.CurrentActivityId
/// </summary>
internal class ActivityTracker
{
{
/// <summary>
/// Called on work item begins. The activity name = providerName + activityName without 'Start' suffix.
@@ -55,15 +54,32 @@ namespace System.Diagnostics.Tracing
public void OnStart(string providerName, string activityName, int task, ref Guid activityId, ref Guid relatedActivityId, EventActivityOptions options)
{
if (m_current == null) // We are not enabled
return;
{
// We used to rely on the TPL provider turning us on, but that has the disadvantage that you don't get Start-Stop tracking
// until you use Tasks for the first time (which you may never do). Thus we change it to pull rather tan push for whether
// we are enabled.
if (m_checkedForEnable)
return;
m_checkedForEnable = true;
#if ES_BUILD_STANDALONE
Enable(); // Enable it unconditionally.
#else
if (System.Threading.Tasks.TplEtwProvider.Log.IsEnabled(EventLevel.Informational, System.Threading.Tasks.TplEtwProvider.Keywords.TasksFlowActivityIds))
Enable();
#endif
if(m_current == null)
{
return;
}
}
Contract.Assert((options & EventActivityOptions.Disable) == 0);
var currentActivity = m_current.Value;
var fullActivityName = NormalizeActivityName(providerName, activityName, task);
var etwLog = TplEtwProvider.Log;
if (etwLog.Debug)
if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStartEnter", fullActivityName);
etwLog.DebugFacilityMessage("OnStartEnterActivityState", ActivityInfo.LiveActivities(currentActivity));
@@ -100,17 +116,17 @@ namespace System.Diagnostics.Tracing
else
id = Interlocked.Increment(ref currentActivity.m_lastChildID);
// Remember the previous ID so we can log it
relatedActivityId = currentActivity != null ? currentActivity.ActivityId : Guid.Empty;
// The previous ID is my 'causer' and becomes my related activity ID
relatedActivityId = EventSource.CurrentThreadActivityId;
// Add to the list of started but not stopped activities.
ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, options);
ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, relatedActivityId, options);
m_current.Value = newActivity;
// Remember the current ID so we can log it
activityId = newActivity.ActivityId;
if (etwLog.Debug)
if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStartRetActivityState", ActivityInfo.LiveActivities(newActivity));
etwLog.DebugFacilityMessage1("OnStartRet", activityId.ToString(), relatedActivityId.ToString());
@@ -119,7 +135,7 @@ namespace System.Diagnostics.Tracing
/// <summary>
/// Called when a work item stops. The activity name = providerName + activityName without 'Stop' suffix.
/// It updates CurrentActivityId to track this fact. The Stop event associated with stop should log the ActivityID associated with the event.
/// It updates m_current variable to track this fact. The Stop event associated with stop should log the ActivityID associated with the event.
///
/// If activity tracing is not on, then activityId and relatedActivityId are not set
/// </summary>
@@ -131,13 +147,13 @@ namespace System.Diagnostics.Tracing
var fullActivityName = NormalizeActivityName(providerName, activityName, task);
var etwLog = TplEtwProvider.Log;
if (etwLog.Debug)
if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStopEnter", fullActivityName);
etwLog.DebugFacilityMessage("OnStopEnterActivityState", ActivityInfo.LiveActivities(m_current.Value));
}
for (; ;) // This is a retry loop.
for (; ; ) // This is a retry loop.
{
ActivityInfo currentActivity = m_current.Value;
ActivityInfo newCurrentActivity = null; // if we have seen any live activities (orphans), at he first one we have seen.
@@ -193,7 +209,7 @@ namespace System.Diagnostics.Tracing
m_current.Value = newCurrentActivity;
if (etwLog.Debug)
if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStopRetActivityState", ActivityInfo.LiveActivities(newCurrentActivity));
etwLog.DebugFacilityMessage("OnStopRet", activityId.ToString());
@@ -210,12 +226,12 @@ namespace System.Diagnostics.Tracing
[System.Security.SecuritySafeCritical]
public void Enable()
{
if (m_current == null)
if (m_current == null)
{
m_current = new AsyncLocal<ActivityInfo>(ActivityChanging);
}
}
/// <summary>
/// An activity tracker is a singleton, this is how you get the one and only instance.
/// </summary>
@@ -263,24 +279,25 @@ namespace System.Diagnostics.Tracing
// *******************************************************************************
/// <summary>
/// An ActivityInfo repesents a particular activity. It is almost read-only the only
/// An ActivityInfo represents a particular activity. It is almost read-only. The only
/// fields that change after creation are
/// m_lastChildID - used to generate unique IDs for the children activities and for the most part can be ignored.
/// m_stopped - indicates that this activity is dead
/// This read-only ness is important because an activity's m_creator chain forms the
/// This read-only-ness is important because an activity's m_creator chain forms the
/// 'Path of creation' for the activity (which is also its unique ID) but is also used as
/// the 'list of live parents' which indicate of those ancestors, which are alive (if they
/// are not marked dead they are alive).
/// </summary>
private class ActivityInfo
{
public ActivityInfo(string name, long uniqueId, ActivityInfo creator, EventActivityOptions options)
public ActivityInfo(string name, long uniqueId, ActivityInfo creator, Guid activityIDToRestore, EventActivityOptions options)
{
m_name = name;
m_eventOptions = options;
m_creator = creator;
m_uniqueId = uniqueId;
m_level = creator != null ? creator.m_level + 1 : 0;
m_activityIdToRestore = activityIDToRestore;
// Create a nice GUID that encodes the chain of activities that started this one.
CreateActivityPathGuid(out m_guid, out m_activityPathGuidOffset);
@@ -294,19 +311,19 @@ namespace System.Diagnostics.Tracing
}
}
public static string Path(ActivityInfo activityInfo)
public static string Path(ActivityInfo activityInfo)
{
if (activityInfo == null)
return("");
return ("");
return Path(activityInfo.m_creator) + "/" + activityInfo.m_uniqueId;
}
public override string ToString()
public override string ToString()
{
string dead = "";
if (m_stopped != 0)
dead = ",DEAD";
return m_name + "(" + Path(this) + dead + ")";
dead = ",DEAD";
return m_name + "(" + Path(this) + dead + ")";
}
public static string LiveActivities(ActivityInfo list)
@@ -331,10 +348,10 @@ namespace System.Diagnostics.Tracing
/// (rooted in an activity that predates activity tracking.
///
/// We wish to encode this path in the Guid to the extent that we can. Many of the paths have
/// many small numbers in them and we take advatage of this in the encoding to output as long
/// many small numbers in them and we take advantage of this in the encoding to output as long
/// a path in the GUID as possible.
///
/// Because of the possiblility of GUID collistion, we only use 96 of the 128 bits of the GUID
/// Because of the possibility of GUID collision, we only use 96 of the 128 bits of the GUID
/// for encoding the path. The last 32 bits are a simple checksum (and random number) that
/// identifies this as using the convention defined here.
///
@@ -347,7 +364,7 @@ namespace System.Diagnostics.Tracing
[System.Security.SecuritySafeCritical]
private unsafe void CreateActivityPathGuid(out Guid idRet, out int activityPathGuidOffset)
{
fixed (Guid* outPtr = &idRet)
fixed (Guid* outPtr = &idRet)
{
int activityPathGuidOffsetStart = 0;
if (m_creator != null)
@@ -355,13 +372,18 @@ namespace System.Diagnostics.Tracing
activityPathGuidOffsetStart = m_creator.m_activityPathGuidOffset;
idRet = m_creator.m_guid;
}
else
else
{
// We start with the appdomain number to make this unique among appdomains.
activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint) System.Threading.Thread.GetDomainID());
//
int appDomainID = 0;
#if !ES_BUILD_PCL
appDomainID = System.Threading.Thread.GetDomainID();
#endif
// We start with the appdomain number to make this unique among appdomains.
activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)appDomainID);
}
activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint) m_uniqueId);
activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)m_uniqueId);
// If the path does not fit, Make a GUID by incrementing rather than as a path, keeping as much of the path as possible
@@ -372,19 +394,19 @@ namespace System.Diagnostics.Tracing
/// <summary>
/// If we can't fit the activity Path into the GUID we come here. What we do is simply
/// generate a 4 byte number (s_nextOverflowId). Then look for an anscesor that has
/// generate a 4 byte number (s_nextOverflowId). Then look for an ancestor that has
/// sufficient space for this ID. By doing this, we preserve the fact that this activity
/// is a child (of unknown depth) from that ancestor.
/// </summary>
[System.Security.SecurityCritical]
private unsafe void CreateOverflowGuid(Guid* outPtr)
{
// Seach backwards for an ancestor that has sufficient space to put the ID.
for(ActivityInfo ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator)
// Search backwards for an ancestor that has sufficient space to put the ID.
for (ActivityInfo ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator)
{
if (ancestor.m_activityPathGuidOffset <= 10) // we need at least 2 bytes.
{
uint id = (uint) Interlocked.Increment(ref ancestor.m_lastChildID); // Get a unique ID
uint id = unchecked((uint)Interlocked.Increment(ref ancestor.m_lastChildID)); // Get a unique ID
// Try to put the ID into the GUID
*outPtr = ancestor.m_guid;
int endId = AddIdToGuid(outPtr, ancestor.m_activityPathGuidOffset, id, true);
@@ -397,8 +419,8 @@ namespace System.Diagnostics.Tracing
}
/// <summary>
/// The encoding for a list of numbers used to make Activity Guids. Basically
/// we operate on nibbles (which are nice becase they show up as hex digits). The
/// The encoding for a list of numbers used to make Activity GUIDs. Basically
/// we operate on nibbles (which are nice because they show up as hex digits). The
/// list is ended with a end nibble (0) and depending on the nibble value (Below)
/// the value is either encoded into nibble itself or it can spill over into the
/// bytes that follow.
@@ -409,18 +431,18 @@ namespace System.Diagnostics.Tracing
LastImmediateValue = 0xA,
PrefixCode = 0xB, // all the 'long' encodings go here. If the next nibble is MultiByte1-4
// than this is a 'overflow' id. Unlike the hierarchitcal IDs these are
// allocated densly but don't tell you anything about nesting. we use
// these when we run out of space in the GUID to store the path.
// than this is a 'overflow' id. Unlike the hierarchical IDs these are
// allocated densely but don't tell you anything about nesting. we use
// these when we run out of space in the GUID to store the path.
MultiByte1 = 0xC, // 1 byte follows. If this Nibble is in the high bits, it the high bits of the number are stored in the low nibble.
// commented out because the code does not explicitly reference the names (but they are logically defined).
// MultiByte2 = 0xD, // 2 bytes follow (we don't bother with the nibble optimzation)
// MultiByte3 = 0xE, // 3 bytes follow (we don't bother with the nibble optimzation)
// MultiByte4 = 0xF, // 4 bytes follow (we don't bother with the nibble optimzation)
// MultiByte2 = 0xD, // 2 bytes follow (we don't bother with the nibble optimization)
// MultiByte3 = 0xE, // 3 bytes follow (we don't bother with the nibble optimization)
// MultiByte4 = 0xF, // 4 bytes follow (we don't bother with the nibble optimization)
}
/// Add the acivity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId'
/// Add the activity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId'
/// Thus if this number is 6 that is where 'id' will be added. This will return 13 (12
/// is the maximum number of bytes that fit in a GUID) if the path did not fit.
/// If 'overflow' is true, then the number is encoded as an 'overflow number (which has a
@@ -450,9 +472,9 @@ namespace System.Diagnostics.Tracing
{
if (endPtr <= ptr + 2) // I need at least 2 bytes
return 13;
// Write out the prefix code nibble and the length nibble
WriteNibble(ref ptr, endPtr, (uint) NumberListCodes.PrefixCode);
WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.PrefixCode);
}
// The rest is the same for overflow and non-overflow case
WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.MultiByte1 + (len - 1));
@@ -460,7 +482,7 @@ namespace System.Diagnostics.Tracing
// Do we have an odd nibble? If so flush it or use it for the 12 byte case.
if (ptr < endPtr && *ptr != 0)
{
// If the value < 4096 we can use the nibble we are otherwise just outputing as padding.
// If the value < 4096 we can use the nibble we are otherwise just outputting as padding.
if (id < 4096)
{
// Indicate this is a 1 byte multicode with 4 high order bits in the lower nibble.
@@ -471,7 +493,7 @@ namespace System.Diagnostics.Tracing
}
// Write out the bytes.
while(0 < len)
while (0 < len)
{
if (endPtr <= ptr)
{
@@ -514,14 +536,15 @@ namespace System.Diagnostics.Tracing
#endregion // CreateGuidForActivityPath
readonly internal string m_name; // The name used in the 'start' and 'stop' APIs to help match up
readonly long m_uniqueId; // a small number that makes this activity unique among its siblings
internal readonly Guid m_guid; // Activity Guid, it is bascially an encoding of the Path() (see CreateActivityPathGuid)
readonly long m_uniqueId; // a small number that makes this activity unique among its siblings
internal readonly Guid m_guid; // Activity Guid, it is basically an encoding of the Path() (see CreateActivityPathGuid)
internal readonly int m_activityPathGuidOffset; // Keeps track of where in m_guid the causality path stops (used to generated child GUIDs)
internal readonly int m_level; // current depth of the Path() of the activity (used to keep recursion under control)
readonly internal EventActivityOptions m_eventOptions; // Options passed to start.
internal long m_lastChildID; // used to create a unique ID for my children activities
internal int m_stopped; // This work item has stopped
readonly internal ActivityInfo m_creator; // My parent (creator). Forms the Path() for the activity.
readonly internal Guid m_activityIdToRestore; // The Guid to restore after a stop.
#endregion
}
@@ -530,26 +553,50 @@ namespace System.Diagnostics.Tracing
// with m_current.ActivityID
void ActivityChanging(AsyncLocalValueChangedArgs<ActivityInfo> args)
{
if (args.PreviousValue == args.CurrentValue)
return;
ActivityInfo cur = args.CurrentValue;
ActivityInfo prev = args.PreviousValue;
if (args.CurrentValue != null)
// Are we popping off a value? (we have a prev, and it creator is cur)
// Then check if we should use the GUID at the time of the start event
if (prev != null && prev.m_creator == cur)
{
// Allow subsequent activities inside this thread to automatically get the current activity ID.
EventSource.SetCurrentThreadActivityId(args.CurrentValue.ActivityId);
// If the saved activity ID is not the same as the creator activity
// that takes precedence (it means someone explicitly did a SetActivityID)
// Set it to that and get out
if (cur == null || prev.m_activityIdToRestore != cur.ActivityId)
{
EventSource.SetCurrentThreadActivityId(prev.m_activityIdToRestore);
return;
}
}
else
EventSource.SetCurrentThreadActivityId(Guid.Empty);
// OK we did not have an explicit SetActivityID set. Then we should be
// setting the activity to current ActivityInfo. However that activity
// might be dead, in which case we should skip it, so we never set
// the ID to dead things.
while(cur != null)
{
// We found a live activity (typically the first time), set it to that.
if (cur.m_stopped == 0)
{
EventSource.SetCurrentThreadActivityId(cur.ActivityId);
return;
}
cur = cur.m_creator;
}
// we can get here if there is no information on our activity stack (everything is dead)
// currently we do nothing, as that seems better than setting to Guid.Emtpy.
}
/// <summary>
/// Async local variables have the propery that the are automatically copied whenever a task is created and used
/// Async local variables have the properly that the are automatically copied whenever a task is created and used
/// while that task is running. Thus m_current 'flows' to any task that is caused by the current thread that
/// last set it.
///
/// This variable points a a linked list that represents all Activities that have started but have not stopped.
/// </summary>
AsyncLocal<ActivityInfo> m_current;
bool m_checkedForEnable;
// Singleton
private static ActivityTracker s_activityTrackerInstance = new ActivityTracker();
@@ -557,8 +604,74 @@ namespace System.Diagnostics.Tracing
// Used to create unique IDs at the top level. Not used for nested Ids (each activity has its own id generator)
static long m_nextId = 0;
private const ushort MAX_ACTIVITY_DEPTH = 100; // Limit maximum depth of activities to be tracked at 100.
// This will avoid leaking memory in case of activities that are never stopped.
// This will avoid leaking memory in case of activities that are never stopped.
#endregion
}
#if ES_BUILD_STANDALONE
/******************************** SUPPORT *****************************/
/// <summary>
/// This is supplied by the framework. It is has the semantics that the value is copied to any new Tasks that is created
/// by the current task. Thus all causally related code gets this value. Note that reads and writes to this VARIABLE
/// (not what it points it) to this does not need to be protected by locks because it is inherently thread local (you always
/// only get your thread local copy which means that you never have ----s.
/// </summary>
///
[EventSource(Name="Microsoft.Tasks.Nuget")]
internal class TplEtwProvider : EventSource
{
public class Keywords
{
public const EventKeywords Debug = (EventKeywords) 1;
}
public static TplEtwProvider Log = new TplEtwProvider();
public bool Debug { get { return IsEnabled(EventLevel.Verbose, Keywords.Debug); } }
public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(1, Facility, Message); }
public void DebugFacilityMessage1(string Facility, string Message, string Arg) { WriteEvent(2, Facility, Message, Arg); }
public void SetActivityId(Guid Id) { WriteEvent(3, Id); }
}
#endif
#if ES_BUILD_AGAINST_DOTNET_V35 || ES_BUILD_PCL || NO_ASYNC_LOCAL
internal sealed class AsyncLocalValueChangedArgs<T>
{
public AsyncLocalValueChangedArgs()
{
}
public T PreviousValue { get { return default(T); } }
public T CurrentValue { get { return default(T); } }
}
internal sealed class AsyncLocal<T>
{
public AsyncLocal()
{
}
public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler)
{
}
public T Value
{
get
{
object obj = null; //
return (obj == null) ? default(T) : (T)obj;
}
set
{
//
}
}
}
#endif
}

View File

@@ -91,7 +91,7 @@ namespace System.Diagnostics.Tracing
private static WriteEventErrorCode s_returnCode; // The last return code
private const int s_basicTypeAllocationBufferSize = 16;
private const int s_etwMaxNumberArguments = 32;
private const int s_etwMaxNumberArguments = 128;
private const int s_etwAPIMaxRefObjCount = 8;
private const int s_maxEventDataDescriptors = 128;
private const int s_traceEventMaximumSize = 65482;

View File

@@ -1 +1 @@
a1b51851218d5fc20ec8ab7c6933e742e0f6a94b
9ae566937256255d1b55dcc7c0b259983dc54595