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
30 changes: 30 additions & 0 deletions scenarios/ddprof_go/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Dockerfile

FROM golang:1.20.5

WORKDIR /app

COPY ./scenarios/ddprof_go/ .

RUN go build main.go


RUN apt-get update && apt-get install -y \
curl \
xz-utils \
jq \
wget \
&& rm -rf /var/lib/apt/lists/*

# Install native profiling
ARG CACHE_DATE=2023-03-01_09:58:27
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noob question: What does this date signify? Does it mean we're using a version from March?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a trick to force the second part of the docker to re-fetch new versions of the profiler.

COPY ./binaries/ /app/binaries/
ADD ./profilers/ddprof/install_profiler.sh .
RUN ./install_profiler.sh /usr/local/bin

ENV EXECUTION_TIME="11"
# Default is that test data is dropped in the data folder
ENV DD_PROFILING_PPROF_PREFIX="/app/data/profiles_"
ENV DD_PROFILING_UPLOAD_PERIOD="10"
# One allocation of size 1000 every millisecond
CMD ["ddprof", "-l", "notice", "/app/main" ]
8 changes: 8 additions & 0 deletions scenarios/ddprof_go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Description

The test aims at checking that we are able to load and capture C allocations.

# Shortcomings

- We are not unwinding through the ASM CGo frame.
- The quantity of allocations is hard to predict considering the Go allocator reserves mmap regions.
72 changes: 72 additions & 0 deletions scenarios/ddprof_go/expected_profile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"test_name": "ddprof_go",
"stacks": [
{
"profile-type": "cpu-time",
"stack-content": [
{
"regular_expression": ";runtime\\.goexit\\.abi0;runtime\\.main;main\\.main",
"percent": 99,
"error_margin": 5,
"labels": [
{
"key": "process_id",
"values": [
"1"
]
}
]
}
]
},
{
"profile-type": "cpu-samples",
"stack-content": [
{
"regular_expression": ";runtime\\.goexit\\.abi0;runtime\\.main;main\\.main",
"percent": 99,
"error_margin": 3,
"labels": [
{
"key": "process_id",
"values": [
"1"
]
}
]
}
]
},
{
"profile-type": "alloc-samples",
"stack-content": [
{
"regular_expression": ".*runtime\\.asmcgocall\\.abi0;cAllocateMemory",
"percent": 20,
"error_margin": 40,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really care about the numbers (I can't predict the mmap strategy from Go), I just want them to be there.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you call this out more clearly in the README

"labels": [
{
"key": "process_id",
"values": [
"1"
]
}
]
},
{
"regular_expression": ".*;x_cgo_mmap",
"percent": 80,
"error_margin": 40,
"labels": [
{
"key": "process_id",
"values": [
"1"
]
}
]
}
]
}
]
}
76 changes: 76 additions & 0 deletions scenarios/ddprof_go/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import (
"fmt"
"os"
"runtime"
"strconv"
"time"
)

/*
#include <stdio.h>
#include <stdlib.h>

void cAllocateMemory() {
// Allocate some memory in the C function
int size_alloc = 10000;
int* data = (int*)malloc(size_alloc * sizeof(int));
int sum = 0;
// Use the allocated memory to avoid compiler optimizations
for (int i = 0; i < size_alloc; i++) {
data[i] = i;
}
for (int i = 0; i < size_alloc; i++) {
sum += data[i];
}
printf("%d\n", sum);
Comment on lines +24 to +27
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ indentation

// Free the allocated memory
free(data);
}
*/
import "C"

func burnCPU() {
// Simulate CPU-intensive work
for i := 0; i < 1000000000; i++ {
_ = i * i
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we guarantee this won't be optimized?

}
}

func allocateMemory() {
// Allocate some memory in Go
data := make([]int, 100)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we're doing 10K in C, and 100 in Go? For future, might be interesting to make this configurable to see how we do at profiling as the relative ratios change

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#9

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, only that I was sure not to catch these for now, so I did not care about having smaller allocations. The native profiler can not instrument the Go allocator (only the mmaps).
We can unify if you feel it is more logical.


// Use the allocated memory to avoid compiler optimizations
for i := 0; i < 100; i++ {
data[i] = i
}
}

func main() {
// Get the execution time from the environment variable
executionTimeStr := os.Getenv("EXECUTION_TIME")
executionTime, err := strconv.Atoi(executionTimeStr)
if err != nil {
fmt.Println("Error parsing EXECUTION_TIME:", err)
return
}

// Calculate the end time based on the execution time
endTime := time.Now().Add(time.Duration(executionTime) * time.Second)

// Run the loop until the specified duration is reached
for time.Now().Before(endTime) {
burnCPU()
allocateMemory()
C.cAllocateMemory()
time.Sleep(100 * time.Millisecond) // Sleep to simulate some delay
}

// Print some memory stats at the end
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Allocated memory (bytes): %v\n", m.Alloc)
fmt.Printf("Total memory allocated (bytes): %v\n", m.TotalAlloc)
}