-
Notifications
You must be signed in to change notification settings - Fork 416
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(profiling): code provenance using libdatadog exporter [backport 2…
….14] (#10856) Backport 4363516 from #10796 to 2.14. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) Co-authored-by: Taegyun Kim <[email protected]>
- Loading branch information
1 parent
a213e8d
commit 73d3d41
Showing
16 changed files
with
569 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
ddtrace/internal/datadog/profiling/dd_wrapper/include/code_provenance.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#pragma once | ||
|
||
#include <atomic> | ||
#include <memory> | ||
#include <mutex> | ||
#include <optional> | ||
#include <set> | ||
#include <string> | ||
#include <string_view> | ||
#include <unordered_map> | ||
#include <vector> | ||
|
||
namespace Datadog { | ||
|
||
struct Package | ||
{ | ||
std::string name; | ||
std::string version; | ||
}; | ||
|
||
static constexpr const char* STDLIB = "stdlib"; | ||
|
||
class CodeProvenance | ||
{ | ||
public: | ||
// Public static method to access the CodeProvenance instance | ||
static CodeProvenance& get_instance() | ||
{ | ||
static CodeProvenance instance; | ||
return instance; | ||
} | ||
|
||
// Delete copy constructor and assignment operator to prevent copies | ||
CodeProvenance(CodeProvenance const&) = delete; | ||
CodeProvenance& operator=(CodeProvenance const&) = delete; | ||
|
||
static void postfork_child(); | ||
|
||
void set_enabled(bool enable); | ||
bool is_enabled(); | ||
void set_runtime_version(std::string_view runtime_version); | ||
void set_stdlib_path(std::string_view stdlib_path); | ||
void add_packages(std::unordered_map<std::string_view, std::string_view> packages); | ||
void add_filename(std::string_view filename); | ||
std::optional<std::string> try_serialize_to_json_str(); | ||
|
||
private: | ||
// Mutex to protect the state | ||
std::mutex mtx; | ||
// Whether this is enabled, set only when DD_PROFILING_ENABLE_CODE_PROVENANCE is set | ||
std::atomic_bool enabled{ false }; | ||
std::string runtime_version; | ||
std::string stdlib_path; | ||
// Mapping from package name to Package object | ||
std::unordered_map<std::string_view, std::unique_ptr<Package>> packages; | ||
// Mapping from Package object to list of filenames that are associated with the package | ||
std::unordered_map<const Package*, std::set<std::string>> packages_to_files; | ||
|
||
// Private Constructor/Destructor to prevent instantiation/deletion from outside | ||
CodeProvenance() = default; | ||
~CodeProvenance() = default; | ||
|
||
void reset(); | ||
std::string_view get_package_name(std::string_view filename); | ||
const Package* add_new_package(std::string_view package_name, std::string_view version); | ||
}; | ||
} |
18 changes: 18 additions & 0 deletions
18
ddtrace/internal/datadog/profiling/dd_wrapper/include/code_provenance_interface.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#pragma once | ||
|
||
#include <string_view> | ||
#include <unordered_map> | ||
|
||
#ifdef __cplusplus | ||
extern "C" | ||
{ | ||
#endif | ||
|
||
void code_provenance_enable(bool enable); | ||
void code_provenance_set_runtime_version(std::string_view runtime_version); | ||
void code_provenance_set_stdlib_path(std::string_view stdlib_path); | ||
void code_provenance_add_packages(std::unordered_map<std::string_view, std::string_view> packages); | ||
|
||
#ifdef __cplusplus | ||
} // extern "C" | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 177 additions & 0 deletions
177
ddtrace/internal/datadog/profiling/dd_wrapper/src/code_provenance.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
#include "code_provenance.hpp" | ||
|
||
#include <memory> | ||
#include <mutex> | ||
#include <set> | ||
#include <sstream> | ||
#include <string> | ||
#include <string_view> | ||
#include <unordered_map> | ||
#include <vector> | ||
|
||
namespace Datadog { | ||
|
||
void | ||
Datadog::CodeProvenance::postfork_child() | ||
{ | ||
get_instance().mtx.~mutex(); // Destroy the mutex | ||
new (&get_instance().mtx) std::mutex(); // Recreate the mutex | ||
get_instance().reset(); // Reset the state | ||
} | ||
|
||
void | ||
Datadog::CodeProvenance::set_enabled(bool enable) | ||
{ | ||
this->enabled.store(enable); | ||
} | ||
|
||
bool | ||
Datadog::CodeProvenance::is_enabled() | ||
{ | ||
return enabled.load(); | ||
} | ||
|
||
void | ||
Datadog::CodeProvenance::set_runtime_version(std::string_view _runtime_version) | ||
{ | ||
std::lock_guard<std::mutex> lock(mtx); | ||
this->runtime_version = _runtime_version; | ||
} | ||
|
||
void | ||
Datadog::CodeProvenance::set_stdlib_path(std::string_view _stdlib_path) | ||
{ | ||
std::lock_guard<std::mutex> lock(mtx); | ||
this->stdlib_path = _stdlib_path; | ||
} | ||
|
||
void | ||
CodeProvenance::add_packages(std::unordered_map<std::string_view, std::string_view> distributions) | ||
{ | ||
|
||
if (!is_enabled()) { | ||
return; | ||
} | ||
|
||
std::lock_guard<std::mutex> lock(mtx); | ||
|
||
for (const auto& [package_name, version] : distributions) { | ||
auto it = packages.find(package_name); | ||
if (it == packages.end()) { | ||
add_new_package(package_name, version); | ||
} | ||
} | ||
} | ||
|
||
void | ||
CodeProvenance::add_filename(std::string_view filename) | ||
{ | ||
if (!is_enabled()) { | ||
return; | ||
} | ||
|
||
std::string_view package_name = get_package_name(filename); | ||
if (package_name.empty() or package_name == STDLIB) { | ||
return; | ||
} | ||
|
||
std::lock_guard<std::mutex> lock(mtx); | ||
|
||
auto it = packages.find(package_name); | ||
if (it == packages.end()) { | ||
return; | ||
} | ||
|
||
const Package* package = it->second.get(); | ||
if (package) { | ||
if (packages_to_files.find(package) == packages_to_files.end()) { | ||
packages_to_files[package] = std::set<std::string>(); | ||
} | ||
packages_to_files[package].insert(std::string(filename)); | ||
} | ||
} | ||
|
||
std::optional<std::string> | ||
CodeProvenance::try_serialize_to_json_str() | ||
{ | ||
if (!is_enabled()) { | ||
return std::nullopt; | ||
} | ||
|
||
std::lock_guard<std::mutex> lock(mtx); | ||
|
||
std::ostringstream out; | ||
// DEV: Simple JSON serialization, maybe consider using a JSON library. | ||
out << "{\"v1\":["; // Start of the JSON array | ||
for (const auto& [package, paths] : packages_to_files) { | ||
out << "{"; // Start of the JSON object | ||
out << "\"name\": \"" << package->name << "\","; | ||
out << "\"kind\": \"library\","; | ||
out << "\"version\": \"" << package->version << "\","; | ||
out << "\"paths\":["; // Start of paths array | ||
for (auto it = paths.begin(); it != paths.end(); ++it) { | ||
out << "\"" << *it << "\""; | ||
if (std::next(it) != paths.end()) { | ||
out << ","; | ||
} | ||
} | ||
out << "]"; // End of paths array | ||
out << "},"; // End of the JSON object | ||
} | ||
// Add python runtime information | ||
out << "{"; // Start of stdlib JSON object | ||
out << "\"name\": \"stdlib\","; | ||
out << "\"kind\": \"standard library\","; | ||
out << "\"version\": \"" << runtime_version << "\","; | ||
out << "\"paths\":["; | ||
out << "\"" << stdlib_path << "\""; | ||
out << "]"; | ||
out << "}"; // End of stdlib JSON object | ||
out << "]}"; // End of the JSON array | ||
|
||
// Clear the state | ||
packages_to_files.clear(); | ||
return out.str(); | ||
} | ||
|
||
void | ||
CodeProvenance::reset() | ||
{ | ||
std::lock_guard<std::mutex> lock(mtx); | ||
packages_to_files.clear(); | ||
} | ||
|
||
std::string_view | ||
CodeProvenance::get_package_name(std::string_view filename) | ||
{ | ||
// std::regex is slow, so we use a simple string search | ||
static const std::string site_packages = "site-packages/"; | ||
|
||
size_t start = filename.find(site_packages); | ||
if (start == std::string::npos) { | ||
return std::string_view(STDLIB); | ||
} | ||
|
||
start += site_packages.length(); | ||
size_t end = filename.find('/', start); | ||
if (end == std::string::npos) { | ||
return {}; | ||
} | ||
|
||
return filename.substr(start, end - start); | ||
} | ||
|
||
const Package* | ||
CodeProvenance::add_new_package(std::string_view package_name, std::string_view version) | ||
{ | ||
std::unique_ptr<Package> package = std::make_unique<Package>(); | ||
package->name = package_name; | ||
package->version = version; | ||
|
||
const Package* ret_val = package.get(); | ||
packages[std::string_view(package->name)] = std::move(package); | ||
|
||
return ret_val; | ||
} | ||
|
||
} |
30 changes: 30 additions & 0 deletions
30
ddtrace/internal/datadog/profiling/dd_wrapper/src/code_provenance_interface.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#include "code_provenance_interface.hpp" | ||
|
||
#include "code_provenance.hpp" | ||
|
||
#include <string_view> | ||
#include <unordered_map> | ||
|
||
void | ||
code_provenance_enable(bool enable) | ||
{ | ||
Datadog::CodeProvenance::get_instance().set_enabled(enable); | ||
} | ||
|
||
void | ||
code_provenance_set_runtime_version(std::string_view runtime_version) | ||
{ | ||
Datadog::CodeProvenance::get_instance().set_runtime_version(runtime_version); | ||
} | ||
|
||
void | ||
code_provenance_set_stdlib_path(std::string_view stdlib_path) | ||
{ | ||
Datadog::CodeProvenance::get_instance().set_stdlib_path(stdlib_path); | ||
} | ||
|
||
void | ||
code_provenance_add_packages(std::unordered_map<std::string_view, std::string_view> distributions) | ||
{ | ||
Datadog::CodeProvenance::get_instance().add_packages(distributions); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.