Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional ThreadStatic storage to avoid allocation while sorting… #2865

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2f2c06b
Add additional ThreadStatic storage to avoid allocation while sorting…
utpilla Feb 5, 2022
f6080d9
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Feb 14, 2022
9b58172
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Feb 18, 2022
c08e350
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
cijothomas Feb 24, 2022
1a3a7c0
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Feb 24, 2022
e8f083e
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 2, 2022
e200ea1
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 3, 2022
92d4b9c
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 4, 2022
70c4884
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 7, 2022
3e8a86f
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 9, 2022
100a00c
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
cijothomas Mar 12, 2022
72d5273
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 14, 2022
93d73e6
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 22, 2022
5c7333e
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 29, 2022
3b5374a
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Mar 29, 2022
0037294
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Apr 7, 2022
d6d155f
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Apr 10, 2022
d80c02d
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Apr 13, 2022
971692a
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
utpilla Apr 15, 2022
47dc178
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
cijothomas Apr 15, 2022
646a2d6
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
cijothomas Apr 15, 2022
b82f7b6
Merge branch 'main' into utpilla/Update-Metric-AggregatorStore
cijothomas Apr 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions src/OpenTelemetry/Metrics/AggregatorStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,28 +183,32 @@ private int LookupAggregatorStore(string[] tagKeys, object[] tagValues, int leng
if (length > 1)
{
// Note: We are using storage from ThreadStatic, so need to make a deep copy for Dictionary storage.
// Create a new array for the sorted Tag keys.
var sortedTagKeys = new string[length];
tagKeys.CopyTo(sortedTagKeys, 0);
// Create or obtain new arrays to temporarily hold the sorted tag Keys and Values
var storage = ThreadStaticStorage.GetStorage();
storage.CloneKeysAndValues(tagKeys, tagValues, length, out var tempSortedTagKeys, out var tempSortedTagValues);

// Create a new array for the sorted Tag values.
var sortedTagValues = new object[length];
tagValues.CopyTo(sortedTagValues, 0);
Array.Sort(tempSortedTagKeys, tempSortedTagValues);

Array.Sort(sortedTagKeys, sortedTagValues);

var sortedTags = new Tags(sortedTagKeys, sortedTagValues);
var sortedTags = new Tags(tempSortedTagKeys, tempSortedTagValues);

if (!this.tagsToMetricPointIndexDictionary.TryGetValue(sortedTags, out aggregatorIndex))
{
// Note: We are using storage from ThreadStatic, so need to make a deep copy for Dictionary storage.
// Note: We are using storage from ThreadStatic for both the input order of tags and the sorted order of tags,
// so we need to make a deep copy for Dictionary storage.
var givenKeys = new string[length];
tagKeys.CopyTo(givenKeys, 0);

var givenValues = new object[length];
tagValues.CopyTo(givenValues, 0);

var sortedTagKeys = new string[length];
tempSortedTagKeys.CopyTo(sortedTagKeys, 0);

var sortedTagValues = new object[length];
tempSortedTagValues.CopyTo(sortedTagValues, 0);

givenTags = new Tags(givenKeys, givenValues);
sortedTags = new Tags(sortedTagKeys, sortedTagValues);

aggregatorIndex = this.metricPointIndex;
if (aggregatorIndex >= this.maxMetricPoints)
Expand Down
37 changes: 31 additions & 6 deletions src/OpenTelemetry/Metrics/ThreadStaticStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ internal class ThreadStaticStorage
[ThreadStatic]
private static ThreadStaticStorage storage;

private readonly TagStorage[] tagStorage = new TagStorage[MaxTagCacheSize];
private readonly TagStorage[] primaryTagStorage = new TagStorage[MaxTagCacheSize];
private readonly TagStorage[] secondaryTagStorage = new TagStorage[MaxTagCacheSize];

private ThreadStaticStorage()
{
for (int i = 0; i < MaxTagCacheSize; i++)
{
this.tagStorage[i] = new TagStorage(i + 1);
this.primaryTagStorage[i] = new TagStorage(i + 1);
this.secondaryTagStorage[i] = new TagStorage(i + 1);
}
}

Expand All @@ -56,8 +58,8 @@ internal void SplitToKeysAndValues(ReadOnlySpan<KeyValuePair<string, object>> ta

if (tagLength <= MaxTagCacheSize)
{
tagKeys = this.tagStorage[tagLength - 1].TagKeys;
tagValues = this.tagStorage[tagLength - 1].TagValues;
tagKeys = this.primaryTagStorage[tagLength - 1].TagKeys;
tagValues = this.primaryTagStorage[tagLength - 1].TagValues;
}
else
{
Expand Down Expand Up @@ -94,8 +96,8 @@ internal void SplitToKeysAndValues(ReadOnlySpan<KeyValuePair<string, object>> ta
}
else if (actualLength <= MaxTagCacheSize)
{
tagKeys = this.tagStorage[actualLength - 1].TagKeys;
tagValues = this.tagStorage[actualLength - 1].TagValues;
tagKeys = this.primaryTagStorage[actualLength - 1].TagKeys;
tagValues = this.primaryTagStorage[actualLength - 1].TagValues;
}
else
{
Expand Down Expand Up @@ -125,6 +127,29 @@ internal void SplitToKeysAndValues(ReadOnlySpan<KeyValuePair<string, object>> ta
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void CloneKeysAndValues(string[] inputTagKeys, object[] inputTagValues, int tagLength, out string[] clonedTagKeys, out object[] clonedTagValues)
{
Guard.ThrowIfZero(tagLength, $"There must be at least one tag to use {nameof(ThreadStaticStorage)}", $"{nameof(tagLength)}");

if (tagLength <= MaxTagCacheSize)
{
clonedTagKeys = this.secondaryTagStorage[tagLength - 1].TagKeys;
clonedTagValues = this.secondaryTagStorage[tagLength - 1].TagValues;
}
else
{
clonedTagKeys = new string[tagLength];
clonedTagValues = new object[tagLength];
}

for (int i = 0; i < tagLength; i++)
{
clonedTagKeys[i] = inputTagKeys[i];
clonedTagValues[i] = inputTagValues[i];
}
}

internal class TagStorage
{
// Used to split into Key sequence, Value sequence.
Expand Down