-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Support pprof profiling feature #13502
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
Changes from 70 commits
41acb04
6b4640f
a54d8dc
d069e68
1afb571
2578bd1
4c03a81
5520d01
c965482
c467076
5000e71
cce039d
3989494
232cdc4
1dc8fcd
e8f44ad
f46887f
f49e7a3
3449d89
26956b0
baaf886
62fd3fb
88692d1
843585f
07fe14c
2e62876
02a5b55
ed0403a
fc0ae02
b3d09ca
c6d7a79
e8253f0
a438569
4df8bd2
78d2e8a
b5f3e89
57fc59f
1b7d636
39911d4
78a2c9c
a4882ff
ba4f02f
9c1379a
6a2dd3a
050a339
602917d
32f384d
e76bdd5
296ed0f
1906182
233027b
7bc7d60
9e9eb9d
6a4ed7f
93b407b
55d67eb
8790b79
7f6267b
2431af5
0e397af
901eeaa
ad6e7ae
3e4c261
d3763bc
e60e3d5
36a83c9
5b6ffae
6bb29d4
f979edd
8adfd28
f613cbd
02d2964
4f76698
49d84a0
79a74bb
ce5384b
5226098
4c47d09
a895cba
c2825e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| package org.apache.skywalking.oap.server.network.trace.component.command; | ||
|
|
||
| import org.apache.skywalking.apm.network.common.v3.Command; | ||
| import org.apache.skywalking.apm.network.common.v3.KeyStringValuePair; | ||
| import java.util.List; | ||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| public class PprofTaskCommand extends BaseCommand implements Serializable, Deserializable<PprofTaskCommand> { | ||
| public static final Deserializable<PprofTaskCommand> DESERIALIZER = new PprofTaskCommand("", "", "", 0, 0, 0); | ||
| public static final String NAME = "PprofTaskQuery"; | ||
| /** | ||
| * pprof taskId | ||
| */ | ||
| private String taskId; | ||
| // Type of profiling (CPU/Heap/Block/Mutex/Goroutine/Threadcreate/Allocs) | ||
| private String events; | ||
| /** | ||
| * run profiling for duration (minute) | ||
| */ | ||
| private long duration; | ||
| /** | ||
| * task create time | ||
| */ | ||
| private long createTime; | ||
| /** | ||
| * pprof dump period parameters. There are different dumpperiod configurations for different events. | ||
| * Here is a table of parameters. | ||
| * | ||
| * <p>For Block - sample an average of one blocking event per rate nanoseconds spent blocked. (default: 0)</p> | ||
| * <p>For Mutex - sample an average of 1/rate events are reported. (default: 0)</p> | ||
| * details @see <a href="https://pkg.go.dev/runtime/pprof">pprof argument</a> | ||
| */ | ||
| private int dumpPeriod; | ||
|
|
||
| public PprofTaskCommand(String serialNumber, String taskId, String events, | ||
| long duration, long createTime, int dumpPeriod) { | ||
| super(NAME, serialNumber); | ||
| this.taskId = taskId; | ||
| this.duration = duration; | ||
| this.createTime = createTime; | ||
| this.dumpPeriod = dumpPeriod; | ||
| this.events = events; | ||
| } | ||
|
|
||
| @Override | ||
| public PprofTaskCommand deserialize(Command command) { | ||
| final List<KeyStringValuePair> argsList = command.getArgsList(); | ||
| String taskId = null; | ||
| String events = null; | ||
| long duration = 0; | ||
| long createTime = 0; | ||
| int dumpPeriod = 0; | ||
| String serialNumber = null; | ||
| for (final KeyStringValuePair pair : argsList) { | ||
| if ("SerialNumber".equals(pair.getKey())) { | ||
| serialNumber = pair.getValue(); | ||
| } else if ("TaskId".equals(pair.getKey())) { | ||
| taskId = pair.getValue(); | ||
| } else if ("Events".equals(pair.getKey())) { | ||
| events = pair.getValue(); | ||
| } else if ("Duration".equals(pair.getKey())) { | ||
| duration = Long.parseLong(pair.getValue()); | ||
| } else if ("CreateTime".equals(pair.getKey())) { | ||
| createTime = Long.parseLong(pair.getValue()); | ||
| } else if ("DumpPeriod".equals(pair.getKey())) { | ||
| dumpPeriod = Integer.parseInt(pair.getValue()); | ||
| } | ||
| } | ||
| return new PprofTaskCommand(serialNumber, taskId, events, duration, createTime, dumpPeriod); | ||
| } | ||
|
|
||
| @Override | ||
| public Command.Builder serialize() { | ||
| final Command.Builder builder = commandBuilder(); | ||
| builder.addArgs(KeyStringValuePair.newBuilder().setKey("TaskId").setValue(taskId)) | ||
| .addArgs(KeyStringValuePair.newBuilder().setKey("Events").setValue(events)) | ||
| .addArgs(KeyStringValuePair.newBuilder().setKey("Duration").setValue(String.valueOf(duration))) | ||
| .addArgs(KeyStringValuePair.newBuilder().setKey("CreateTime").setValue(String.valueOf(createTime))) | ||
| .addArgs(KeyStringValuePair.newBuilder().setKey("DumpPeriod").setValue(String.valueOf(dumpPeriod))); | ||
| return builder; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -53,6 +53,7 @@ | |||||
| * Self Observability: add `metrics_aggregation_queue_used_percentage` and `metrics_persistent_collection_cached_size` metrics for the OAP server. | ||||||
| * Optimize metrics aggregate/persistent worker: separate `OAL` and `MAL` workers and consume pools. The dataflow signal drives the new MAL consumer, | ||||||
| the following table shows the pool size,driven mode and queue size for each worker. | ||||||
| * Support pprof profiling feature. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| | Worker | poolSize | isSignalDrivenMode | queueChannelSize | queueBufferSize | | ||||||
| |-------------------------------|------------------------------------------|--------------------|------------------|-----------------| | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -47,6 +47,20 @@ Async Profiler can trace the following kinds of events: | |||||
|
|
||||||
| Only Java agent support this. | ||||||
|
|
||||||
| ### Go App Profiling | ||||||
|
|
||||||
| Go App Profiling uses the [Pprof](https://github.com/google/pprof) for sampling. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| pprof is a profiling tool by Google for visualizing and analyzing sampled performance data. | ||||||
| It reads samples in profile.proto format and generates text or graphical reports (via the dot visualization) to highlight performance hotspots. | ||||||
|
|
||||||
| pprof supports profiling of: | ||||||
|
|
||||||
| - CPU. | ||||||
| - Memory allocs / heap. | ||||||
| - Block / mutex. | ||||||
| - Gouroutine / threadcreate. | ||||||
|
|
||||||
| ## Out-of-process profiling | ||||||
|
|
||||||
| Out-of-process profiling leverage [eBPF](https://ebpf.io/) technology with origins in the Linux kernel. | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,107 @@ | ||||||
| # Go App Profiling | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file should be linked from doc menu. |
||||||
|
|
||||||
| Go App Profiling uses the Pprof for sampling | ||||||
|
|
||||||
| Pprof is bound within the auto-instrument agent and corresponds to [In-Process Profiling](../../concepts-and-designs/profiling.md#in-process-profiling). | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
pprof is a project name. They don't use capital first letter, ref to https://github.com/google/pprof |
||||||
|
|
||||||
| It is delivered to the agent in the form of a task, allowing it to be enabled or disabled dynamically. | ||||||
| When service encounters performance issues (cpu usage, memory allocation, etc.), Pprof task can be created. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Please fix nits in your words. |
||||||
| When the agent receives a task, it enables Pprof for sampling. | ||||||
| After sampling is completed, the sampling results are analyzed by requesting the server to render a flame graph for performance | ||||||
| analysis to determine the specific business code lines that cause performance problems. | ||||||
| Note, tracing profiling in the Go agent relies on the Go runtime’s global CPU sampling used by pprof. | ||||||
| Since only one CPU profiler can run at a time within the same instance, tracing and pprof CPU profiling cannot be enabled simultaneously. | ||||||
| If both are activated on the same instance, one task may fail to start. | ||||||
|
wu-sheng marked this conversation as resolved.
|
||||||
|
|
||||||
| ## Activate Pprof in the OAP | ||||||
| OAP and the agent use a brand-new protocol to exchange Pprof data, so it is necessary to start OAP with the following configuration: | ||||||
|
|
||||||
| ```yaml | ||||||
| receiver-pprof: | ||||||
| selector: ${SW_RECEIVER_PPROF:default} | ||||||
| default: | ||||||
| # Used to manage the maximum size of the pprof file that can be received, the unit is Byte, default is 30M | ||||||
| pprofMaxSize: ${SW_RECEIVER_PPROF_MAX_SIZE:31457280} | ||||||
| # Used to determine whether to receive pprof in memory file or physical file mode | ||||||
| # | ||||||
| # The memory file mode have fewer local file system limitations, so they are by default. But it costs more memory. | ||||||
| # | ||||||
| # The physical file mode will use less memory when parsing and is more friendly to parsing large files. | ||||||
| # However, if the storage of the tmp directory in the container is insufficient, the oap server instance may crash. | ||||||
| # It is recommended to use physical file mode when volume mounting is used or the tmp directory has sufficient storage. | ||||||
| memoryParserEnabled: ${SW_RECEIVER_PPROF_MEMORY_PARSER_ENABLED:true} | ||||||
| ``` | ||||||
|
|
||||||
| ## Pprof Task with Analysis | ||||||
|
|
||||||
| To use the Pprof feature, please follow these steps: | ||||||
|
|
||||||
| 1. **Create Pprof task**: Use the UI or CLI tool to create a task. | ||||||
| 2. **Wait agent collect data and upload**: Wait for Pprof to collect pprof data and report. | ||||||
| 3. **Query task progress**: Query the progress of tasks, including analyzing successful and failed instances and task logs. | ||||||
| 4. **Analyze the data**: Analyze the pprof data to determine where performance bottlenecks exist in the service. | ||||||
|
|
||||||
| ### Create an Pprof task | ||||||
|
|
||||||
| Create an Pprof task to notify some go-agent instances in the execution service to start Pprof for data collection. | ||||||
|
|
||||||
| When creating a task, the following configuration fields are required: | ||||||
|
|
||||||
| 1. **serviceId**: Define the service to execute the task. | ||||||
| 2. **serviceInstanceIds**: Define which instances need to execute tasks. | ||||||
| 3. **duration**: Define the duration of this task in minutes, required for CPU, BLOCK, MUTEX events. | ||||||
| 4. **events**: Define which event types this task needs to collect. | ||||||
| 5. **dumpPeriod**: Define the period of the pprof dump, required for BLOCK, MUTEX events. | ||||||
|
|
||||||
| When the Agent receives a Pprof task from OAP, it automatically generates a log to notify that the task has been acknowledged. The log contains the following field information: | ||||||
|
|
||||||
| 1. **Instance**: The name of the instance where the Agent is located. | ||||||
| 2. **Type**: Supports "NOTIFIED" and "EXECUTION_FINISHED" and "PPROF_UPLOAD_FILE_TOO_LARGE_ERROR", "EXECUTION_TASK_ERROR", with the current log displaying "NOTIFIED". | ||||||
| 3. **Time**: The time when the Agent received the task. | ||||||
|
|
||||||
| ### Wait the agent to collect data and upload | ||||||
|
|
||||||
| At this point, Pprof will trace the events you selected when you created the task: | ||||||
|
|
||||||
| 1. CPU: samples CPU usage over time to show which functions consume the most processing time. | ||||||
| 2. ALLOC, HEAP: | ||||||
| - HEAP: a sampling of memory allocations of live objects. | ||||||
| - ALLOC: a sampling of all past memory allocations. | ||||||
| 3. BLOCK, MUTEX: | ||||||
| - BLOCK: stack traces that led to blocking on synchronization primitives. | ||||||
| - MUTEX: stack traces of holders of contended mutexes. | ||||||
| 4. GOROUTINE, THREADCREAT: | ||||||
| - GOROUTINE: stack traces of all current goroutines. | ||||||
| - THREADCREATE: stack traces that led to the creation of new OS threads. | ||||||
|
|
||||||
| Finally, the agent will upload the pprof file produced by Pprof to the oap server for online performance analysis. | ||||||
|
|
||||||
| ### Query the profiling task progresses | ||||||
|
|
||||||
| Wait for Pprof to complete data collection and upload successfully. | ||||||
| We can query the execution logs of the Pprof task and the task status, which includes the following information: | ||||||
|
|
||||||
| 1. **successInstanceIds**: SuccessInstanceIds gives instances that have executed the task successfully. | ||||||
| 2. **errorInstanceIds**: ErrorInstanceIds gives instances that failed to execute the task. | ||||||
| 3. **logs**: All task execution logs of the current task. | ||||||
| 1. **id**: The task id. | ||||||
| 2. **instanceId**: InstanceId is the id of the instance which reported this task log. | ||||||
| 3. **instanceName**: InstanceName is the name of the instance which reported this task log. | ||||||
| 4. **operationType**: Contains "NOTIFIED" and "EXECUTION_FINISHED" and "PPROF_UPLOAD_FILE_TOO_LARGE_ERROR", "EXECUTION_TASK_ERROR". | ||||||
| 5. **operationTime**: operationTime is the time when the operation occurs. | ||||||
|
|
||||||
| ### Analyze the profiling data | ||||||
|
|
||||||
| Once some agents completed the task, we can analyze the data through the following query: | ||||||
|
|
||||||
| 1. **taskId**: The task id. | ||||||
| 2. **instanceIds**: InstanceIds defines the instances to be included for analysis | ||||||
|
|
||||||
| After the query, the following data would be returned to render a flame graph: | ||||||
| 1. **taskId**: The task id. | ||||||
| 2. **elements**: Combined with "id" to determine the hierarchical relationship. | ||||||
| 1. **Id**: Id is the identity of the stack element. | ||||||
| 2. **parentId**: Parent element ID. The dependency relationship between elements can be determined using the element ID and parent element ID. | ||||||
| 3. **codeSignature**: Method signatures in tree nodes. | ||||||
| 4. **total**:The total number of samples of the current tree node, including child nodes. | ||||||
| 5. **self**: The sampling number of the current tree node, excluding samples of the children. | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment format is not consistent, please fix this.