Warehouse-level code parallelization optimization method
By acquiring the global dependency graph and performance data of the code repository, constructing a global navigation graph, and adding parallelization instructions, the suboptimal performance and erroneous code problems caused by isolated function-level optimization in existing technologies are solved, and automatic parallel optimization at the repository level is achieved.
Patent Information
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- INST OF SOFTWARE - CHINESE ACAD OF SCI
- Filing Date
- 2026-03-05
- Publication Date
- 2026-07-31
AI Technical Summary
Existing parallel optimization methods, being limited to isolated function-level optimization, are prone to suboptimal performance, generating error code, and missing key optimization objectives, thus affecting the effectiveness of parallel optimization.
Obtain the global dependency graph within the code repository, mark the performance data of functions, construct a global navigation graph, add parallelization instructions at the function locations where the performance data exceeds the threshold, and use OpenMP instructions for compilation optimization.
It achieves parallel optimization across function call chains and global variable dependencies, avoids optimization conflicts and data races, focuses on high-value computing areas, ensures optimization safety and accuracy, and improves the effect of parallel optimization.
Smart Images

Figure CN121785609B_ABST
Abstract
Description
Technical Field
[0001] This application relates to the field of parallel optimization technology, specifically to a repository-level code parallel optimization method. Background Technology
[0002] Existing parallel optimization methods can be broadly categorized into three paradigms: rule-based tools, specialized pre-trained models, and tools based on large language models.
[0003] However, all three paradigms mentioned above are limited to isolated function-level optimization. In this case, on the one hand, in order to avoid potential errors, parallel optimization must resort to conservative strategies, which inevitably leads to suboptimal performance. On the other hand, only scattered and partial code information can be obtained, and parallel optimization is prone to generating erroneous code that seems reasonable but has fundamental defects such as data races. Furthermore, focusing mainly on semantically related code for completion or debugging, parallel optimization is prone to blindly missing key optimization objectives.
[0004] In summary, existing parallel optimization methods, limited to isolated function-level optimization, are prone to suboptimal performance, generating erroneous code, and missing key optimization objectives, thus severely impacting the effectiveness of parallel optimization. Summary of the Invention
[0005] This application provides a repository-level code parallel optimization method to address the technical problem that existing parallel optimization methods, which are limited to isolated function-level optimization, are prone to suboptimal performance, generate erroneous code, and miss key optimization objectives, thus seriously affecting the effectiveness of parallel optimization.
[0006] This application provides a repository-level code parallel optimization method, including:
[0007] Obtain the global dependency graph of the source code within the code repository; the global dependency graph includes the call relationships and data dependencies between multiple functions in the source code;
[0008] The performance data of each function is marked in the global dependency graph to obtain the global navigation graph;
[0009] Based on the global navigation graph, parallelization instructions are added to the target location of the source code to obtain the parallel optimized source code; the target location is the function location where the performance data exceeds a threshold.
[0010] In one embodiment, obtaining the global dependency graph of the source code within the code repository includes:
[0011] Calling multiple functions in the source code;
[0012] Obtain the call relationship graph and data dependencies between functions;
[0013] The data dependencies are marked in the call relationship graph to obtain the global dependency graph.
[0014] In one embodiment, obtaining the call relationship graph between functions includes:
[0015] Convert the source code into an executable file;
[0016] Tracing the execution process of the executable file;
[0017] Based on the entry and exit nodes of each function during the execution process, the calling relationship between the functions is constructed to obtain the calling relationship graph.
[0018] In one embodiment, obtaining the data dependencies between functions includes:
[0019] Generate an intermediate representation of the source code;
[0020] Obtain the input and output variables of each function recorded in the intermediate representation;
[0021] The data dependencies are obtained based on the input and output variables of each function.
[0022] In one embodiment, the performance data of each function includes the execution time and call frequency of each function, which are obtained based on the following method:
[0023] Based on the entry and exit nodes of each function during the execution process, the execution time of each function is timed to obtain the execution time of each function;
[0024] Based on the entry and exit nodes of each function during the execution process, the number of times each function is called during the execution process is counted to obtain the calling frequency of each function.
[0025] In one embodiment, the performance data of each function includes the execution time of the loop structure within each function, and the execution time of the loop structure within each function is obtained based on the following method:
[0026] Identify the boundaries of loop structures within each function in the intermediate representation;
[0027] Create a copy of the source code;
[0028] Based on the boundary, the execution time of the loop structure is timed in the copy to obtain the execution time of the loop structure within each function.
[0029] In one embodiment, the performance data of each function includes the execution time of each function, the calling frequency of each function, and the execution time of the loop structure within each function. The target position is the position of the function whose execution time exceeds a first threshold and / or whose calling frequency exceeds a second threshold.
[0030] The parallelization instructions are used by the compiler to guide the compiler to perform parallel optimization on the function at the target location when compiling the parallel optimized source code;
[0031] The parallel optimization of the function at the target position includes:
[0032] If the function at the target position is not a recursive function and loop optimization has not been completed, parallel optimization is performed on the function at the target position and the loop structure within the function at the target position whose execution time exceeds the third threshold.
[0033] In one embodiment, the performance data of each function includes the execution time of each function, the calling frequency of each function, and the execution time of the loop structure within each function. The target position is the position of the function whose execution time exceeds a first threshold and / or whose calling frequency exceeds a second threshold.
[0034] The parallelization instructions are used by the compiler to guide the compiler to perform parallel optimization on the function at the target location when compiling the parallel optimized source code;
[0035] The parallel optimization of the function at the target position includes:
[0036] If the function at the target location is a recursive function and task optimization has not been completed, a depth-limited task optimization is performed on the recursive function.
[0037] In one embodiment, after obtaining the parallel-optimized source code, the process includes:
[0038] If the parallel optimized source code does not meet the verification pass conditions, the parallel optimized source code is retried for verification and / or rolled back for modification until the parallel optimized source code meets the verification pass conditions, and the parallel optimized source code is pruned.
[0039] The verification is successful if the compilation result of the parallel optimized source code is successful, the running result is correct, and the running speed is improved.
[0040] In one embodiment, after obtaining the parallel-optimized source code, the process includes:
[0041] If the parallel optimized source code meets the verification pass conditions, the parallel optimized source code is pruned.
[0042] The verification is successful if the compilation result of the parallel optimized source code is successful, the running result is correct, and the running speed is improved.
[0043] The repository-level code parallel optimization method provided in this application obtains a global dependency graph of the source code in the code repository. The global dependency graph includes the call relationships and data dependencies between multiple functions in the source code. The performance data of each function is marked in the global dependency graph to obtain a global navigation graph. Based on the global navigation graph, parallelization instructions are added to the target position of the source code to obtain the parallel optimized source code. The target position is the position of the function whose performance data exceeds a threshold. This application obtains a global dependency graph of the source code within the code repository, enabling the acquisition of global information on the call relationships and data dependencies between multiple functions in the source code. This allows parallel optimization to move beyond isolated function-level optimization and transcend function call chains and global variable dependencies, avoiding optimization conflicts and data race risks between functions. This minimizes suboptimal performance and erroneous code, achieving global optimization through correct code. Furthermore, based on the global navigation graph, parallelization instructions are added to function locations in the source code where performance data exceeds a threshold. These locations, identified as computational hotspots, are targeted for parallel optimization, focusing on critical, high-value computational areas and avoiding blind optimization that wastes resources. Moreover, by acquiring global information on the call relationships and data dependencies between multiple functions in the source code beforehand, the addition of parallelization instructions adheres to these relationships, preserving the original logic of the source code and ensuring absolute safety in parallel optimization, further preventing the generation of erroneous code. In summary, this application introduces a global navigation mechanism. By obtaining the global dependency graph of the source code in the code repository and marking the computation hotspots, it navigates the addition of parallelization instructions. This makes parallel optimization no longer limited to isolated function-level optimization, avoiding suboptimal performance, generating erroneous code, and missing key optimization targets, thereby effectively improving the effect of parallel optimization and realizing automatic parallel optimization of repository-level code. Attached Figure Description
[0044] To more clearly illustrate the technical solutions in this application or the prior art, the drawings used in the description of the embodiments or the prior art will be briefly introduced below. Obviously, the drawings described below are some embodiments of this application. For those skilled in the art, other drawings can be obtained based on these drawings without creative effort.
[0045] Figure 1 This is one of the flowcharts illustrating the repository-level code parallel optimization method provided in this application embodiment;
[0046] Figure 2 This is the second flowchart illustrating the repository-level code parallel optimization method provided in this application embodiment;
[0047] Figure 3 This is the third flowchart illustrating the repository-level code parallel optimization method provided in this application embodiment;
[0048] Figure 4 This is the fourth flowchart of the repository-level code parallel optimization method provided in the embodiments of this application;
[0049] Figure 5 This is a schematic diagram of the parallel optimization process under the multi-agent cooperative framework provided in the embodiments of this application;
[0050] Figure 6 This is a schematic diagram illustrating the workflow of the global dependency analysis agent and the global performance analysis agent within the multi-agent collaboration framework provided in this application embodiment;
[0051] Figure 7 This is a schematic diagram illustrating the workflow of adding agents using OpenMP instructions within the multi-agent cooperation framework provided in this application embodiment;
[0052] Figure 8 This is a schematic diagram of the structure of the electronic device provided in the embodiments of this application. Detailed Implementation
[0053] To make the objectives, technical solutions, and advantages of this application clearer, the technical solutions of this application will be clearly and completely described below with reference to the accompanying drawings of the embodiments. Obviously, the described embodiments are only some embodiments of this application, not all embodiments. Based on the embodiments of this application, all other embodiments obtained by those skilled in the art without creative effort are within the scope of protection of this application.
[0054] It should be noted that in the description of the embodiments of this application, the terms "comprising," "including," or any other variations thereof are intended to cover non-exclusive inclusion, such that a process, method, article, or apparatus that includes a list of elements includes not only those elements but also other elements not expressly listed, or elements inherent to such a process, method, article, or apparatus. Without further limitations, an element defined by the phrase "comprising one..." does not exclude the presence of other identical elements in the process, method, article, or apparatus that includes said element. The terms "upper," "lower," etc., indicating orientation or positional relationships based on the orientation or positional relationships shown in the accompanying drawings, are only for the convenience of describing this application and simplifying the description, and do not indicate or imply that the device or element referred to must have a specific orientation, or be constructed and operated in a specific orientation, and therefore should not be construed as a limitation of this application. Unless otherwise expressly specified and limited, the terms "installed," "connected," and "linked" should be interpreted broadly, for example, they can be fixed connections, detachable connections, or integral connections; they can be mechanical connections or electrical connections; they can be direct connections or indirect connections through an intermediate medium; and they can be internal connections between two elements. Those skilled in the art can understand the specific meaning of the above terms in this application according to the specific circumstances.
[0055] The terms "first," "second," etc., used in this application are used to distinguish similar objects and not to describe a specific order or sequence. It should be understood that such data can be interchanged where appropriate so that embodiments of this application can be implemented in orders other than those illustrated or described herein, and the objects distinguished by "first," "second," etc., are generally of the same class, without limiting the number of objects; for example, a first object can be one or more. Furthermore, "and / or" indicates at least one of the connected objects, and the character " / " generally indicates that the preceding and following objects have an "or" relationship.
[0056] Figure 1 This is one of the flowcharts illustrating the repository-level code parallel optimization method provided in this application embodiment. (Refer to...) Figure 1 This application provides a repository-level code parallel optimization method, which may include:
[0057] Step 101: Obtain the global dependency graph of the source code in the code repository;
[0058] The global dependency graph includes the call relationships and data dependencies between multiple functions in the source code;
[0059] Step 102: Mark the performance data of each function in the global dependency graph to obtain the global navigation graph;
[0060] Step 103: Based on the global navigation graph, add the parallelization instructions to the target location of the source code to obtain the parallel optimized source code.
[0061] The target location is the function location where the performance data exceeds the threshold.
[0062] In step 101, the calling relationships between multiple functions describe the transfer path of control flow. During execution, a function (called the caller) will actively call one or more other functions (called the callees) to complete a specific subtask. This call can be direct (function A directly calls function B) or indirect (function A calls function B, and function B then calls function C).
[0063] Data dependencies between multiple functions characterize the flow and usage of data between functions. A data dependency occurs when the execution result of one function (its return value or its side effects, such as modifying global variables or output parameters) is used by another function. For example, if function A calculates an intermediate result and returns it, and function B receives that result as an input parameter for further processing, then function B is data-dependent on function A. Furthermore, implicit data dependencies may also exist between multiple functions if they share the same global variable or external resource (such as a file or database).
[0064] As shown above, the calling relationships and data dependencies between multiple functions jointly determine the static structure and dynamic behavior of the source code. Obtaining a global dependency graph that includes these calling relationships and data dependencies deeply integrates the static structure and dynamic behavior of the source code within the code repository, forming a unified and comprehensive global framework. This fundamentally avoids the fragmented perspective of existing technologies that are limited to function-level optimization.
[0065] In step 102, the performance data of the function is usually used to measure the function's execution efficiency, resource consumption and scalability. It can include execution time, time complexity, space complexity, memory usage, CPU utilization, call overhead, input / output or external dependency time, throughput, caching behavior and locality, scalability, etc., which can be obtained through performance analysis tools, benchmark tests or static analysis.
[0066] By marking the performance data of each function in the global dependency graph, the running performance of each function can be visually quantified. Furthermore, corresponding thresholds can be set for the performance data of each function, so that computational hotspots with high computational density can be identified based on the comparison with the thresholds.
[0067] In step 103, the function corresponding to the performance data exceeding the threshold is obtained in the global navigation graph, and the parallelization instruction is added to the corresponding function position in the source code. Parallelization opportunities are fully identified from a global perspective, and the navigation of parallelization instructions to the computing hotspot position is realized. This allows the parallel optimization target to focus on the key high-value computing area. Parallel optimization of this high-value computing area can bring significant performance improvement.
[0068] Furthermore, the parallelization instruction can be any instruction capable of converting a serial code repository into a parallel code repository; no limitation is made here. In this embodiment, OpenMP (Open Multi-Processing) instructions are used as the parallelization instructions. These instructions are parallelization syntax provided by OpenMP, such as #pragma omp parallel or #pragma omp task. This embodiment integrates loop-level parallelization strategies and task-level parallelization strategies in this instruction.
[0069] It's worth noting that OpenMP is a powerful shared-memory parallelism application programming interface that provides thousands of flexible primitive clause combinations and is used in over 80% of computationally intensive scientific and engineering projects. Adding OpenMP instructions to computationally hot locations in the source code can significantly improve the execution speed of functions at those locations.
[0070] The repository-level code parallel optimization method provided in this embodiment obtains a global dependency graph of the source code in the code repository. The global dependency graph includes the call relationships and data dependencies between multiple functions in the source code. The performance data of each function is marked in the global dependency graph to obtain a global navigation graph. Based on the global navigation graph, parallelization instructions are added to the target position of the source code to obtain the parallel optimized source code. The target position is the position of the function whose performance data exceeds a threshold. This embodiment obtains a global dependency graph of the source code within the code repository, enabling the acquisition of global information on the call relationships and data dependencies between multiple functions in the source code. This allows parallel optimization to move beyond isolated function-level optimization and transcend function call chains and global variable dependencies, avoiding optimization conflicts and data race risks between functions. This minimizes suboptimal performance and erroneous code, achieving global optimization through correct code. Furthermore, based on the global navigation graph, parallelization instructions are added to function locations in the source code where performance data exceeds a threshold. These locations are identified as computational hotspots, and adding parallelization instructions at these locations focuses the parallel optimization objective on critical, high-value computational areas, avoiding blind optimization and wasted resources. Moreover, because global information on the call relationships and data dependencies between multiple functions in the source code is obtained beforehand, adding parallelization instructions adheres to these relationships without disrupting the original logic of the source code, ensuring absolute safety in parallel optimization and further preventing the generation of erroneous code. In summary, this embodiment introduces a global navigation mechanism. By obtaining the global dependency graph of the source code in the code repository and marking the computation hotspots, it navigates the addition of parallelization instructions. This makes parallel optimization no longer limited to isolated function-level optimization, avoiding suboptimal performance, generating erroneous code, and missing key optimization targets. As a result, it effectively improves the effect of parallel optimization and realizes automatic parallel optimization of repository-level code.
[0071] Figure 2 This is the second flowchart illustrating the repository-level code parallel optimization method provided in this application embodiment. (Refer to...) Figure 2 In one embodiment, step 101 may include:
[0072] Step 201: Call multiple functions in the source code;
[0073] Step 202: Obtain the call relationship graph and data dependencies between functions;
[0074] Step 203: Mark the data dependencies in the call relationship graph to obtain the global dependency graph.
[0075] In step 201, main.c can be located or created to serve as the entry point for calling multiple functions in the source code within the code repository.
[0076] In step 202, firstly, the call relationships between the functions are obtained, and a call relationship graph is generated. This call relationship graph can be a directed graph, where the nodes are functions and the edges represent the call behavior; it can also be a tree graph, where the root node represents the main function or entry function, and the branches represent other functions called layer by layer; other graph structures can also be used, which are not limited here.
[0077] Furthermore, obtaining the data dependencies between functions can include data dependencies between functions at the same level in the call relationship graph, as well as data dependencies between functions at different levels; this is not limited here.
[0078] In step 203, since the call relationship graph has already depicted the call relationship between each function, further marking the data dependency relationship between functions at the same level and between functions at different levels in the call relationship graph can achieve a comprehensive capture of the global dependency relationship of the source code and generate a global dependency graph.
[0079] It should be noted that, in this embodiment, the graph structure used to carry global navigation information can be, in addition to a global dependency graph, a more complex graph structure such as a code attribute graph, a code knowledge graph, or a dedicated graph database, as long as the data structure therein can effectively store and query global information such as the call relationships, data dependencies, and computational hotspots of each function in the entire code repository.
[0080] This embodiment uses main.c as the entry point to call multiple functions in the source code, thereby obtaining the call relationships and data dependencies between the functions. After generating a call relationship graph based on the call relationships, the data dependencies are then marked in the call relationship graph to obtain a global dependency graph. This global dependency graph deeply integrates the static structure and dynamic behavior of the source code in the code repository and contains global information of the source code.
[0081] Figure 3 This is the third flowchart illustrating the repository-level code parallel optimization method provided in this application. (Refer to...) Figure 3 In one embodiment, step 202 may include:
[0082] 301. Convert the source code into an executable file;
[0083] 302. Trace the execution process of the executable file;
[0084] 303. Based on the entry and exit nodes of each function during execution, construct the calling relationship between the functions to obtain the calling relationship graph.
[0085] In step 301, the source code can be converted into an executable file using GCC (GNU Compiler Collection), or more specifically, GCC-O0 can be used to convert the source code into an executable file.
[0086] GCC is a compiler system maintained by the GNU (GNU's Not Unix) project that supports multiple programming languages. It can convert high-level program source code into machine code that can be run directly on the target computer architecture. GCC-O0 is an optimization option of GCC that means "no optimization" and is the default optimization level of GCC. This optimization option prevents the compiler from performing any performance or size optimization on the source code. The execution logic of the converted executable file is completely consistent with the source code, which facilitates accurate tracing of each function in the source code.
[0087] In steps 302 to 303, the execution process of the executable file can be traced using Uftrace. Uftrace is an open-source function-level tracing and performance profiling tool for C / C++, Rust, and even some Python programs. It can effectively trace the entry and exit nodes of each function during execution, thereby constructing the call relationship between each function and obtaining the call relationship graph.
[0088] Specifically, the entry and exit nodes of each function during execution refer to the two key nodes when the executable file is running: when each function begins execution and when it finishes execution and returns. These nodes represent a complete lifecycle of each function. By tracing these two key nodes, we can accurately determine which functions call each function and which functions call each function, thus enabling us to construct the call relationships between functions and obtain a call relationship graph. The tracing of these two key nodes can be achieved using dynamic instrumentation or with compiler assistance.
[0089] This embodiment strictly converts the source code into an executable file according to its original execution logic and traces the execution process of the executable file. This allows for the tracking of key nodes such as the entry and exit nodes of each function in the source code, providing a comprehensive understanding of the function calls and being called. As a result, it is possible to accurately construct the call relationships between functions and generate a call relationship graph that can serve as a global navigation skeleton.
[0090] Figure 4 This is the fourth flowchart illustrating the repository-level code parallel optimization method provided in this application's embodiments. (Refer to...) Figure 4 In one embodiment, step 202 may include:
[0091] Step 401: Generate an intermediate representation of the source code;
[0092] Step 402: Obtain the input and output variables of each function recorded in the intermediate representation;
[0093] Step 403: Based on the input and output variables of each function, obtain the data dependencies.
[0094] In step 401, Clang can be used to generate the LLVM IR (LLVM Intermediate Representation) of the source code from main.c.
[0095] Clang is a compiler front-end based on the LLVM architecture, applicable to C / C++, Objective-C, and some other languages. LLVM is a modular, reusable collection of compiler and toolchain technologies, the core of which is a programming language-independent intermediate representation and optimization framework. LLVM IR is an intermediate representation used in the LLVM framework that is independent of both the source language and the target machine. It is a neutral bridge connecting the compiler front-end and back-end, and the core carrier for machine-independent optimization, containing read and write records of various variables.
[0096] In steps 402 to 403, since the functions in the source code were called in advance using main.c, the LLVM IR of the source code generated from main.c also records the data flow information of each function during the calling and being called process, such as memory and variable input / output logs, function and loop information, variable information, etc. Thus, the input variables and output variables of each function can be obtained from them, and the flow trajectory of each variable between each function can be fully understood, and the data dependency relationship between each function can be obtained.
[0097] The above data dependency relationships refer to the sequential constraints between function instructions due to shared data. They mainly include three modes: RAW (Read After Write), WAR (Write After Read), and WAW (Write After Write). These three modes are the core factors that ensure the correctness of the source code and limit the parallel optimization of the compiler and processor.
[0098] In this context, RAW means that the next instruction needs to read the data written by the previous instruction, WAR means that the next instruction needs to write the data read by the previous instruction, and WAW means that both instructions need to write to the same register or memory location.
[0099] This embodiment generates an intermediate representation of the source code to obtain records of the input and output variables of each function, thereby enabling the tracking of the flow trajectory of each function variable in the source code and accurately understanding the data dependencies between functions.
[0100] In one embodiment, the performance data for each function includes the execution time and call frequency of each function. The execution time and call frequency of each function can be obtained based on the following method:
[0101] 1. Based on the entry and exit nodes of each function during the execution process, the execution time of each function is timed to obtain the execution time of each function;
[0102] 2. Based on the entry and exit nodes of each function during execution, count the number of times each function is called during execution to obtain the call frequency of each function.
[0103] When tracing the execution process of an executable file using Uftrace, dynamic instrumentation or compiler assistance can be used to trace the entry and exit nodes of each function. In addition to constructing the call relationships between functions, the execution time of each function can be calculated, and the number of times each function is called can be counted, thereby obtaining the execution time and call frequency of each function.
[0104] Dynamic instrumentation involves automatically inserting additional measurement instructions into the entry and exit nodes of each function in the executable file. This allows for the accurate collection of the execution time and call frequency of each function without altering the original logic of the executable file.
[0105] The execution time and call frequency of each function are marked at the corresponding function position in the global dependency graph. Thresholds are set for the execution time and call frequency of each function, making it easy to identify functions in the global navigation graph whose execution time and call frequency exceed the thresholds. This serves as a navigation function to add parallelized instructions to computationally hot locations, avoiding blind optimization that wastes resources on functions with extremely short execution times or extremely low call frequencies. This prevents the benefits of parallelization from being insufficient to offset the inherent scheduling overhead, thereby reducing the overall speedup.
[0106] According to empirical rules, the execution time of a code segment usually needs to exceed 50 microseconds to be considered to have sufficient parallelization benefits to offset the inherent scheduling overhead. Therefore, the threshold for function execution time can be set to 50 microseconds. Only when the execution time of a function exceeds 50 microseconds will it be optimized for parallelism, thereby maximizing the optimization benefits.
[0107] In this embodiment, during the aforementioned process of tracing the entry and exit nodes of each function using dynamic instrumentation or compiler assistance, the execution time and number of calls of each function are calculated simultaneously to obtain the execution time and call frequency of each function. This data is used as performance data for each function and can be combined with corresponding thresholds to accurately identify computational hotspots, providing precise navigation for the addition of parallelization instructions.
[0108] In one embodiment, the performance data of each function includes the execution time of the loop structure within each function. The execution time of the loop structure within each function can be obtained based on the following method:
[0109] Identify the boundaries of loop structures within each function in the intermediate representation, create a copy of the source code, and based on these boundaries, time the execution duration of the loop structures within the copy to obtain the execution time of each loop structure within the function.
[0110] As mentioned above, the middle part indicates that LLVM IR records information such as memory and variable input / output logs, function and loop information, and variable information, which can be used to identify the boundaries of loop structures within each function, i.e., the start and end nodes of loop structures within each function.
[0111] Furthermore, a copy of the source code is created, and based on this boundary, dynamic instrumentation is performed on the copy. This involves automatically inserting additional measurement instructions at the start and end nodes of the loop structures within each function to accurately collect the execution time of the loop structures within each function without changing the original logic of the copy.
[0112] The execution time of each loop structure within a function is marked at the corresponding function position in the global dependency graph, and a threshold is set for the execution time of the loop structure within a function. This makes it easy to identify loop structures in the global navigation graph whose execution time exceeds the threshold. This serves as a navigation function for adding parallel instructions to computation hotspots, avoiding blind optimization that wastes resources on loop structures with extremely short execution times. This prevents the benefits of parallelization from being insufficient to offset the inherent scheduling overhead, thereby reducing the overall speedup.
[0113] According to empirical rules, the execution time of a single code segment usually needs to exceed 50 microseconds to be considered that its parallelization benefits are large enough to offset the inherent scheduling overhead. Therefore, the threshold for the execution time of the loop structure within the function can be set to 50 microseconds. Only when the execution time of the loop structure within the function exceeds 50 microseconds will it be optimized for parallelism, thereby maximizing the optimization benefits.
[0114] In this embodiment, the boundaries of the loop structures within each function are identified based on the intermediate representation LLVM IR, and then the boundary points are dynamically instrumented on the generated source code copy to obtain the execution time of the loop structures within each function. This time is used as the performance data of each function, and can be combined with the corresponding threshold to accurately identify the computation hotspot locations, providing precise navigation for the addition of parallelization instructions.
[0115] In one embodiment, the performance data of each function includes the execution time of each function, the call frequency of each function, and the execution time of the loop structure within each function. The target position is the position of the function whose execution time exceeds a first threshold and / or whose call frequency exceeds a second threshold.
[0116] Parallelization instructions are used by the compiler to guide the compiler to perform parallel optimization on the function at the target location when compiling parallel-optimized source code;
[0117] Parallel optimization of the function at the target location may include:
[0118] If the function at the target position is not a recursive function and loop optimization has not been completed, perform parallel optimization on the function at the target position and the loop structure within the function at the target position whose execution time exceeds the third threshold.
[0119] The first threshold, the second threshold, and the third threshold can all be set according to actual needs, and there is no limitation here. In this embodiment, the first threshold and the third threshold can both be set to 50 microseconds.
[0120] If there are multiple target positions where the function is not a recursive function and loop optimization has not been completed, then the functions and their internal loop structures whose execution time exceeds the third threshold should be optimized in parallel from the higher level to the lower level according to the call hierarchy of these target position functions. At the same time, it is necessary to ensure that functions with data dependencies are not optimized in parallel in the same region to avoid interference from shared data on the optimization process.
[0121] It should be noted that the parallel optimization of the function at the target location by the compiler in this embodiment is to convert the function from serial code to parallel code during the compilation stage so that it can be executed in parallel code later, rather than performing code conversion on the original source code, so it does not change the original source code.
[0122] This embodiment focuses on the optimization of non-recursive functions and their internal loops. When the non-recursive function at the target position has not completed loop optimization, it prioritizes the parallel optimization of non-recursive functions with high call levels and their internal hot loop structures, effectively improving the benefits of parallel optimization.
[0123] In one embodiment, the performance data of each function includes the execution time of each function, the call frequency of each function, and the execution time of the loop structure within each function. The target position is the position of the function whose execution time exceeds a first threshold and / or whose call frequency exceeds a second threshold.
[0124] Parallelization instructions are used by the compiler to guide the compiler to perform parallel optimization on the function at the target location when compiling parallel-optimized source code;
[0125] Parallel optimization of the function at the target location can include:
[0126] If the function at the target location is a recursive function and task optimization has not been completed, perform depth-limited task optimization on the recursive function.
[0127] The first threshold, the second threshold, and the third threshold can all be set according to actual needs, and there is no limitation here. In this embodiment, the first threshold and the third threshold can both be set to 50 microseconds.
[0128] If the function at the target location is a recursive function, its tree / graph-like internal structure of self-calling differs significantly from the linear iterative loop structure of a regular function, making it unsuitable for parallel optimization of general functions. Therefore, task optimization is necessary. This involves encapsulating each recursive call as an independent task at each recursive branch point and using a work-stealing mechanism to achieve parallel execution of these tasks. This allows for parallel optimization of the recursive function without breaking recursive dependencies. Simultaneously, it's crucial to ensure that functions with data dependencies are not optimized in the same region to avoid interference from shared data in the optimization process.
[0129] It should be noted that, in order to avoid the explosion of parallel tasks, the recursion depth also needs to be appropriately limited.
[0130] In addition, the parallel optimization of the function at the target location by the compiler in this embodiment is to convert the function from serial code to parallel code during the compilation stage so that it can be executed in parallel code later, rather than performing code conversion on the original source code, so as not to change the original source code.
[0131] This embodiment focuses on task optimization of recursive functions. When the recursive function at the target position has not completed task optimization, it performs task parallel optimization with limited depth, which effectively improves the benefits of parallel optimization.
[0132] In one embodiment, after step 103, the following may be included:
[0133] If the parallel-optimized source code meets the verification conditions, then prune the parallel-optimized source code.
[0134] If the parallel-optimized source code does not meet the verification pass conditions, the parallel-optimized source code is retried for verification and / or rolled back for modification until the parallel-optimized source code meets the verification pass conditions, and then the parallel-optimized source code is pruned.
[0135] The verification is successful if the parallel-optimized source code compiles successfully, runs correctly, and its running speed is improved.
[0136] This involves performing closed-loop verification on the parallel-optimized source code to check whether the compilation result is successful, the running result is correct, and whether a real performance acceleration has been achieved. If the verification passes, the parallel optimization result is retained, and a pruning strategy is executed to avoid invalid nested parallelism in the source code and reduce computational resource consumption. If the verification fails, the code is rolled back and modified before retrying verification, or the code is retried with error messages. If the retry fails, the code is rolled back and modified before retrying verification again, until the verification passes, the parallel optimization result is retained, and the pruning strategy is executed. This closed-loop verification continues until all non-recursive functions have completed loop optimization and all recursive functions have completed task optimization.
[0137] This embodiment performs closed-loop verification, verification retries, rollback modifications, and pruning on the optimized source code, resulting in the final optimized source code with the best acceleration performance.
[0138] Reference Figure 5 In one embodiment, the overall process of the parallel optimization method of this application is briefly described using a warehouse-level parallel optimization multi-agent cooperation framework:
[0139] This multi-agent collaboration framework can include three specialized agents: a global dependency analysis agent, a global performance analysis agent, and an OpenMP instruction addition agent.
[0140] in:
[0141] The global dependency analysis agent is the cornerstone of safe parallelization. It takes the original code repository as input, combines Uftrace and Clang to obtain the call relationship graph and data dependency relationships between functions in the source code of the code repository, marks the data dependency relationships in the call relationship graph, and obtains the global dependency graph. Using this global dependency graph as the graph structure to carry global navigation information can ensure that subsequent parallelization modifications do not violate the safety constraint information of the source code.
[0142] It's important to note that the core functionality of Uftrace and Clang is to parse function call relationships and data dependencies. These functions can be replaced by other tools with equivalent capabilities. For example, other source-to-source converters (such as Cetus and ROSE) or dedicated static / dynamic code analysis tools (such as the profiling module of DiscoPoP (Discovery of Potential Parallelism)) can be used to collect function call chains, dependencies, and performance profiling data, as long as they can provide the necessary static structural information and dynamic performance data for building global navigation.
[0143] The global performance analysis agent acts as a "navigator." It receives the global dependency graph generated by the global dependency analysis agent and, combined with Uftrace and Clang, obtains global performance data, namely the execution time and call frequency of each function, as well as the execution time of loop structures (e.g., for loops) within each function. By labeling this precise performance data with the corresponding function positions in the global dependency graph and comparing it with corresponding thresholds, it can identify computationally hotspots with high computational density that are worth optimizing, thus completing the construction of the global navigation graph.
[0144] The OpenMP instruction-added agent is the final optimization executor. Using a complete global navigation graph as the sole decision blueprint, it adds OpenMP instructions to computationally hot locations in the source code, resulting in parallel-optimized source code. This OpenMP instruction guides the compiler to execute macroscopic, repository-level OpenMP parallelization strategies, supplemented by rigorous iterative verification and correction loops.
[0145] Through the efficient collaboration of these three intelligent agents, the original serial code in a code repository can be efficiently and safely converted into parallel optimized source code.
[0146] Reference Figures 6 to 7 In one embodiment, the workflow of each agent in the parallel optimization method of this application is briefly described:
[0147] Reference Figure 6 :
[0148] The global dependency analysis agent locates / creates `main.c`, which calls multiple functions in the source code within the code repository. It then branches into two parts: First, it uses GCC-O0 to convert the source code into an executable file, and then uses Uftrace to trace the execution process of the executable, thereby tracing the entry and exit nodes of each function and generating a precise call graph. Second, it uses Clang to generate an LLVM IR of the source code from `main.c`, including memory and variable input / output logs, function and loop information, and variable information. It obtains the input and output variables of each function and checks the data dependencies between functions. If any of the following data dependencies—RAW, WAR, or WAW—are identified, the data dependency between functions is determined to be dependent; otherwise, it is determined to be independent. The results are summarized to obtain the complete data dependency graph, which is then marked on the call graph to obtain the global dependency graph.
[0149] The global performance analysis agent utilizes the aforementioned Uftrace to trace the entry and exit nodes of each function and the aforementioned intermediate representation LLVM IR to obtain performance data for each function and its internal loop structure. For functions, Uftrace is used to dynamically instrument the entry and exit nodes of each function, thereby timing the execution time and counting the number of calls to each function, thus obtaining the execution time and call frequency of each function. For loop structures, such as for loop structures, the boundaries of the loop structure within each function in the intermediate representation LLVM IR are identified, namely the start and end nodes of the loop structure. After creating a copy of the source code, dynamic instrumentation is performed on the start and end nodes of the loop structure within each function in the copy, thereby timing the execution time of the loop structure within each function, thus obtaining the execution time of the loop structure within each function. The execution time and call frequency of each function, as well as the execution time of the loop structure within each function, are marked as performance data on the global dependency graph to generate a global navigation graph.
[0150] Reference Figure 7 :
[0151] The OpenMP instruction-based agent is driven by the global navigation graph. OpenMP instructions are added to the source code to guide the compiler to execute two optimization branches. The first branch optimizes for loops, checking for non-recursive functions whose execution time exceeds a threshold (e.g., 50 microseconds) or whose call frequency exceeds a threshold, and which have not completed loop optimization. If so, the non-recursive function and its internal for loop structure exceeding the threshold (e.g., 50 microseconds) are optimized sequentially according to the call hierarchy from high to low. Simultaneously, it ensures that functions with data dependencies are not optimized in the same region. Afterwards, a closed-loop verification step is performed: checking whether the compilation result of the parallel-optimized source code is successful, whether the running result is correct, and whether a real performance acceleration has been achieved. If the verification passes (i.e., the compilation result of the parallel-optimized source code is successful, the running result is correct, and a real performance acceleration has been achieved), the parallel optimization result is retained, and a pruning strategy is executed to avoid... Invalid nested parallelism in the source code reduces computational resource consumption. If verification fails, it retryes with an error message. If the retry passes, the parallel optimization results are retained, and a pruning strategy is executed. If the retry fails, it checks if the rollback count has reached a threshold. If not, it rolls back to the entry point of the first optimization branch to correct the error message and facilitate subsequent verification retries. If the threshold is reached, it returns directly to the entry point of the first optimization branch to perform parallel optimization for the next opportunity, until all non-recursive functions complete the for loop optimization. The second optimization branch is task optimization. After checking if there are any non-recursive functions whose execution time exceeds the threshold (e.g., 50 microseconds) or whose call frequency exceeds the threshold and have not completed loop optimization, if none are found, it further checks if there are any recursive functions whose execution time exceeds the threshold (e.g., 50 microseconds) or whose call frequency exceeds the threshold and have not completed task optimization. If none are found, parallel optimization ends; otherwise, it uses an if statement to resolve the issue. The clause sets a threshold for the number of tasks generated to limit the depth of task optimization for the recursive function, while ensuring that functions with data dependencies are not optimized in parallel in the same region; then the above closed-loop verification steps are reused until all recursive functions have completed task optimization.
[0152] It should be noted that this embodiment uses a multi-agent collaborative framework to construct the global navigation graph and execute specific parallel instruction addition operations. However, the role of this execution engine can also be replaced by other technologies. For example, a pre-trained model with powerful code understanding and generation capabilities, fine-tuned on a specialized dataset, such as HPC-Coder-v2 (High Performance Computing-Coder version 2), or a sophisticated rule-based reasoning engine can be used to undertake this task. Regardless of the execution engine used, its core function remains the same: to systematically and safely insert parallel instructions into the code based solely on the global navigation graph.
[0153] In this embodiment, the global dependency analysis agent generates a global dependency graph that deeply integrates the static structure and dynamic behavior of the source code. This fundamentally overcomes the limitation of existing technologies that are limited to isolated function-level optimization and avoids the risk of data competition due to optimization conflicts caused by information fragmentation.
[0154] Furthermore, this embodiment establishes a data-driven computational hotspot localization strategy for the global performance analysis agent and introduces a parallelization cost-benefit evaluation model, realizing a shift from "blind optimization" to "precision guidance." This strategy, by quantitatively evaluating the expected benefits and inherent overhead of parallelization (e.g., filtering code segments with a single execution time exceeding 50 microseconds based on empirical rules), precisely focuses optimization resources on high-value computational regions, thereby avoiding performance degradation caused by ineffective parallelization and improving the efficiency and success rate of automated optimization.
[0155] Furthermore, this embodiment adds an agent to the OpenMP instruction with complete global navigation as its guide, integrating loop-level parallelization and task-level parallelization strategies, supplemented by rigorous iterative verification and loop correction. This mechanism strictly follows the global data flow and constraints within the code repository when adding OpenMP instructions. This method of elevating security verification from local code to the repository system level ensures the logical correctness of parallelization modifications from a mechanistic perspective, eliminating the risk of introducing data races and thus ensuring the absolute safety of parallel optimization. Simultaneously, by integrating loop-level and task-level parallelization strategies, it can correctly capture all optimization opportunities and skip all optimization risks (such as complex dependencies or high parallelization costs), improving the quality of parallel code from "usable" to "efficient." In particular, it implements task optimization for irregular recursive and branching structures, using if clauses to set a threshold for the number of tasks generated to limit depth, balancing task scheduling overhead with actual parallel benefits. In a real-world application scenario, when all existing methods, such as AutoPar (Automatic Parallelization), GitHub Copilot, and Codex, failed to optimize a computationally intensive function in the OpenCV (Open Source Computer Vision) library, this embodiment accurately identified and optimized the critical loop through global analysis, achieving a speedup of 22.273 times, demonstrating its robustness in complex real-world scenarios.
[0156] In practice, this embodiment delivers performance and hardware platform adaptability that surpass those of human experts. Experiments on representative repository-level datasets NPB (NAS Parallel Benchmarks, NASA Ames Research Center's parallel benchmark set) and BOTS (Barcelona OpenMP Task Suite) demonstrate an average speedup of 14.2x compared to rule-based tools, 3.20x compared to state-of-the-art code agents, and even 1.21x faster than human experts in challenging cases. This is attributed to its systematic global analysis capabilities, which capture deep cross-module optimization opportunities that human experts might miss due to limited perspective when dealing with large and complex code repositories. Furthermore, the global performance analysis agent makes data-driven decisions, accurately identifying hardware-specific bottlenecks and addressing performance degradation issues that might occur with empirical methods on different hardware architectures, such as Intel and AMD platforms. Moreover, the parallel optimization in this embodiment has a synergistic effect with compiler optimizations (e.g., GCC-O3, with the highest level of optimization enabled), enabling the discovery of thread-level parallel potential across complex function call chains that compiler optimizations cannot detect from a global perspective.
[0157] Figure 8 This is a schematic diagram of the structure of the electronic device provided in the embodiments of this application, such as... Figure 8 As shown, the electronic device may include: a processor 810, a communication interface 820, a memory 830, and a communication bus 840, wherein the processor 810, the communication interface 820, and the memory 830 communicate with each other via the communication bus 840. The processor 810 can call computer programs stored in the memory 830 to execute steps of a repository-level code parallel optimization method, such as including:
[0158] Obtain the global dependency graph of the source code within the code repository; the global dependency graph includes the call relationships and data dependencies between multiple functions in the source code;
[0159] The performance data of each function is marked in the global dependency graph to obtain the global navigation graph;
[0160] Based on the global navigation graph, parallelization instructions are added to the target location of the source code to obtain the parallel optimized source code; the target location is the function location where the performance data exceeds a threshold.
[0161] Furthermore, the logical instructions in the aforementioned memory 830 can be implemented as software functional units and, when sold or used as independent products, can be stored in a computer-readable storage medium. Based on this understanding, the technical solution of this application, in essence, or the part that contributes to the prior art, or a part of the technical solution, can be embodied in the form of a software product. This computer software product is stored in a storage medium and includes several instructions to cause a computer device (which may be a personal computer, server, or network device, etc.) to execute all or part of the steps of the methods described in the various embodiments of this application. The aforementioned storage medium includes various media capable of storing program code, such as USB flash drives, portable hard drives, read-only memory (ROM), random access memory (RAM), magnetic disks, or optical disks.
[0162] On the other hand, embodiments of this application also provide a computer program product, which includes a computer program that can be stored on a non-transitory computer-readable storage medium. When the computer program is executed by a processor, the computer can perform the steps of the repository-level code parallel optimization method provided in the above embodiments, such as including:
[0163] Obtain the global dependency graph of the source code within the code repository; the global dependency graph includes the call relationships and data dependencies between multiple functions in the source code;
[0164] The performance data of each function is marked in the global dependency graph to obtain the global navigation graph;
[0165] Based on the global navigation graph, parallelization instructions are added to the target location of the source code to obtain the parallel optimized source code; the target location is the function location where the performance data exceeds a threshold.
[0166] On the other hand, embodiments of this application also provide a non-transitory computer-readable storage medium storing a computer program thereon, the computer program being used to cause a processor to execute the steps of the repository-level code parallel optimization method provided in the above embodiments, for example including:
[0167] Obtain the global dependency graph of the source code within the code repository; the global dependency graph includes the call relationships and data dependencies between multiple functions in the source code;
[0168] The performance data of each function is marked in the global dependency graph to obtain the global navigation graph;
[0169] Based on the global navigation graph, parallelization instructions are added to the target location of the source code to obtain the parallel optimized source code; the target location is the function location where the performance data exceeds a threshold.
[0170] The non-transitory computer-readable storage medium can be any available medium or data storage device that the processor can access, including but not limited to magnetic memory (e.g., floppy disk, hard disk, magnetic tape, magneto-optical disk (MO)), optical memory (e.g., CD, DVD, BD, HVD), and semiconductor memory (e.g., ROM, EPROM, EEPROM, non-volatile memory (NAND FLASH), solid-state drive (SSD)).
[0171] Through the above description of the embodiments, those skilled in the art can clearly understand that each embodiment can be implemented by means of software plus necessary general-purpose hardware platforms, and of course, it can also be implemented by hardware. Based on this understanding, the above technical solutions, in essence or the part that contributes to the prior art, can be embodied in the form of a software product. This computer software product can be stored in a computer-readable storage medium, such as ROM / RAM, magnetic disk, optical disk, etc., and includes several instructions to cause a computer device (which may be a personal computer, server, or network device, etc.) to execute the methods described in the various embodiments or some parts of the embodiments.
[0172] Finally, it should be noted that the above embodiments are only used to illustrate the technical solutions of this application, and are not intended to limit them. Although this application has been described in detail with reference to the foregoing embodiments, those skilled in the art should understand that modifications can still be made to the technical solutions described in the foregoing embodiments, or equivalent substitutions can be made to some of the technical features. Such modifications or substitutions do not cause the essence of the corresponding technical solutions to deviate from the spirit and scope of the technical solutions of the embodiments of this application.
Claims
1. A warehouse-level code parallelization optimization method, characterized by, include: Obtain the global dependency graph of the source code within the code repository; The global dependency graph includes the call relationships and data dependencies between multiple functions in the source code; The performance data of each function is marked in the global dependency graph to obtain the global navigation graph; Based on the global navigation graph, parallelization instructions are added to the target location of the source code to obtain parallel optimized source code; The target location is the function location where the performance data exceeds a threshold; the performance data of each function includes the execution time of each function, the call frequency of each function, and the execution time of the loop structure within each function; the target location is the function location where the execution time exceeds a first threshold and / or the call frequency of the function exceeds a second threshold; the parallelization instruction is used by the compiler to guide the compiler to perform parallel optimization on the functions at the target location when compiling the parallel optimized source code, wherein functions with data dependencies are not performed in parallel optimization in the same region; If there are multiple non-recursive functions at target locations and loop optimization has not been completed, then the non-recursive functions and their internal hot loop structures are optimized in parallel from the higher to the lower levels according to the calling hierarchy of the non-recursive functions.
2. The warehouse-level code parallelization optimization method of claim 1, wherein, The process of obtaining the global dependency graph of the source code within the code repository includes: Calling multiple functions in the source code; Obtain the call relationship graph and data dependencies between functions; The data dependencies are marked in the call relationship graph to obtain the global dependency graph.
3. The warehouse-level code parallelization optimization method of claim 2, wherein, Obtain the call relationship graph between the functions, including: Convert the source code into an executable file; Tracing the execution process of the executable file; Based on the entry and exit nodes of each function during the execution process, the calling relationship between the functions is constructed to obtain the calling relationship graph.
4. The warehouse-level code parallelization optimization method of claim 2, wherein, Obtain the data dependencies between functions, including: Generate an intermediate representation of the source code; Obtain the input and output variables of each function recorded in the intermediate representation; The data dependencies are obtained based on the input and output variables of each function.
5. The warehouse-level code parallelization optimization method of claim 3, wherein, The performance data for each function includes its execution time and call frequency. The execution time and call frequency of each function are obtained based on the following method: Based on the entry and exit nodes of each function during the execution process, the execution time of each function is timed to obtain the execution time of each function; Based on the entry and exit nodes of each function during the execution process, the number of times each function is called during the execution process is counted to obtain the calling frequency of each function.
6. The warehouse-level code parallelization optimization method of claim 4, wherein, The performance data for each function includes the execution time of the loop structure within each function, which is obtained based on the following method: Identify the boundaries of loop structures within each function in the intermediate representation; Create a copy of the source code; Based on the boundary, the execution time of the loop structure is timed in the copy to obtain the execution time of the loop structure within each function.
7. The repository-level code parallel optimization method according to claim 1, characterized in that, The parallel optimization of the function at the target position includes: If the function at the target position is not a recursive function and loop optimization has not been completed, parallel optimization is performed on the function at the target position and the loop structure within the function at the target position whose execution time exceeds the third threshold.
8. The repository-level code parallel optimization method according to claim 1, characterized in that, The parallel optimization of the function at the target position includes: If the function at the target location is a recursive function and task optimization has not been completed, a depth-limited task optimization is performed on the recursive function.
9. The warehouse-level code parallelization optimization method of claim 1, wherein, After obtaining the parallel-optimized source code, the process includes: If the parallel optimized source code does not meet the verification pass conditions, the parallel optimized source code is retried for verification and / or rolled back for modification until the parallel optimized source code meets the verification pass conditions, and the parallel optimized source code is pruned. The verification is successful if the compilation result of the parallel optimized source code is successful, the running result is correct, and the running speed is improved.
10. The warehouse-level code parallelization optimization method of claim 1, wherein, After obtaining the parallel-optimized source code, the process includes: If the parallel optimized source code meets the verification pass conditions, the parallel optimized source code is pruned. The verification is successful if the compilation result of the parallel optimized source code is successful, the running result is correct, and the running speed is improved.