Cangjie Profile Tool
Overview
cjprof (Cangjie Profile) is a performance profiling tool for the Cangjie programming language. It supports the following features:
- Perform CPU hot function sampling on Cangjie programs and export sampling data.
- Analyze hot function sampling data and generate CPU hot function statistical reports or flame graphs.
- Dump heap memory of Cangjie applications and analyze it to generate analysis reports.
Currently, cjprof supports the above features on Linux systems, and only supports heap memory analysis for Cangjie applications on macOS and Windows systems.
Usage Instructions
Run cjprof --help to view command usage. It supports the record, report, and heap subcommands, which are used to collect CPU hot function information, generate CPU hot function reports (including flame graphs), and dump and analyze heap memory respectively.
cjprof --help
Usage: cjprof [--help] COMMAND [ARGS]
The supported commands are:
-v Print version of cjprof
heap Dump heap into a dump file or analyze the heap dump file
record Run a command and record its profile data into data file
report Read profile data file (created by cjprof record) and display the profile
Note:
Since
cjprof recordrelies on the system'sperfpermissions, one of the following two conditions must be met for usage:
- Execute with the
rootuser orsudoprivileges.- Set the system's
perf_event_paranoidparameter (via the/proc/sys/kernel/perf_event_paranoidfile) to -1.Otherwise, insufficient permission errors may occur.
Collecting CPU Hot Function Information
Command
cjprof record
Syntax
cjprof record [<options>] [<command>]
cjprof record [<options>] -- <command> [<options>]
Options
-f, --freq <freq>
Specifies the sampling frequency in hertz (Hz), i.e., the number of samples per second. The default value is 5000 Hz. If set to max or a value exceeding the maximum frequency supported by the system, the maximum supported frequency will be used.
-o, --output <file>
Specifies the filename of the sampling data generated after sampling. The default is cjprof.data.
-p, --pid <pid>
Specifies the process ID of the application to be sampled. This option is ignored when a new application is launched and sampled via <command>.
Examples
- Sample a running application.
# Sample the running application (PID 12345) at a frequency of 10000 Hz, and generate sampling data in the current directory named sample.data after sampling completes.
cjprof record -f 10000 -p 12345 -o sample.data
- Launch a new application and sample it.
# Execute the `test` application in the current directory with arguments `arg1 arg2`, sample it at the maximum frequency supported by the system, and generate sampling data in the current directory named `cjprof.data` (default filename) after sampling completes.
cjprof record -f max -- ./test arg1 arg2
Notes
- After sampling starts, it will only end when the sampled program exits. To stop sampling early, press
Ctrl+Cduring the sampling process.
Generating CPU Hot Function Reports
Command
cjprof report
Syntax
cjprof report [<options>]
Options
-F, --flame-graph
Generates a CPU hot function flame graph instead of the default text report.
-i, --input <file>
Specifies the sampling data file. The default is cjprof.data.
-o, --output <file>
Specifies the filename of the generated CPU hot function flame graph. The default is FlameGraph.svg. This option only takes effect when generating a flame graph.
Examples
- Generate the default CPU hot function text report.
# Analyze sampling data in sample.data and generate a CPU hot function text report.
cjprof report -i sample.data
- Generate a CPU hot function flame graph.
# Analyze sampling data in cjprof.data (default file) and generate a CPU hot function flame graph named test.svg.
cjprof report -F -o test.svg
Report Format Description
-
The text report includes three parts: total sampling percentage of the function (including child functions), self sampling percentage of the function, and function name (displayed as an address if no corresponding symbol information is available). Results are sorted in descending order by total sampling percentage.
-
In the flame graph, the horizontal axis represents the sampling percentage — wider bars indicate a higher sampling percentage and longer execution time. The vertical axis represents the call stack, with parent functions below and child functions above.
Dumping and Analyzing Heap Memory
Command
cjprof heap
Syntax
cjprof heap [<options>]
Options
-D, --depth <depth>
Specifies the maximum display depth of object reference/referenced relationships. The default is 10 levels. This option only takes effect when --show-reference is specified.
-d, --dump <pid>
Dumps the current heap memory of a Cangjie application, where pid is the process ID of the application. It also works if a child thread ID of the application is provided.
--dump-report[=<port>]
Starts an HTTP report server to view heap memory analysis results visually in a web browser. port specifies the server listening port, with a default of 8080. When specifying a port, use = to connect (e.g., --dump-report=9090); space separation is not supported. The server keeps running after analysis completes; press Ctrl+C to stop it.
-i, --input <file>
Specifies the heap memory data file to analyze. The default is cjprof.data.
-o, --output <file>
Specifies the filename of the exported heap memory data. The default is cjprof.data.
--show-reference[=<objnames>]
Displays object reference relationships in the analysis report. objnames are the names of objects to display, which must be fully qualified names, separated by ; for multiple objects. When not specified, all objects are displayed by default. If the object is a root node of the heap, the root node category of the heap it belongs to will also be displayed.
--incoming-reference
Displays referenced-by relationships of objects instead of reference relationships. Must be used together with --show-reference.
-t, --show-thread
Displays Cangjie thread stacks and objects referenced on the stack in the analysis report.
-V, --verbose
Diagnostic option. Prints parsing logs when parsing heap memory data files.
Examples
- Export heap memory data.
# Dump the current heap memory of the running application (PID 12345) to a file named heap.data in the current directory.
cjprof heap -d 12345 -o heap.data
Note:
Dumping heap memory sends a
SIG_USR1signal to the target process. Exercise caution when unsure whether the target process is a Cangjie application, as sending the signal incorrectly may cause unexpected errors. Both the directory of the running Cangjie program and the directory where the dump command is executed require write permissions; otherwise, the operation may fail due to insufficient permissions.
- Start heap memory analysis report server.
# Parse and analyze the heap memory data file heap.data in the current directory, start an HTTP report server on port 9090, and access http://localhost:9090 in a web browser to view the visual analysis report.
cjprof heap -i heap.data --dump-report=9090
Note:
If a proxy is configured, the web page may not be accessible. You need to remove the proxy before accessing it through a web browser.
The visual analysis report provides a dominance tree view, displaying the dominance relationships of heap objects. It supports two visualization modes: sunburst chart and tree chart. Objects can be displayed at two granularity levels: by object or by type. Objects whose proportion falls below the threshold are merged into summary nodes. A Top 10 ranking is provided, showing the top 10 objects by retained heap size.
- Analyze heap memory data and display object information.
# Parse and analyze the heap memory data file heap.data in the home directory, displaying the object type name, instance count, shallow heap size, and retained heap size of each live object in the heap.
cjprof heap -i ~/heap.data
The output of the above command is as follows:
Object Type Objects Shallow Heap Retained Heap
========================================= ============ ============= ==============
default::AAA 1 80 400
default::BBB 4 32 196
default::CCC 2 16 32
- Analyze heap memory data and display Cangjie thread stacks and object references.
# Parse and analyze the heap memory data file cjprof.data (default file) in the current directory, displaying Cangjie thread stacks and objects referenced on the stack.
cjprof heap --show-thread
The output of the above command is as follows:
Object/Stack Frame Shallow Heap Retained Heap
=============================================== ============= ==============
thread0
at Func2() (/home/test/test.cj:10)
<local> default::AAA @ 0x7f1234567800 80 400
at Func1() (/home/test/test.cj:20)
<local> default::CCC @ 0x7f12345678c0 16 16
at main (/home/test/test.cj:30)
- Analyze heap memory data and display object reference relationships.
# Parse and analyze the heap memory data file cjprof.data (default file) in the current directory, displaying reference relationships of objects of type default::AAA and default::BBB.
cjprof heap --show-reference="default::AAA;default::BBB"
The output of the above command is as follows:
Objects with outgoing references:
Object Type Shallow Heap Retained Heap
=============================================== ============= ==============
default::AAA @ 0x7f1234567800 80 400
default::BBB @ 0x7f1234567880 32 48
default::CCC @ 0x7f12345678c0 16 16
default::CCC @ 0x7f12345678e0 16 16
default::BBB @ 0x7f1234567880 32 48
default::CCC @ 0x7f12345678c0 16 16
- Analyze heap memory data and display referenced-by relationships of objects.
# Parse and analyze the heap memory data file cjprof.data (default file) in the current directory, displaying referenced-by relationships of objects of type default::CCC.
cjprof heap --show-reference="default::CCC" --incoming-reference
The output of the above command is as follows:
Objects with incoming references:
Object Type Shallow Heap Retained Heap
=============================================== ============= ==============
default::CCC @ 0x7f12345678c0 16 16
default::BBB @ 0x7f1234567880 32 48
default::AAA @ 0x7f1234567800 80 400
default::CCC @ 0x7f12345678e0 16 16
default::AAA @ 0x7f1234567800 80 400
Heap Memory Analysis Report Explanation
-
Object type names
RawArray<Byte>[],RawArray<Half>[],RawArray<Word>[], andRawArray<DWord>[]represent primitive raw arrays of 1-byte, 2-byte, 4-byte, and 8-byte sizes respectively. -
Shallow Heap refers to the heap memory size occupied by the object itself.
-
Retained Heap refers to the sum of the shallow heap sizes of all objects that can be freed (i.e., objects directly or indirectly referenced by the object) after the object is garbage collected.
-
When the object reference hierarchy exceeds the maximum display depth, or duplicate objects appear due to circular references,
...is used to omit subsequent references.
Memory Analysis API
The cjprof dynamic library provides the following memory analysis APIs to support secondary development.
Parse Heap Snapshot Files
bool ParseHeapSnapshotFiles(std::vector<std::string>& filePaths);
ParseHeapSnapshotFiles accepts the following input parameters:
- filePaths: List of heap snapshot file paths
Returns true only when all heap snapshots are parsed successfully.
Clean Heap Snapshot Data
void CleanHeapSnapshotFiles(std::vector<uint64_t> ids);
CleanHeapSnapshotFiles accepts the following input parameters:
- ids: List of heap snapshot IDs
Clears the parsed data of corresponding heap snapshots.
Query Overview of All Heap Snapshots
std::vector<HeapSnapshot> QueryAllHeapSnapshot();
QueryAllHeapSnapshot returns overview information of all heap snapshots.
Get Heap Snapshot ID
uint64_t GetSnapshotIDByFilePath(std::string filePath);
GetSnapshotIDByFilePath accepts the following input parameters:
- filePath: Heap snapshot file path
Returns the corresponding ID.
Get All Constructor Nodes of Heap Snapshot
std::vector<ConstructorNode> GetConstructorNodesBySnapshotID(uint64_t id);
GetConstructorNodesBySnapshotID accepts the following input parameters:
- id: Heap snapshot ID
Returns all Constructor nodes.
Get Root Nodes of Heap Snapshot
std::vector<ConstructorNode> GetRootNodesBySnapshotID(uint64_t id, std::set<uint8_t> rootTypes);
GetRootNodesBySnapshotID accepts the following input parameters:
- id: Heap snapshot ID
- rootTypes: Collection of root node types
Returns the corresponding list of Constructor node.
GetRootNodesBySnapshotID supports the following root node types:
- 0: Non-root node
- 1: GLOBAL root node
- 2: LOCAL root node
- 3: UNKNOWN root node
Get Diff Root Nodes of Two Heap Snapshots
std::vector<ConstructorDiffNode> GetRootDiffNodesBySnapshotID(uint64_t baseSnapshotId, uint64_t targetSnapshotId, std::set<uint8_t> rootTypes);
GetRootDiffNodesBySnapshotID accepts the following input parameters:
- baseSnapshotId: Base heap snapshot ID
- targetSnapshotId: Target heap snapshot ID
- rootTypes: Collection of root node types
Returns the corresponding list of diff Constructor nodes.
GetRootDiffNodesBySnapshotID supports the following root node types:
- 0: Non-root node
- 1: GLOBAL root node
- 2: LOCAL root node
- 3: UNKNOWN root node
Expand Constructor Node
ConstructorNode ExpandConstructorNode(uint64_t snapshotId, uint64_t nodeId, uint32_t startIndex, uint32_t length);
ExpandConstructorNode accepts the following input parameters:
- snapshotId: Heap snapshot ID
- nodeId: ID of the Constructor node to be expanded
- startIndex: Pagination start position, counting from 0
- length: Pagination length
Returns the expanded Constructor node.
Expand Diff Constructor Node of Two Heap Snapshots
ConstructorDiffNode ExpandConstructorDiffNode(uint64_t baseSnapshotId, uint64_t targetSnapshotId, uint64_t nodeId, uint32_t startIndex, uint32_t length);
ExpandConstructorDiffNode accepts the following input parameters:
- baseSnapshotId: Base heap snapshot ID
- targetSnapshotId: Target heap snapshot ID
- nodeId: ID of the Constructor node to be expanded
- startIndex: Pagination start position, counting from 0
- length: Pagination length
Returns the expanded diff Constructor node.
Expand Instance Node
InstanceNode ExpandInstanceNode(uint64_t snapshotId, uint64_t nodeId, uint32_t startIndex, uint32_t length);
ExpandInstanceNode accepts the following input parameters:
- snapshotId: Heap snapshot ID
- nodeId: ID of Instance node to be expanded
- startIndex: Pagination start position, counting from 0
- length: Pagination length
Returns the expanded Instance node.
Expand Diff Instance Node of Two Heap Snapshots
InstanceDiffNode ExpandInstanceDiffNode(uint64_t baseSnapshotId, uint64_t targetSnapshotId, uint64_t nodeId, uint32_t startIndex, uint32_t length);
ExpandInstanceDiffNode accepts the following input parameters:
- baseSnapshotId: Base heap snapshot ID
- targetSnapshotId: Target heap snapshot ID
- nodeId: ID of the diff Instance node to be expanded
- startIndex: Pagination start position, counting from 0
- length: Pagination length
Returns the expanded diff Instance node.
Expand Attribute Nodes or Referenced Nodes of Instance Node
InstanceNode ExpandDetailNode(uint64_t snapshotId, uint64_t nodeId, bool isReference, uint32_t startIndex, uint32_t length);
ExpandDetailNode accepts the following input parameters:
- snapshotId: Heap snapshot ID
- nodeId: ID of the Instance node to be expanded
- isReference:
truefor expanding attribute nodes,falsefor expanding referenced nodes - startIndex: Pagination start position, counting from 0
- length: Pagination length
Returns the expanded Instance node.
Expand Attribute Nodes or Referenced Nodes of Diff Instance Node Between Two Heap Snapshots
InstanceDiffNode ExpandDetailDiffNode(uint64_t baseSnapshotId, uint64_t targetSnapshotId, uint64_t nodeId, bool isReference, uint32_t startIndex, uint32_t length);
ExpandDetailDiffNode accepts the following input parameters:
- baseSnapshotId: Base heap snapshot ID
- targetSnapshotId: Target heap snapshot ID
- nodeId: ID of the Instance node to be expanded
- isReference:
truefor expanding attribute nodes,falsefor expanding referenced nodes - startIndex: Pagination start position, counting from 0
- length: Pagination length
Returns the expanded diff Instance node.
Query Diff Information Between Two Heap Snapshots
std::vector<ConstructorDiffNode> QuerySnapshotComparison(uint64_t baseId, uint64_t targetId);
QuerySnapshotComparison accepts the following input parameters:
- baseId: Base heap snapshot ID
- targetId: Target heap snapshot ID
Returns all diff Constructor nodes.
Get Paths from An Instance Node to Root Node
std::vector<std::vector<InstanceNode>> GetNodeRootpaths(uint64_t snapshotId, uint64_t nodeId, int32_t pathNum);
GetNodeRootpaths accepts the following input parameters:
- snapshotId: Heap snapshot ID
- nodeId: ID of the Instance node to query
- pathNum: Number of paths to the root node, -1 means all paths
Returns the list of paths from the Instance node to the root node.
Get Thread Information
std::vector<ThreadInfo> GetThreadInfos(uint64_t snapshotId);
GetThreadInfos accepts the following input parameters:
- snapshotId: Heap snapshot ID
Returns all thread information in the heap snapshot.
Query Instance Node Count by Keyword
uint32_t QuerySnapshotCountOfResults(std::string keyword, bool isIgnoreCase, uint64_t snapshotId);
QuerySnapshotCountOfResults accepts the following input parameters:
- keyword: Search keyword
- isIgnoreCase: Whether to ignore case
- snapshotId: Heap snapshot ID
Returns the count of matched Instance nodes.
Query Constructor Node of A Specific Instance Node Searched by Keyword
ConstructorNode QuerySnapshotNodeByIndex(std::string keyword, bool isIgnoreCase, uint64_t snapshotId, uint32_t length, uint32_t index);
QuerySnapshotNodeByIndex accepts the following input parameters:
- keyword: Search keyword
- isIgnoreCase: Whether to ignore case
- snapshotId: Heap snapshot ID
- length: Maximum number of child nodes of the Constructor node
- index: The Nth matched Instance node
Returns the Constructor node that the matched Instance node belongs to.
Query Diff Instance Node Count of Two Heap Snapshots by Keyword
uint32_t QueryComparisonCountOfResults(std::string keyword, bool isIgnoreCase, uint64_t baseId, uint64_t targetId);
QueryComparisonCountOfResults accepts the following input parameters:
- keyword: Search keyword
- isIgnoreCase: Whether to ignore case
- baseId: Base heap snapshot ID
- targetId: Target heap snapshot ID
Returns the count of matched diff Instance nodes.
Query Diff Constructor Node of A Specific Diff Instance Node Searched by Keyword
ConstructorDiffNode QueryComparisonNodeByIndex(std::string keyword, bool isIgnoreCase, uint64_t baseId, uint64_t targetId, uint32_t length, uint32_t index);
QueryComparisonNodeByIndex accepts the following input parameters:
- keyword: Search keyword
- isIgnoreCase: Whether to ignore case
- baseId: Base heap snapshot ID
- targetId: Target heap snapshot ID
- length: Maximum number of child nodes of the Constructor node
- index: The Nth matched diff Instance node
Returns the diff Constructor node that the matched diff Instance node belongs to.
class HeapSnapshot
HeapSnapshot represents overview information of a heap snapshot, containing the following fields:
- uint64_t id: Heap snapshot ID
- uint64_t fileSize: Heap snapshot file size
- std::string filePath: Heap snapshot file path
class InstanceNode
InstanceNode represents information of an Instance node, containing the following fields:
- std::string className: Type name
- uint32_t distance: Shortest distance to the root node
- uint32_t retainedSize: Retained heap size
- uint32_t shallowSize: Shallow heap size
- double shallowSizePercent: Percentage of shallow heap size in total heap size
- double retainedSizePercent: Percentage of retained heap size in total heap size
- uint32_t totalSize: Total heap size
- std::vector<InstanceNode> children: List of attribute nodes
- std::vector<InstanceNode> retainerNodes: List of referenced nodes
- uint64_t id: Node ID
- uint32_t nodeIndex: Node index
- std::string type: Node type
- std::string rootType: Root node type
- uint32_t childrenCount: Number of attribute nodes
- uint32_t retainerCount: Number of referenced nodes
- uint32_t startPosition: Pagination start position
- uint32_t endPosition: Pagination end position
- uint32_t arrayLength: Number of elements in the array
class InstanceDiffNode
InstanceDiffNode inherits from InstanceNode and represents information of a diff Instance node, with the following additional fields:
- uint32_t addedCount: Number of objects added in the base heap snapshot
- uint32_t removedCount: Number of objects removed in the base heap snapshot
- int64_t countDelta: Difference between added object count and removed object count
- uint32_t addedSize: Shallow heap size of objects added in the base heap snapshot
- uint32_t removedSize: Shallow heap size of objects removed in the base heap snapshot
- int64_t sizeDelta: Difference between shallow heap size of added objects and removed objects
- bool added: Whether the Instance node is a newly added object
class ConstructorNode
ConstructorNode represents information of a Constructor node, containing the following fields:
- std::string className: Type name
- uint32_t totalSize: Total heap size
- uint64_t id: Node ID
- uint32_t childrenCount: Number of contained Instance nodes
- uint32_t distance: Shortest distance to the root node among contained Instance nodes
- uint32_t shallowSize: Shallow heap size
- uint32_t retainedSize: Retained heap size
- double shallowSizePercent: Percentage of shallow heap size in total heap size
- double retainedSizePercent: Percentage of retained heap size in total heap size
- double totalInstanceCountPercent: Percentage of contained Instance node count in total Instance node count
- std::vector<InstanceNode> children: List of contained Instance nodes
- uint32_t startPosition: Pagination start position
- uint32_t endPosition: Pagination end position
class ConstructorDiffNode
ConstructorDiffNode inherits from ConstructorNode and represents information of a diff Constructor node, with the following additional fields:
- uint32_t addedCount: Number of objects added in the base heap snapshot
- uint32_t removedCount: Number of objects removed in the base heap snapshot
- int64_t countDelta: Difference between added object count and removed object count
- uint32_t addedSize: Shallow heap size of objects added in the base heap snapshot
- uint32_t removedSize: Shallow heap size of objects removed in the base heap snapshot
- int64_t sizeDelta: Difference between shallow heap size of added objects and removed objects
- uint32_t baseTotalSize: Total heap size of base heap snapshot
- uint32_t targetTotalSize: Total heap size of target heap snapshot
- std::vector<bool> childAddedStates: List indicating whether each contained Instance node is added or removed
class ThreadInfo
ThreadInfo represents thread information, containing the following fields:
- std::string name: Thread name
- std::vector<Frame> frames: List of stack frames in the thread
- uint64_t id: Thread ID
Frame represents a stack frame information in the thread, containing the following fields:
- std::string funcName: Function name corresponding to the stack frame
- std::string fileName: Source file name corresponding to the stack frame
- int line: Source code line number corresponding to the stack frame
- std::vector<InstanceNode> locals: List of local objects in the stack frame
- uint64_t id: Stack frame ID