Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
110 changes: 110 additions & 0 deletions ddtrace/internal/datadog/profiling/echion/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
60 changes: 60 additions & 0 deletions ddtrace/internal/datadog/profiling/echion/echion/cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// This file is part of "echion" which is released under MIT.
//
// Copyright (c) 2023 Gabriele N. Tornetta <[email protected]>.

#pragma once

#include <functional>
#include <list>
#include <memory>
#include <unordered_map>

#include <echion/errors.h>

#define CACHE_MAX_ENTRIES 2048

template <typename K, typename V>
class LRUCache
{
public:
LRUCache(size_t capacity) : capacity(capacity) {}

Result<std::reference_wrapper<V>> lookup(const K& k);

void store(const K& k, std::unique_ptr<V> v);

private:
size_t capacity;
std::list<std::pair<K, std::unique_ptr<V>>> items;
std::unordered_map<K, typename std::list<std::pair<K, std::unique_ptr<V>>>::iterator> index;
};

template <typename K, typename V>
void LRUCache<K, V>::store(const K& k, std::unique_ptr<V> v)
{
// Check if cache is full
if (items.size() >= capacity)
{
index.erase(items.back().first);
items.pop_back();
}

// Insert the new item at front of the list
items.emplace_front(k, std::move(v));

// Insert in the map
index[k] = items.begin();
}

template <typename K, typename V>
Result<std::reference_wrapper<V>> LRUCache<K, V>::lookup(const K& k)
{
auto itr = index.find(k);
if (itr == index.end())
return ErrorKind::LookupError;

// Move to the front of the list
items.splice(items.begin(), items, itr->second);

return std::reference_wrapper<V>(*(itr->second->second.get()));
}
137 changes: 137 additions & 0 deletions ddtrace/internal/datadog/profiling/echion/echion/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// This file is part of "echion" which is released under MIT.
//
// Copyright (c) 2023 Gabriele N. Tornetta <[email protected]>.

#pragma once

#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include <string>

// Sampling interval
inline unsigned int interval = 1000;

// CPU Time mode
inline int cpu = 0;

// For cpu time mode, Echion only unwinds threads that're running by default.
// Set this to false to unwind all threads.
inline bool ignore_non_running_threads = true;

// Memory events
inline int memory = 0;

// Native stack sampling
inline int native = 0;

// Where mode
inline int where = 0;

// Maximum number of frames to unwind
inline unsigned int max_frames = 2048;

// Pipe name (where mode IPC)
inline std::string pipe_name;

// ----------------------------------------------------------------------------
static PyObject* set_interval(PyObject* Py_UNUSED(m), PyObject* args)
{
unsigned int new_interval;
if (!PyArg_ParseTuple(args, "I", &new_interval))
return NULL;

interval = new_interval;

Py_RETURN_NONE;
}

// ----------------------------------------------------------------------------
inline void _set_cpu(int new_cpu)
{
cpu = new_cpu;
}

// ----------------------------------------------------------------------------
inline void _set_ignore_non_running_threads(bool new_ignore_non_running_threads)
{
ignore_non_running_threads = new_ignore_non_running_threads;
}

// ----------------------------------------------------------------------------
static PyObject* set_cpu(PyObject* Py_UNUSED(m), PyObject* args)
{
int new_cpu;
if (!PyArg_ParseTuple(args, "p", &new_cpu))
return NULL;

_set_cpu(new_cpu);

Py_RETURN_NONE;
}

// ----------------------------------------------------------------------------
static PyObject* set_memory(PyObject* Py_UNUSED(m), PyObject* args)
{
int new_memory;
if (!PyArg_ParseTuple(args, "p", &new_memory))
return NULL;

memory = new_memory;

Py_RETURN_NONE;
}

// ----------------------------------------------------------------------------
static PyObject* set_native(PyObject* Py_UNUSED(m), PyObject* Py_UNUSED(args))
{
#ifndef UNWIND_NATIVE_DISABLE
int new_native;
if (!PyArg_ParseTuple(args, "p", &new_native))
return NULL;

native = new_native;
#else
PyErr_SetString(PyExc_RuntimeError,
"Native profiling is disabled, please re-build/install echion without "
"UNWIND_NATIVE_DISABLE env var/preprocessor flag");
return NULL;
#endif // UNWIND_NATIVE_DISABLE
Py_RETURN_NONE;
}

// ----------------------------------------------------------------------------
static PyObject* set_where(PyObject* Py_UNUSED(m), PyObject* args)
{
int value;
if (!PyArg_ParseTuple(args, "p", &value))
return NULL;

where = value;

Py_RETURN_NONE;
}

// ----------------------------------------------------------------------------
static PyObject* set_pipe_name(PyObject* Py_UNUSED(m), PyObject* args)
{
const char* name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;

pipe_name = name;

Py_RETURN_NONE;
}

// ----------------------------------------------------------------------------
static PyObject* set_max_frames(PyObject* Py_UNUSED(m), PyObject* args)
{
unsigned int new_max_frames;
if (!PyArg_ParseTuple(args, "I", &new_max_frames))
return NULL;

max_frames = new_max_frames;

Py_RETURN_NONE;
}
Loading
Loading