diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp index 25ff4cf4a4d1..f427c6346fc6 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp @@ -52,6 +52,9 @@ AllocationsProvider::AllocationsProvider( _sampledAllocationsCountMetric = metricsRegistry.GetOrRegister("dotnet_sampled_allocations"); _sampledAllocationsSizeMetric = metricsRegistry.GetOrRegister("dotnet_sampled_allocations_size"); _totalAllocationsSizeMetric = metricsRegistry.GetOrRegister("dotnet_total_allocations_size"); + + // disable sub sampling when recording allocations + _shouldSubSample = !_pConfiguration->IsAllocationRecorderEnabled(); } @@ -66,7 +69,8 @@ void AllocationsProvider::OnAllocation(uint32_t allocationKind, _allocationsSizeMetric->Add((double_t)objectSize); _totalAllocationsSizeMetric->Add((double_t)allocationAmount); - if ((_sampleLimit > 0) && (!_sampler.Sample())) + // remove sampling when recording allocations + if (_shouldSubSample && (_sampleLimit > 0) && (!_sampler.Sample())) { return; } diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.h index 70fc5c4aadb5..02dc84cad2a5 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.h @@ -57,6 +57,7 @@ class AllocationsProvider GenericSampler _sampler; int32_t _sampleLimit; IConfiguration const* const _pConfiguration; + bool _shouldSubSample; std::shared_ptr _allocationsCountMetric; std::shared_ptr _allocationsSizeMetric; std::shared_ptr _sampledAllocationsCountMetric; diff --git a/profiler/src/Tools/AllocSimulator/AllocSimulator.csproj b/profiler/src/Tools/AllocSimulator/AllocSimulator.csproj index f02677bf640f..d70cef1ef9f9 100644 --- a/profiler/src/Tools/AllocSimulator/AllocSimulator.csproj +++ b/profiler/src/Tools/AllocSimulator/AllocSimulator.csproj @@ -7,4 +7,8 @@ enable + + + + diff --git a/profiler/src/Tools/AllocSimulator/BinaryFileAllocProvider.cs b/profiler/src/Tools/AllocSimulator/BinaryFileAllocProvider.cs index 3ec39c443805..976b607f5817 100644 --- a/profiler/src/Tools/AllocSimulator/BinaryFileAllocProvider.cs +++ b/profiler/src/Tools/AllocSimulator/BinaryFileAllocProvider.cs @@ -77,7 +77,7 @@ private bool ParseAllocations(string filename) private void ReadStringTable(FileStream fileStream, ref int pos) { int currentString = 0; - byte[] stringBuffer = new byte[1024]; // expect type names less than 1024 characters long + byte[] stringBuffer = new byte[2048]; // expect type names less than 2048 characters long int currentChar = 0; // = length of the string after \0 is read byte[] buffer = new byte[1]; diff --git a/profiler/src/Tools/AllocSimulator/IUpscaler.cs b/profiler/src/Tools/AllocSimulator/IUpscaler.cs index 037827b0b631..7fe6b0c5d9df 100644 --- a/profiler/src/Tools/AllocSimulator/IUpscaler.cs +++ b/profiler/src/Tools/AllocSimulator/IUpscaler.cs @@ -9,6 +9,11 @@ public interface IUpscaler { public void OnAllocationTick(string type, int key, long size, long allocationsAmount); - public IEnumerable GetAllocs(); + public IEnumerable GetUpscaledAllocs(); + + public IEnumerable GetSampledAllocs(); + + public void Upscale(AllocInfo sampled, ref AllocInfo upscaled); + } } diff --git a/profiler/src/Tools/AllocSimulator/PProfFile.cs b/profiler/src/Tools/AllocSimulator/PProfFile.cs new file mode 100644 index 000000000000..e2c18f66a78f --- /dev/null +++ b/profiler/src/Tools/AllocSimulator/PProfFile.cs @@ -0,0 +1,360 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2022 Datadog, Inc. +// + +using Perftools.Profiles; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable SA1025 // Code should not contain multiple whitespace in a row +#pragma warning disable SA1507 // Code should not contain multiple blank lines in a row +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable SA1201 // Elements should appear in the correct order +#pragma warning disable SA1009 // Closing parenthesis should be spaced correctly +#pragma warning disable SA1108 // Block statements should not contain embedded comments +#pragma warning disable SA1111 // Closing parenthesis should be on line of last parameter + + +public class PProfFile +{ + public PProfFile() + { + } + + public IEnumerable Samples { get; private set; } + public IReadOnlyList ValueTypes { get; private set; } + public IEnumerable Mappings { get; private set; } + public IEnumerable Locations { get; private set; } + public IEnumerable Functions { get; private set; } + public IEnumerable StringTable { get; private set; } + + + // Can be called only once + public bool Load(Profile profile) + { + if (_profile != null) + { + return false; + } + + try + { + _profile = profile; + LoadStringTable(); + LoadValueTypes(); + LoadMappings(); + LoadFunctions(); + LoadLocations(); + LoadSamples(); + } + catch (Exception x) + { + throw new InvalidOperationException(x.Message, x); + } + + return true; + } + + public string GetString(long id) + { + if (_stringTable.Count < id) + { + return $"?{id}"; + } + + return _stringTable[(int)id]; + } + + public string GetString(ulong id) + { + return GetString((long)id); + } + + public string GetValueName(int pos) + { + if (_valueTypes.Count <= pos) + { + return $"v#{pos}"; + } + + return _valueTypes[pos].Name; + } + + public Mapping GetMapping(ulong id) + { // looks like a "no mapping" id + if ((_mappings.Count < (int)id) || (id == 0)) + { + return null; + } + + return _mappings[(int)id - 1]; + } + + public Function GetFunction(int id) + { + if (_functions.Count < id) + { + return null; + } + + return _functions[id - 1]; + } + + public string GetFunctionName(int id) + { + var function = GetFunction(id); + return function?.Name; + } + + public Location GetLocation(ulong location) + { + if (_locations.Count < (int)location) + { + return null; + } + + return _locations[(int)location - 1]; + } + + private void LoadStringTable() + { + var stringsCount = _profile.StringTable.Count; + _stringTable = new List(stringsCount); + + var current = 0; + foreach (var entry in _profile.StringTable) + { + _stringTable.Add(entry); + current++; + } + + StringTable = _stringTable; + } + + private void LoadValueTypes() + { + _valueTypes = new List(_profile.SampleType.Count); + foreach (var entry in _profile.SampleType) + { + _valueTypes.Add(new ValueType(GetString(entry.Type), GetString(entry.Unit))); + } + + ValueTypes = _valueTypes; + } + + private void LoadFunctions() + { + _functions = new List(_profile.Function.Count); + foreach (var function in _profile.Function) + { + _functions.Add(new Function(function.Id, GetString(function.Name))); + } + + Functions = _functions; + } + + private void LoadMappings() + { + _mappings = new List(_profile.Mapping.Count); + foreach (var mapping in _profile.Mapping) + { + _mappings.Add(new Mapping(mapping.Id, GetString(mapping.Filename), mapping.BuildId)); + } + + Mappings = _mappings; + } + + private void LoadLocations() + { + _locations = new List(_profile.Location.Count); + foreach (var entry in _profile.Location) + { + var framesCount = entry.Line.Count; + var frames = new List(framesCount); + for (int i = 0; i < framesCount; i++) + { + frames.Add( + new Frame( + entry.Line[i].FunctionId, + GetFunctionName((int)entry.Line[i].FunctionId), + i != (framesCount - 1) // the last frame is not inlined + ) + ); + } + + var filename = "?"; + var mapping = GetMapping(entry.MappingId); + if (mapping != null) + { + filename = mapping.Filename; + } + + _locations.Add( + new Location( + entry.Id, entry.MappingId, entry.Address, filename, frames + ) + ); + } + + Locations = _locations; + } + + private void LoadSamples() + { + var samplesCount = _profile.Sample.Count; + _samples = new List(samplesCount); + + foreach (var sample in _profile.Sample) + { + var values = new List(sample.Value); + var labels = new List