Program compiling method, computing device, storage medium and computer program product

CN122733293APending Publication Date: 2026-09-11PHYTIUM TECH CO LTD
View PDF 0 Cites 0 Cited by

Patent Information

Application Number
CN202610703996.5
Authority / Receiving Office
CN · China
Patent Type
Applications(China)
Current Assignee / Owner
Filing Date
2026-05-20
Publication Date
2026-09-11

AI Technical Summary

Technical Problem

[0004]当出现缓存未命中时,若程序的后续执行依赖于数据访问结果,在数据被下一级存储返回之前,处理器(或其他访问主体)会被迫处于停顿等待数据的状态,造成处理器资源的浪费

Benefits of technology

[0010] As can be seen from the above technical solution, the program compilation method provided in the embodiments of this specification optimizes the parallel program structure in the target program, enabling the target program to perform multiple iterations of the parallel program structure based on multiple coroutines during execution. Specifically, before a coroutine executes a target instruction for which a cache miss is expected during an iteration, it first performs the steps of saving the current coroutine's context state and initiating a prefetch operation for the data corresponding to the target instruction. Then, it switches to the next runnable coroutine. When the coroutine is run again, it can restore its context based on the previously saved context state and continue executing the target instruction. In this way, the processor can utilize multiple coroutines to execute multiple iterations of the parallel program structure. During the execution of multiple iterations, while waiting for the data prefetch operation initiated by one coroutine to complete, multiple coroutines can switch to another coroutine to execute other iterations, thereby effectively utilizing idle cycles that would otherwise be wasted and achieving instruction-level parallelism and overall resource utilization efficiency. In addition, each coroutine saves and restores its context through an independent management structure, achieving extremely low-overhead context switching, which greatly reduces the resource overhead compared to thread switching.

✦ Generated by Eureka AI based on patent content.

Smart Images

  • Figure CN122733293A_ABST
    Figure CN122733293A_ABST
Patent Text Reader

Abstract

The compilation method provided in this specification optimizes the parallel program structure of the target program. The compiler-generated target code creates multiple coroutines to execute iteratively in an alternating loop. Before a cache miss is expected, the inserted switching code saves the current coroutine's context state and initiates data prefetching, then switches to the next runnable coroutine. When the coroutine resumes, the recovery code continues execution of the target instruction based on its context state. Thus, while one coroutine is waiting for data prefetching, the processor can switch to execute other coroutines, fully utilizing previously idle cycles to achieve instruction-level parallelism and improve resource utilization. Coroutines save and restore their context through an independent management structure, resulting in extremely low context switching overhead. Furthermore, this method is optimized during the compilation phase, requiring no intervention from the original developer of the target program, and is therefore universally applicable.
Need to check novelty before this filing date? Find Prior Art

Description

Technical Field

[0001] This specification relates to the field of computer application technology, specifically to program compilation technology in the field of computer application technology, and more specifically to a program compilation method, computing device, storage medium, and computer program product. Background Technology

[0002] A cache is a temporary storage area designed in computer architecture, storage systems, and software architecture to reduce data / instruction access latency and improve system throughput. A cache can store copies of frequently accessed, recently accessed, or highly likely to be accessed data / instructions, allowing subsequent accesses to retrieve them directly from the cache without having to navigate through slow storage, thereby improving access efficiency.

[0003] A cache miss occurs when a data / instruction access request is made by a user (e.g., a processor) but the target data is not stored in the cache (e.g., L1, L2, or L3 cache), forcing the user to read the data from the next level of storage (e.g., main memory DRAM, disk, or even network storage), which is slower and has higher latency.

[0004] When a cache miss occurs, if the subsequent execution of the program depends on the data access result, the processor (or other access subject) will be forced to pause and wait for the data before the data is returned from the next level of storage, resulting in a waste of processor resources. Summary of the Invention

[0005] This specification provides a program compilation method, computing device, storage medium, and computer program product to improve program execution efficiency and avoid resource waste caused by processor pauses due to cache misses.

[0006] To achieve the above technical objectives, the embodiments of this specification provide the following technical solutions: Firstly, one embodiment of this specification provides a program compilation method, including: The target program is compiled to obtain target code; the target code is used to implement the loop process when executed: The loop process includes: creating multiple coroutines for the thread executing the parallel program structure, each coroutine having a corresponding management structure for storing the state of the coroutine; and alternately executing multiple iterations of the parallel program structure through the multiple coroutines, wherein, for a target instruction, the target code includes switching code and recovery code for the target instruction; the target instruction is an instruction for which a cache miss is expected. The switching code is used to save the current state of the coroutine in the management structure, initiate a prefetch operation of the data corresponding to the target instruction, and switch to run the next runnable coroutine before executing the target instruction; the recovery code is used to restore the state based on the current state when the coroutine is run again, so as to continue executing the target instruction.

[0007] Secondly, one embodiment of this specification also provides a computing device, including a memory, a processor, and a computer program stored in the memory and executable on the processor, wherein the processor executes the computer program to implement the program compilation method described above.

[0008] Thirdly, one embodiment of this specification also provides a computer-readable storage medium storing a computer program that, when executed by a processor, implements the program compilation method described above.

[0009] Fourthly, embodiments of this specification provide a computer program product or a computer program, the computer program product including a computer program stored in a computer-readable storage medium; the processor of the computer device reads the computer program from the computer-readable storage medium, and when the processor executes the computer program, it implements the steps of the above-described program compilation method. Optionally, the computer program may be stored in a computer-readable storage medium or in the cloud; the processor of the computer device reads the computer program from the readable storage medium or in the cloud.

[0010] As can be seen from the above technical solution, the program compilation method provided in the embodiments of this specification optimizes the parallel program structure in the target program, enabling the target program to perform multiple iterations of the parallel program structure based on multiple coroutines during execution. Specifically, before a coroutine executes a target instruction for which a cache miss is expected during an iteration, it first performs the steps of saving the current coroutine's context state and initiating a prefetch operation for the data corresponding to the target instruction. Then, it switches to the next runnable coroutine. When the coroutine is run again, it can restore its context based on the previously saved context state and continue executing the target instruction. In this way, the processor can utilize multiple coroutines to execute multiple iterations of the parallel program structure. During the execution of multiple iterations, while waiting for the data prefetch operation initiated by one coroutine to complete, multiple coroutines can switch to another coroutine to execute other iterations, thereby effectively utilizing idle cycles that would otherwise be wasted and achieving instruction-level parallelism and overall resource utilization efficiency. In addition, each coroutine saves and restores its context through an independent management structure, achieving extremely low-overhead context switching, which greatly reduces the resource overhead compared to thread switching.

[0011] Furthermore, in one embodiment, the program compilation method of this solution can achieve the above-mentioned optimization of the target program during the compilation and runtime phases (i.e., in this specification, compilation can refer to compilation in a broad sense, which can cover the program compilation phase and the dynamic modification and recompilation of code during the runtime phase), without requiring program developers to perform targeted optimizations for individual programs during the development process of the target program, thus having high universality. For example, a management structure corresponding to the coroutine can be created during the compilation phase, the target program can be executed based on a single thread, the target instructions can be determined through perf or other methods during the runtime phase, and then optimizations for the target instructions can be achieved by dynamically modifying the code or recompiling, thereby achieving the purpose of data prefetching and switching between multiple coroutines when the expected cache miss occurs.

[0012] Furthermore, the program compilation method can be implemented based on the compiler, which can utilize the compiler to automatically insert a mechanism that supports coroutines. It can also support the insertion of instructions for saving the context, coroutine switching, and context restoration at the location where a cache miss is expected. After obtaining the target code, the processor can directly execute it without the processor having to perform operations such as determining the target instructions in real time during program execution, which helps to reduce the resource overhead of the processor running the target code. Attached Figure Description

[0013] To more clearly illustrate the technical solutions in the embodiments or prior art of this specification, the drawings used in the description of the embodiments or prior art will be briefly introduced below. Obviously, the drawings described below are only embodiments of this specification. For those skilled in the art, other drawings can be obtained based on the provided drawings without creative effort.

[0014] Figure 1 This is a flowchart illustrating a program compilation method provided for one embodiment of this specification.

[0015] Figure 2 This is a schematic diagram of a coroutine management structure provided for one embodiment of this specification.

[0016] Figure 3 This diagram illustrates a loop leading code, coroutine working code, custom loop code, and loop ending code, as provided in one embodiment of this specification.

[0017] Figure 4 This diagram illustrates, as one embodiment of the present specification, the insertion of specific switching and recovery code into the generated code for each identified target instruction (i.e., an instruction expected to result in a cache miss).

[0018] Figure 5This diagram illustrates two implementation paths of the compilation method provided in one embodiment of this specification.

[0019] Figure 6 This is a schematic diagram of the structure of a computing device provided for one embodiment of this specification. Detailed Implementation

[0020] Unless otherwise defined, the technical or scientific terms used in the embodiments of this specification shall have the ordinary meaning understood by one of ordinary skill in the art to which this specification pertains. The terms "first," "second," and similar terms used in the embodiments of this specification do not indicate any order, quantity, or importance, but are merely used to avoid confusion of constituent elements.

[0021] Unless the context otherwise requires, throughout this specification, "a plurality of" means "at least two," and "including" is interpreted as open-ended or encompassing, that is, "including, but not limited to." In the description of this specification, terms such as "one embodiment," "some embodiments," "exemplary embodiment," "example," "specific example," or "some examples" are intended to indicate that a particular feature, structure, material, or characteristic associated with that embodiment or example is included in at least one embodiment or example of this specification. The illustrative representations of the above terms do not necessarily refer to the same embodiment or example.

[0022] The technical solutions in the embodiments of this specification will be clearly and completely described below with reference to the accompanying drawings. Obviously, the described embodiments are only some embodiments of this specification, and not all embodiments. Based on the embodiments in this specification, all other embodiments obtained by those skilled in the art without creative effort are within the scope of protection of this specification.

[0023] Overview As described in the background section, the emergence of caching systems has greatly improved the data access efficiency of processors. Based on the principle of locality, caches can temporarily store frequently accessed data, thereby reducing the number of accesses to slow backend storage and computing resources, and improving the overall system response speed and throughput.

[0024] When a memory access instruction of the accessing entity (described below using the processor as an example) encounters a cache miss, the processor is forced to access the higher-latency back-end memory. If subsequent program execution depends on the data access result, the processor will be forced to pause and wait for the data until the back-end memory returns it, resulting in a waste of processor computing resources. Furthermore, even if the subsequent instructions of the memory access instruction do not depend on the result of this memory access instruction, the fact that this memory access instruction cannot complete in a timely manner will prevent the subsequent instructions from completing, consuming the processor's internal hardware resources. The processor may also be forced to pause and wait for the memory access instruction to complete due to the exhaustion of internal resources.

[0025] Further research revealed that traditional task-level parallelism schemes are unsuitable for solving the aforementioned problems. Specifically, task-level parallelism schemes utilize operating system threads as parallel execution units to exploit and leverage parallelism within programs. However, thread switching incurs significant overhead, primarily because it must be performed through the operating system kernel (privileged mode). This design, based on considerations of system security and isolation, introduces additional mode-switching overhead. Specifically, the thread switching process involves transitioning from user mode to kernel mode, complex scheduling decisions by the kernel's general-purpose scheduler (which must consider universal goals such as fairness, responsiveness, and priority for all processes and threads), and saving and restoring the complete thread context (including register and memory mapping states). These factors collectively make thread switching a relatively heavyweight operation.

[0026] Typically, the overhead of a single thread context switch is on the order of 1 to 2 microseconds (i.e., 1000 to 2000 nanoseconds). This time is significantly longer than the execution latency of many common instructions, and far exceeds the memory access pause time caused by cache misses (approximately 110 nanoseconds) mentioned earlier. Therefore, strategies that rely on operating system threads for task switching are ineffective in addressing the above problems due to their inherently high overhead.

[0027] Therefore, to address this issue, this specification aims to provide a solution with sufficient instruction flow parallelism. Specifically, after the target program is developed, dynamic compiler optimization techniques such as PGO (Profile-Guided Optimization) can be used to first identify target instructions (which may be memory access instructions) in the target program's parallel program structure that are expected to generate long latency (i.e., cache misses). Then, the parallel program structure is optimized, and multiple iterations of the parallel program structure are executed alternately by multiple coroutines. For the target instruction, switching code and recovery code can be inserted. The switching code is used to save the current coroutine's context state in the management structure, initiate a prefetch operation of the data corresponding to the target instruction, and switch to run the next runnable coroutine before executing the target instruction. The recovery code is used to restore the context state based on the context state when the coroutine is run again, so as to continue executing the target instruction. Thus, before a coroutine reaches the target instruction where a cache miss is expected during an iteration, it first saves the current coroutine's context state, initiates a prefetch operation for the data corresponding to the target instruction, and then switches to the next runnable coroutine. When the coroutine is run again, it can restore its context based on the previously saved context state and continue executing the target instruction. This allows the processor to utilize multiple coroutines to execute multiple iterations of a parallel program structure. During the execution of multiple iterations, while waiting for the data prefetch operation initiated by one coroutine to complete, multiple coroutines can switch to another coroutine to execute other iterations, effectively utilizing idle cycles that would otherwise be wasted, achieving instruction-level parallelism and overall resource utilization efficiency. Furthermore, each coroutine saves and restores its context through an independent management structure, achieving extremely low-overhead context switching, significantly reducing the resource overhead compared to thread switching.

[0028] Furthermore, the program compilation method in this scheme achieves the aforementioned optimizations of the target program during compilation, eliminating the need for program developers to perform specific optimizations for each individual program during development, thus exhibiting high versatility. Moreover, the program compilation method can be implemented based on a compiler, leveraging the compiler's automatic insertion of coroutine support mechanisms and supporting the insertion of instructions for saving the current state, coroutine switching, and restoring the current state at anticipated cache miss locations. After obtaining the target code, the processor can directly execute it without requiring the processor to determine target instructions in real-time during program runtime, thereby reducing processor resource overhead.

[0029] Based on the above concept, this specification provides a program compilation method. The program compilation method provided by this specification will be described exemplarily below with reference to the accompanying drawings.

[0030] Before introducing the compilation method of this program, let's briefly explain the technical terms that may be involved in this manual: A thread is the smallest unit of computation that an operating system can schedule. It is contained within a process and is the actual unit of operation within the process. A process can contain multiple threads, which share the process's resources (such as memory space and file handles) but have their own independent execution flow and stack space.

[0031] A coroutine is a more lightweight user-mode execution entity than a thread. Coroutine scheduling is controlled by the program, not the operating system kernel. It has its own execution context and stack, but when it voluntarily yields execution, it saves its current state for later restoration.

[0032] The context (or execution context) refers to the complete state information of an execution entity (such as a thread or coroutine) at a particular moment, which may include the program counter, register contents, stack pointer, etc. Saving and restoring the context is the foundation for implementing execution entity switching.

[0033] A parallel program structure can refer to a control flow structure in a program that repeatedly executes a segment of code, and may include at least one of initialization, conditional judgment, loop body, and iterative update parts. In some implementations, a parallel program structure may include a loop structure that iterates multiple times.

[0034] Iteration refers to the process of a single execution in a parallel program structure.

[0035] Prefetching is a memory access optimization technique that refers to loading data from slow storage (such as main memory) into a cache in advance before the data is actually needed, in order to hide memory access latency.

[0036] Memory access can refer to the processor executing load or store instructions to read or write data from the memory subsystem (cache or main memory).

[0037] Compilation can refer to the process of converting source code written in a high-level programming language into machine code or intermediate code that can be executed by a computer.

[0038] PGO is a compiler optimization technique that can be executed in two steps: first, a binary version of the program is compiled and run to collect performance data under typical workloads; then, the compiler uses this data (profile file) to perform a second compilation and make more targeted optimization decisions.

[0039] LLVM (Low Level Virtual Machine) is a framework system for architecture compilers. It adopts a modular design and includes a series of reusable compiler and toolchain technologies.

[0040] OpenMP is a commonly used mechanism for declaring data that can be processed in parallel. Program developers can declare parallel regions by adding compiler directives.

[0041] Exemplary methods This specification provides a program compilation method, such as... Figure 1 As shown, it includes: S101: Compile the target program to obtain target code; the target code is used to implement the loop process when executed: The cyclic process includes: S1011: Multiple coroutines are created for the thread executing the parallel program structure. Each coroutine has a corresponding management structure, which is used to store the context state of the coroutine. Multiple iterations of the parallel program structure are executed alternately through the multiple coroutines. For the target instruction, the target code includes switching code and recovery code for the target instruction. The target instruction is the instruction for which a cache miss is expected. S1012: The switching code is used to save the current state of the coroutine in the management structure, initiate a prefetch operation of the data corresponding to the target instruction, and switch to run the next runnable coroutine before executing the target instruction; the recovery code is used to restore the context based on the current state when the coroutine is run again, so as to continue executing the target instruction. The multiple iterations of the parallel program structure executed alternately by multiple coroutines can refer to the following: during any iteration of a coroutine, when the target instruction is encountered, the current iteration can be paused and switched to another iteration executed by another coroutine, thereby achieving interleaved and parallel iteration execution.

[0042] In some implementations, for dynamic compilation scenarios, the code corresponding to the loop process can be generated during the first compilation, and the target instructions can be replaced with the code corresponding to the loop process. In this scenario, the compiler generates the complete code corresponding to the loop process and directly replaces the target instructions with this complete code.

[0043] In static compilation scenarios, the traditional form of the target instructions can be preserved during the first compilation, and then the code based on multi-coroutine execution can be generated during the second compilation (PGO).

[0044] In one implementation, techniques such as PGO can be used to analyze the target program to obtain relevant performance data, and the target instruction in the parallel program structure of the target program can be determined based on the performance data. In another implementation, for a system that supports querying cache existence, the cache existence of the data targeted by the memory access instruction can be queried first. If it is found that it is not in the cache, the memory access instruction can be determined as the target instruction.

[0045] In one implementation, the region where data can be processed in parallel (usually the region where the parallel program structure is located) can be determined by the OpenMP mechanism. Alternatively, other mechanisms that declare parallel processing capability can be used to determine the parallel program structure, such as the Parellel for interface provided by Intel OneAPI. This specification will not exhaustively list them all; the specific method depends on the actual situation.

[0046] In the program compilation method described above, the target program can be a program developed by developers and possessing one or more specific functions. During the development of the target program, developers do not need to perform specific optimizations to address processor pauses caused by cache misses of target instructions. After the target program is developed, the program compilation method provided in this specification can be used for unified optimization to solve the aforementioned problems.

[0047] Specifically, in this embodiment, the program compilation method optimizes the parallel program structure in the target program, enabling the target program to perform multiple iterations of the parallel program structure alternately based on multiple coroutines during execution. Specifically, before a coroutine executes a target instruction for which a cache miss is expected during an iteration, it first performs the steps of saving the current coroutine's context state and initiating a prefetch operation for the data corresponding to the target instruction. Then, it switches to the next runnable coroutine. When the coroutine is run again, it can restore its context based on the previously saved context state and continue executing the target instruction. In this way, the processor can utilize multiple coroutines to execute multiple iterations of the parallel program structure. During the execution of multiple iterations, while waiting for the data prefetch operation initiated by one coroutine to complete, multiple coroutines can switch to another coroutine to execute other iterations, thereby effectively utilizing idle cycles that would otherwise be wasted, achieving instruction-level parallelism and overall resource utilization efficiency. In addition, each coroutine saves and restores its context through an independent management structure, achieving extremely low-overhead context switching, which greatly reduces the resource overhead compared to thread switching.

[0048] Furthermore, the program compilation method of this solution achieves the aforementioned optimizations of the target program during the compilation process, eliminating the need for program developers to perform targeted optimizations for individual programs during the development of the target program, thus possessing high versatility. Moreover, the program compilation method can be implemented based on a compiler, and the program compilation method provided in the embodiments of this specification can be implemented using the compiler's automatic insertion mechanism that supports coroutines.

[0049] In one implementation, creating multiple coroutines for the threads executing the parallel program structure includes: Determine the scheduling coroutine and multiple worker coroutines among the multiple coroutines; The scheduling coroutine is used to allocate the iteration to the idle working coroutine according to the index variable of the parallel program structure during runtime; the index variable corresponds to the iteration. The worker coroutine is used to execute the assigned iteration at runtime.

[0050] In this implementation, multiple coroutines are divided into scheduling coroutines and multiple worker coroutines. A dedicated scheduling coroutine is responsible for dynamically allocating iterations to worker coroutines based on a loop index variable. This centralizes and reuses task scheduling logic, avoiding the embedding of complex allocation logic in each worker coroutine or during each switch. Worker coroutines can thus maintain a simple structure and focus on executing their assigned iterative computations. This not only reduces the code complexity and state management overhead of individual coroutines but also makes switching between coroutines more efficient.

[0051] In one implementation, the management structure further includes: a running state, which is used to characterize at least one of runnable coroutines and currently running coroutines; The switching to run the next runnable coroutine includes: Based on the running status, determine whether there is an idle working coroutine. If there is an idle working coroutine, determine the next runnable coroutine as the scheduling coroutine; if there is no idle working coroutine, determine the next runnable coroutine as the runnable working coroutine.

[0052] In this implementation, a currently running coroutine can refer to a coroutine that actually occupies a processor core and whose instructions are being executed. A runnable coroutine can refer to a coroutine that is ready to run once selected by the scheduler.

[0053] By storing the running state in the management structure, each coroutine can determine which coroutines are runnable and / or currently running based on that running state. This allows decisions to be made based on the running state during coroutine switching, avoiding the overhead of obtaining the running state through traversal or complex inference. This reduces the decision complexity and time overhead of coroutine scheduling itself, making the switching process more efficient.

[0054] Furthermore, this implementation specifies a concrete coroutine switching strategy. When there are idle worker coroutines, they can be scheduled to the scheduling coroutine, allowing the scheduling coroutine to attempt to allocate new iterations to the idle worker coroutines. This significantly reduces the idle waiting time of worker coroutines, improving resource reuse and overall task execution efficiency. When all worker coroutines are busy, switching can be performed directly between runnable worker coroutines, allowing the runnable worker coroutines to continue executing their assigned iterations. This avoids the ineffective scheduling overhead of switching to the scheduling coroutine when there are no idle worker coroutines, ensuring program efficiency and smooth workflow.

[0055] In one implementation, compiling the target program includes: Based on the target program, an initial intermediate representation corresponding to the target program is obtained; Based on the initial intermediate representation corresponding to the parallel program structure in the target program, an optimized intermediate representation corresponding to the loop process is generated. The optimized intermediate representation includes a calling function, which is used to call the switching code and the recovery code. The compiler backend generates the target code based on the optimized intermediate representation.

[0056] The compilation process can be divided into three stages: intermediate code generation, pass optimization, and binary code generation. In the intermediate code generation stage, the compiler converts the source code into a hardware-independent intermediate representation (IR). In the pass optimization stage, the compiler optimizes the intermediate representation, such as removing unnecessary code, simplifying calculations, and optimizing loops. In the binary code generation stage, the compiler converts the optimized intermediate representation into machine instructions specific to the architecture. During this process, the compiler backend handles core tasks such as instruction selection, instruction scheduling, and register allocation. Specifically, in register allocation, the compiler backend determines how to map the vast number of virtual registers (which can hold program variables) to the very limited number of physical registers in the processor. The goal is to keep as many variables as possible in fast-access registers while satisfying instruction semantics, reducing data interaction with slow memory and thus significantly improving program efficiency.

[0057] This implementation provides a method for performing the compilation process during the intermediate code generation stage. This embodiment provides a feasible method for compiling a target program. Specifically, the compilation process can be implemented during the intermediate code generation stage. As mentioned earlier, in this stage, since physical registers have not yet been allocated, the issue of saving and restoring the execution context does not need to be considered. Thus, when the compiler allocates physical registers, it can generate relevant register saving and restoring instructions. In this embodiment, the compilation process of the target program does not need to consider the issue of saving and restoring the execution context, making the overall execution logic of the program compilation method simpler.

[0058] In one implementation, compiling the target program includes: The compiler performs a compilation process based on the target program to generate a source program in binary code form; the compilation process includes issuing intermediate representations and allocating registers; The parallel program structure portion of the source program is reconstructed to obtain optimized code corresponding to the loop process; The target code is generated based on the optimized code and the source program.

[0059] Emitting intermediate representations refers to the process by which the compiler transforms the abstract syntax tree or other intermediate forms and generates a specific intermediate representation (IR). Essentially, it's the operation of outputting high-level semantic structures as code or data structures in a specific format. Register allocation is the process of appropriately mapping variables or temporary values ​​used in the program's intermediate representation to the processor's physical registers.

[0060] In this embodiment, a compilation process implemented during the binary code generation stage is provided. Reconstruction is performed at the binary code level, which enables precise optimization based on a completely deterministic machine state. This is particularly beneficial for generating minimal register save / restore code, further reducing save-switching overhead.

[0061] For example, in one implementation, the current state of the coroutine includes the values ​​of registers that are active when the target instruction is executed; the active state of the registers is obtained by the compiler based on the control flow graph analysis of the target program.

[0062] In this embodiment, an active register refers to a register whose value will be read or used in the future program execution path when the target instruction is executed.

[0063] By analyzing the control flow graph of the target program through the compiler, the registers in the active state can be obtained. Therefore, when saving the current coroutine's context state, only the values ​​of the registers in the active state can be saved, achieving minimal overhead for context saving and restoration.

[0064] In one implementation, the management structure includes a coroutine stack and a context storage area, wherein the coroutine stack is used to store the running state and the context storage area is used to store the context state of the coroutine.

[0065] In this embodiment, the operating status and the field status are stored separately, which achieves efficient organization and secure isolation of status information.

[0066] The context storage area can be located in the coroutine stack, in which case the top of the coroutine stack can be used to retrieve other content contained in the context.

[0067] In one implementation, before compiling the target program to obtain target code, the method further includes: Obtain performance profiling data of the target program, and based on the performance profiling data, determine the target instructions of the parallel program structure in the target code; the performance profiling data is used to indicate the probability of cache misses occurring during runtime of the target instructions.

[0068] In this embodiment, a feasible process for determining target instructions based on secondary compilation techniques such as PGO is provided. First, the target program can be subjected to performance profiling to obtain performance profiling data. From the performance profiling data, target instructions that are prone to cache misses can be obtained.

[0069] The following example illustrates the feasible implementation process of the program compilation method using LLVM's PGO optimization for OpenMP type programs.

[0070] In traditional OpenMP type target programs, multiple threads are created to execute parallel program structures. Each thread processes the data allocated to it serially. If a thread pauses memory access due to a cache miss while executing certain data, it will waste processor resources.

[0071] For instructions (i.e., target instructions) identified in performance profiling data that are highly likely to cause cache misses, their corresponding OpenMP parallel regions can be located based on their call stacks. During the compilation process based on profiling feedback, the following steps can be performed on this parallel region: First, the generated code enables the thread executing this parallel program structure to create multiple coroutines at runtime. Specifically, this includes: Allocate an independent stack space (or coroutine stack) for each coroutine.

[0072] Create and initialize the management structure for coroutines, refer to Figure 2This management structure can be used to store: the context state and the running state of a coroutine. The context state can include the stack pointer of each coroutine, the program counter value of each coroutine, and other context states. The running state can include currently runnable coroutines and currently running coroutines, etc. Figure 2 In this example, taking OpenMP threads, Figure 2 The current coroutine number and runnable coroutine bitmap in the memory can represent the running state, that is, the currently running coroutines and the currently runnable coroutines. Specifically, the current coroutine number can be used to represent the number of the coroutine currently occupying the processor, and the runnable coroutine bitmap can identify the currently runnable coroutines. The current coroutine number and runnable coroutine bitmap can be inferred from the information in the coroutine's local storage. For ease of implementation, the current coroutine number and runnable coroutine bitmap can be stored separately.

[0073] The coroutine local storage is an array of pointers or an index table used to quickly locate the private data area of ​​each coroutine (such as its coroutine stack). Using this field, the manager can efficiently find the stack of the corresponding coroutine based on its coroutine number (index). In the coroutine local storage, the current stack top and entry PC can be components of the context state; the current stack top can refer to the coroutine's stack pointer, and the entry PC can refer to the coroutine's program counter value. The context storage area can be used to store other context states. The context storage area can be located in a dedicated storage area; it can also be placed on the coroutine's stack, in which case other contents contained in the context can be retrieved through the top of the coroutine stack.

[0074] Figure 2 The right side shows the correspondence between each coroutine and its coroutine stack. The idle coroutine stack refers to the coroutine stack of the scheduled coroutine. The worker coroutine 1 stack, worker coroutine 2 stack, etc., represent the coroutine stacks of different worker coroutines.

[0075] After creating the coroutine stack and management structure, code generation and refactoring can be performed on the original parallel program structure in the target program. The resulting target code, specifically for the parallel program structure, can include the following four parts of logic: (1) The loop preamble is responsible for setting the current coroutine as the scheduled coroutine.

[0076] (2) The coroutine working code includes task acquisition logic, original parallel program structure and coroutine completion logic.

[0077] (3) Custom loop code, the core of which is to allocate tasks to idle worker coroutines based on index variables and schedule worker coroutines to run.

[0078] (4) Loop the cleanup code, responsible for synchronizing and completing all working coroutines.

[0079] It should be emphasized that the reconstructed main loop is the scheduling loop logic described above, while the logic of the original parallel program structure is encapsulated in the coroutine working code (specifically the original parallel program structure), which is executed when the working coroutine is scheduled.

[0080] The following is combined with Figure 3 This section provides illustrative examples of loop leading code, coroutine working code, custom loop code, and loop closing code.

[0081] When the loop's leading code is executed, the current coroutine is set as the scheduled coroutine; Then, the custom loop code is executed, entering the scheduling loop to check if there are any idle worker coroutines. If there are, the "supplement available coroutines" step is taken; otherwise, the currently runnable coroutines are scheduled.

[0082] The process of supplementing available coroutines may include the following steps: Retrieve the current value from the global loop index (obtain the loop index), use it as a task, find an idle worker coroutine, set the state at the time of restoration, and set the PC value as the entry point of the coroutine execution body; after completion, update the loop index, determine whether the exit condition is met, if not, return to the step of obtaining the loop index to continue iterating, if yes, execute the loop termination code.

[0083] Coroutine working code: When a working coroutine is scheduled to run, it obtains index variables from the coroutine's local storage space and executes the actual business logic (i.e., the original parallel program structure).

[0084] If the target instruction is encountered during the execution of the original parallel program structure, the switching code is executed: it saves its current state, initiates a prefetch, and then switches to run the next runnable coroutine. If there are no idle coroutines, the switch is made directly between runnable coroutines (i.e., the currently runnable coroutine is scheduled on the right). If there are idle coroutines, the steps described above for supplementing available coroutines are executed. In this way, multiple work coroutines can be executed alternately, hiding their respective memory access pause times.

[0085] After the original parallel program structure of the worker coroutine has been executed, the coroutine is set to idle and the step of scheduling the next coroutine is triggered again.

[0086] When the scheduling coroutine finds that the global loop index has reached the termination condition (all iterations have been assigned) and all working coroutines have completed their respective iterations and become idle, it executes the loop termination code, sets the coroutine scheduling mode to the lowest priority, switches to an available coroutine, and ends the entire parallel loop.

[0087] refer to Figure 4For each identified target instruction (i.e., the instruction expected to cause a cache miss), specific switch and recovery code is inserted into the generated code: The switching code performs the following operations: Before executing the target instruction, save the current state of the coroutine (especially the values ​​of active registers) to its management structure; calculate the memory address to be accessed by the target instruction and initiate a data prefetch operation; then, based on the running status in the management structure, if there is an idle working coroutine, determine the target coroutine as the scheduled coroutine, otherwise determine the target coroutine as the next runnable working coroutine; finally, switch to run the target coroutine.

[0088] The recovery code is located at a specific label. When the coroutine is run again, execution begins from here. It is responsible for restoring the previously saved state from the management structure and continuing to execute the target instructions.

[0089] by Figure 4 For example, Figure 4 This demonstrates the switching logic for switching from an executing coroutine to different working coroutines (coroutines that have not yet been executed and coroutines that have been executed).

[0090] After the execution of the original logic - part 1 ends, before executing the target instruction, the executing coroutine saves its current context, updates its program counter (PC) to the next address, and stores the next address of the program counter (PC) and the stack pointer (SP) in the coroutine's management results. The coroutine's register context saving and restoring time is approximately 10ns, which is much less than the 110ns of memory access pause.

[0091] Calculate the memory address of the data to be accessed by the target data, and then initiate a data prefetch operation.

[0092] After issuing the prefetch, the next coroutine entry point can be obtained based on the management structure, and the next runnable coroutine can be switched to (i.e., unconditional transfer to a coroutine). The coroutine switching logic can be referred to the previous description. If the coroutine switched to is one that has not yet been executed, the task acquisition logic (acquiring the iteration index, etc.) is executed, the original parallel program structure is executed, and the coroutine completion code is executed. If the coroutine switched to is one that has already been executed, execution will start from next (i.e., at the continuation label), the register context is restored, and then "original logic - part 2" is executed, which includes continuing to execute the target instruction (memory access operation) and subsequent logic.

[0093] The following example of binary tree search illustrates the execution logic of the target code obtained by the compilation method provided in this specification.

[0094] In binary tree search, the next node to be visited is obtained through the pointer stored in the current node. When the cache misses, the retrieval efficiency of a binary tree is relatively low. Suppose a programmer declares a parallel loop using OpenMP instructions to find the corresponding value of each element in the array `item[]` in the binary tree and stores the result in the array `result[]`: #pragma omp parallel for for (int i=0; i <n; i++) result[i] = binary_tree_search(item[i]); The core loop of the binary_tree_search(int target) function is as follows: TreeNode searchBSTIterative(TreeNode root, int target) { TreeNode current = root; while (current != nullptr) { if (current->value == target) / / Line 19: This memory access may cause a cache miss. return current; else if (target <current->value) current = current->left; else current = current->right; } return nullptr; } Suppose that performance analysis reveals that frequent accesses to current->value in line 19 cause processor pauses.

[0095] When applying the compilation method provided in the embodiments of this specification, for the OpenMP loop described above, the compiler generates target code for each thread executing the parallel program structure, and its core logic is as follows (illustrated in pseudocode): loop_begin: idx = get_free_worker(this_thread); / / Attempt to obtain an idle worker coroutine. if (!is_valid(idx)) / / If no idle worker coroutine is available sched_worker(); / / Schedules an available coroutine to run. add_worker_context(programmer_entry, i); / / Sets the context for the worker coroutine, including the entry address and loop index variable i. i++; / / Update the loop index variable if (i>bulk_end) goto worker_join; / / Check the loop termination condition goto loop_begin; programmer_entry: / / Entry point for the worker coroutine: the loop logic defined by the programmer i = load_context(); / / Restore the state of the coroutine (including index variable i, etc.) from the management structure. result[i] = binary_tree_search(item[i]); / / Perform the actual search. finish_work(this_thread); / / Mark the completion of the current coroutine's work and trigger a coroutine switch. worker_join: set_lowest_priority(this_thread); / / Set the priority of the scheduled coroutine to the lowest. sched_worker(); / / Execute the scheduler and wait for all work to complete. Once the performance profiling identifies the memory access in line 19 as a high-probability cache miss instruction, the compiler treats it as the target instruction and transforms it to generate code containing switching and recovery code: / / Switch code (the original line 19 has been replaced with this logic) save_worker_context(this_thread, cont_label); / / Saves the current coroutine's state to the management structure and records cont_label as the return point. prefetch(current->value); / / Initiate a prefetch operation on the data corresponding to the target instruction. pc, sp = get_next_worker(); / / Determine the entry address and stack pointer of the next runnable coroutine based on its running state. load_sp(); / / Sets the current stack as the target coroutine's stack. jump_to_pc(pc); / / Jump to the entry address of the target coroutine to complete the switch. / / Restore code (the original logic continues here) cont_label: / / Continue labeling: This is where the labeling begins when this coroutine is run again. restore_worker_context(this_thread); / / Restore the previously saved state from the management structure. if (current->value == target) / / Existing target instructions and subsequent logic return current; else if (target <current->value) / / ... Existing logic Execution Process Example: Assume the compiler creates 3 worker coroutines and 1 scheduler coroutine for each thread, with a total loop count of 4. After applying the compilation method provided in this specification, the execution flow is as follows: The scheduling coroutine (i.e., the idle coroutine) runs first, assigning iterative tasks (i=0,1,2) to the first 3 working coroutines and setting their state.

[0096] When attempting to allocate the 4th iteration (i=3), it was found that there were no idle worker coroutines, so the scheduling coroutine was switched to worker coroutine 1 (processing i=0) to run.

[0097] When coroutine 1 executes the target instruction (the transformed code), it saves the context, initiates a prefetch, and switches to coroutine 2.

[0098] Similarly, goroutine 2 switches to goroutine 3, and goroutine 3 switches back to goroutine 1 (since there are no idle goroutines, the scheduled goroutine is skipped).

[0099] Coroutine 1 resumes its state from cont_label, completes the remaining work of this iteration, marks itself as idle, and switches to coroutine 2.

[0100] And so on, goroutines 2 and 3 complete their tasks and switch over in sequence. Once all the working goroutines have completed one iteration, the control flow switches back to the scheduling goroutine.

[0101] The scheduler resumes operation and can allocate remaining iterations to idle coroutines (there are none left in this example). Finally, it waits for all working coroutines to complete before ending the loop.

[0102] The above process demonstrates the case where only one target instruction is optimized. When multiple target instructions exist, the execution and switching of each coroutine will be more frequent and intertwined, thereby making fuller use of processor resources, hiding memory access latency, and improving execution efficiency.

[0103] refer to Figure 5 , Figure 5 The embodiments of this specification show two implementation paths for the compilation method provided: a compile-time optimization path based on PGO (i.e., intermediate code logic generated during PGO compilation) or a code hot update path (i.e., binary code logic generated during code hot update).

[0104] Both paths aim to transform "target instructions that are prone to triggering pauses" in the original program logic. Their core transformation idea is the same: insert a cache existence check before executing the target instruction; if the data is already in the cache, continue execution; if it is not found, insert coroutine switching logic to hide memory access latency.

[0105] PGO's compile-time optimization path occurs during the program compilation and linking phase. The compiler possesses complete program information and can freely refactor the code, allocate registers, and generate the optimal instruction sequence at the intermediate representation level.

[0106] Hot code update path: This occurs after the program has been compiled into binary code and run. Because it is impossible to directly insert a large number of new instructions at the original location of the optimized instructions (insufficient space), the original instructions need to be replaced with jump instructions to jump to a newly allocated code area to execute the optimized logic.

[0107] In the PGO compile-time optimization path, the original logic-part1 is maintained: first, the code before the target instruction (original logic-part1) is executed, and then a cache existence check is inserted (taking the support for cache existence check as an example) to determine whether the target data is already in the cache.

[0108] If a hit occurs: the data is in the cache with no significant delay, and the execution jumps directly to the original logic - part2 (i.e., the code containing the target instruction and its subsequent parts).

[0109] If a cache miss occurs: the data is not in the cache, and a memory access pause is expected. At this point, the compiler generates code for the target instruction to perform a coroutine switch. This includes saving the current coroutine's state, initiating a data prefetch operation, and switching to the next runnable coroutine.

[0110] Because it is performed during the compilation phase, the compiler can perform a global register activity analysis, accurately determining which registers need to be saved and restored at checkpoints, thereby generating highly efficient save / restore code.

[0111] Hot code update path: Maintain the original logic - part 1: Same compile-time optimization path as PGO.

[0112] Save active registers corrupted by cache presence checks: Before performing a cache presence check, active registers corrupted by the cache presence check instruction itself can be saved. This is because a cache presence check may require writing some information to a register, which corrupts the current value of that register; if the current value of this register is needed later (e.g., in the original logic - part 2), it will cause an error in program execution, so its value must be saved.

[0113] Insert cache existence check: Perform the check.

[0114] If a hit occurs: the data is in the cache. At this point, simply restore the registers corrupted by the instructions checked in step 2, and then jump back to the original flow to continue executing the original logic - part 2. This avoids the overhead of a complete coroutine context save / restore.

[0115] If a cache miss occurs: the data is not in the cache, and a complete coroutine switch is required. In this case, based on the data saved in step 2, all currently active registers (i.e., the complete state of the current state) are saved, and then a coroutine switch (including prefetching and switching to the next coroutine) is performed.

[0116] Exemplary device In one exemplary embodiment of this specification, a program compilation apparatus is also provided, the program compilation apparatus comprising: The first module is used to compile the target program to obtain target code; the target code is used to implement a loop process when executed. The loop process includes: creating multiple coroutines for the thread executing the parallel program structure, each coroutine having a corresponding management structure for storing the state of the coroutine; and alternately executing multiple iterations of the parallel program structure through the multiple coroutines, wherein, for a target instruction, the target code includes switching code and recovery code for the target instruction; the target instruction is an instruction for which a cache miss is expected. The switching code is used to save the current state of the coroutine in the management structure, initiate a prefetch operation of the data corresponding to the target instruction, and switch to run the next runnable coroutine before executing the target instruction; the recovery code is used to restore the state based on the current state when the coroutine is run again, so as to continue executing the target instruction.

[0117] This compiler optimizes the parallel program structure of the target program. The compiler-generated target code creates multiple coroutines to execute iteratively in alternating loops. Before a cache miss is expected, inserted switching code saves the current coroutine's context state and initiates data prefetching, then switches to the next runnable coroutine. When the coroutine resumes, the recovery code continues execution of the target instruction based on the context state. Thus, while one coroutine is waiting for data prefetching, the processor can switch to execute other coroutines, fully utilizing previously idle cycles to achieve instruction-level parallelism and improve resource utilization. Coroutines save and restore their context through an independent management structure, resulting in extremely low context switching overhead. Furthermore, this method automatically performs optimization during the compilation phase, requiring no developer intervention and possessing universality. The compiler uses a global view of the program to accurately locate target instructions and generate efficient code, with no additional decision-making overhead during processor execution, further reducing runtime resource consumption.

[0118] For specific limitations regarding the program compilation apparatus, please refer to the limitations regarding the program compilation method above, which will not be repeated here. Each module in the aforementioned program compilation apparatus can be implemented entirely or partially through software, hardware, or a combination thereof. These modules can be embedded in hardware or independently of the processor in the computer device, or stored in software in the memory of the computer device, so that the processor can call and execute the operations corresponding to each module.

[0119] Exemplary computing device Another embodiment of this application also proposes a computing device, see [link to relevant documentation] Figure 6 As shown, an exemplary embodiment of this specification also provides a computing device, including: a memory and a processor, the memory storing a computer program, the processor executing the computer program and performing the steps of the program compilation method according to various embodiments of this specification described above.

[0120] The internal structure of the computing device can be as follows: Figure 6 As shown, the computing device includes a processor, memory, network interface, and input devices connected via a system bus. The processor provides computing and control capabilities. The memory includes a non-volatile storage medium and internal memory. The non-volatile storage medium stores an operating system and computer programs. The internal memory provides an environment for the operation of the operating system and computer programs stored in the non-volatile storage medium. The network interface is used to communicate with external terminals via a network connection. When the computer program is executed by the processor, it follows the steps of the program compilation methods according to various embodiments of this specification described in the above embodiments.

[0121] The processor may include the main processor, as well as baseband chips, modems, etc.

[0122] It is understood that the processor in the embodiments of this specification can be an integrated circuit chip with signal processing capabilities. In implementation, each step of the above method embodiments can be completed by integrated logic circuits in the processor's hardware or by instructions in software form. The processor can be a general-purpose processor, a digital signal processor (DSP), an application-specific integrated circuit (ASIC), a field-programmable gate array (FPGA), or other programmable logic devices, discrete gate or transistor logic devices, or discrete hardware components. It can implement or execute the methods, steps, and logic block diagrams disclosed in the embodiments of this specification. The general-purpose processor can be a microprocessor or any conventional processor. The steps of the methods disclosed in the embodiments of this specification can be directly implemented by a hardware decoding processor, or by a combination of hardware and software modules in the decoding processor. The software modules can reside in random access memory, flash memory, read-only memory, programmable read-only memory, electrically erasable programmable memory, registers, or other mature storage media in the art. This storage medium is located in memory; the processor reads information from the memory and, in conjunction with its hardware, completes the steps of the above methods.

[0123] It is understood that the memory in the embodiments of this specification may be volatile memory or non-volatile memory, or may include both volatile and non-volatile memory. Non-volatile memory may be read-only memory (ROM), programmable read-only memory (PROM), erasable programmable read-only memory (EPROM), electrically erasable programmable read-only memory (EEPROM), or flash memory. Volatile memory may be random access memory (RAM). It should be noted that the memory in the systems and methods described herein is intended to include, but is not limited to, these and any other suitable types of memory.

[0124] Input devices may include devices that receive data and information input by the user, such as keyboards, mice, cameras, scanners, light pens, voice input devices, touch screens, pedometers, or gravity sensors.

[0125] Output devices may include devices that allow information to be output to the user, such as displays, printers, speakers, etc.

[0126] The communication interface may include any transceiver-like device for communicating with other devices or communication networks, such as Ethernet, Radio Access Network (RAN), Wireless Local Area Network (WLAN), etc.

[0127] The computing device may also include a display component and a voice component. The display component may be a liquid crystal display screen or an e-ink display screen. The input device of the computing device may be a touch layer covering the display component, or a button, trackball or touchpad set on the casing of the computing device, or an external keyboard, touchpad or mouse, etc.

[0128] Those skilled in the art will understand that Figure 6 The structures shown are merely block diagrams of some structures related to the solutions in this specification and do not constitute a limitation on the computing devices on which the solutions in this specification are applied. Specific computing devices may include more or fewer components than those shown in the figures, or combine certain components, or have different component arrangements.

[0129] Exemplary computer program products and storage media In addition to the methods and devices described above, the program compilation methods provided in the embodiments of this specification can also be computer program products, which include computer program instructions that, when executed by a processor, cause the processor to perform the steps in the program compilation methods according to various embodiments of this specification as described in the "Exemplary Methods" section above.

[0130] The aforementioned computer program product can be implemented through hardware, software, or a combination thereof. In one optional embodiment, the computer program product is specifically embodied in a computer storage medium; in another optional embodiment, the computer program product is specifically embodied in a software product, such as a software development kit (SDK), etc.

[0131] The computer program product described herein can be written in any combination of one or more programming languages ​​to perform the operations of the embodiments described herein. These programming languages ​​include object-oriented programming languages ​​such as Java and C++, as well as conventional procedural programming languages ​​such as C or similar languages. The program code can be executed entirely on the user's computing device, partially on the user's computing device, as a standalone software package, partially on the user's computing device and partially on a remote computing device, or entirely on a remote computing device or server.

[0132] Furthermore, embodiments of this specification also provide a computer-readable storage medium having a computer program stored thereon, the computer program being executed by a processor of the steps in the program compilation methods according to various embodiments of this specification as described in the "Exemplary Methods" section above.

[0133] Those skilled in the art will understand that all or part of the processes in the methods of the above embodiments can be implemented by a computer program instructing related hardware. The computer program can be stored in a non-volatile computer-readable storage medium. When executed, the computer program can include the processes of the embodiments of the above methods. Any references to memory, storage, databases, or other media used in the embodiments provided in this specification can include non-volatile and / or volatile memory. Non-volatile memory may include read-only memory (ROM), programmable ROM (PROM), electrically programmable ROM (EPROM), electrically erasable programmable ROM (EEPROM), or flash memory. Volatile memory may include random access memory (RAM) or external cache memory. By way of illustration and not limitation, RAM is available in a variety of forms, such as static RAM (SRAM), dynamic RAM (DRAM), synchronous DRAM (SDRAM), dual data rate SDRAM (DDRSDRAM), enhanced SDRAM (ESDRAM), synchronous link DRAM (SLDRAM), RAMbus direct RAM (RDRAM), direct memory bus dynamic RAM (DRDRAM), and memory bus dynamic RAM (RDRAM), etc.

[0134] The technical features of the above embodiments can be combined in any way. For the sake of brevity, not all possible combinations of the technical features in the above embodiments are described. However, as long as there is no contradiction in the combination of these technical features, they should be considered to be within the scope of this specification.

[0135] The embodiments described above are merely illustrative of several implementation methods outlined in this specification. While the descriptions are specific and detailed, they should not be construed as limiting the scope of the solutions provided in this specification. It should be noted that those skilled in the art can make various modifications and improvements without departing from the concept of this specification, and these all fall within the scope of protection of this specification. Therefore, the scope of protection for this patent should be determined by the appended claims.

Claims

1. A program compilation method, characterized in that, include: The target program is compiled to obtain the target code; The target code is used to implement a loop process when executed: The loop process includes: creating multiple coroutines for the thread executing the parallel program structure, each coroutine having a corresponding management structure for storing the state of the coroutine; and alternately executing multiple iterations of the parallel program structure through the multiple coroutines, wherein, for a target instruction, the target code includes switching code and recovery code for the target instruction; the target instruction is an instruction for which a cache miss is expected. The switching code is used to save the current state of the coroutine in the management structure, initiate a prefetch operation of the data corresponding to the target instruction, and switch to run the next runnable coroutine before executing the target instruction; the recovery code is used to restore the state based on the current state when the coroutine is run again, so as to continue executing the target instruction.

2. The method according to claim 1, characterized in that, The creation of multiple coroutines for the thread executing the parallel program structure includes: Determine the scheduling coroutine and multiple worker coroutines among the multiple coroutines; The scheduling coroutine is used to allocate the iteration to the idle working coroutine according to the index variable of the parallel program structure during runtime; the index variable corresponds to the iteration. The worker coroutine is used to execute the assigned iteration at runtime.

3. The method according to claim 2, characterized in that, The management structure further includes: a running state, which is used to characterize at least one of runnable coroutines and currently running coroutines; The switching to run the next runnable coroutine includes: Based on the running status, determine whether there is an idle working coroutine. If there is an idle working coroutine, determine the next runnable coroutine as the scheduling coroutine; if there is no idle working coroutine, determine the next runnable coroutine as the runnable working coroutine.

4. The method according to claim 1, characterized in that, The compilation of the target program includes: Based on the target program, an initial intermediate representation corresponding to the target program is obtained; Based on the initial intermediate representation corresponding to the parallel program structure in the target program, an optimized intermediate representation corresponding to the loop process is generated. The optimized intermediate representation includes a calling function, which is used to call the switching code and the recovery code. The compiler backend generates the target code based on the optimized intermediate representation.

5. The method according to claim 1, characterized in that, The compilation of the target program includes: The compiler performs a compilation process based on the target program to generate a source program in binary code form; the compilation process includes issuing intermediate identifiers and allocating registers; The parallel program structure portion of the source program is reconstructed to obtain optimized code corresponding to the loop process; The target code is generated based on the optimized code and the source program.

6. The method according to claim 5, characterized in that, The current state of the coroutine includes the values ​​of the registers that are active when the target instruction is executed; the active state of the registers is obtained by the compiler based on the control flow graph analysis of the target program.

7. The method according to claim 3, characterized in that, The management structure includes a coroutine stack and a context storage area. The coroutine stack is used to store the running state, and the context storage area is used to store the context state of the coroutine.

8. The method according to claim 7, characterized in that, The field storage area is located in the coroutine stack.

9. The method according to any one of claims 1 to 8, characterized in that, Before compiling the target program to obtain the target code, the process further includes: Obtain performance profiling data of the target program, and based on the performance profiling data, determine the target instructions of the parallel program structure in the target code; the performance profiling data is used to indicate the probability of cache misses occurring during runtime of the target instructions.

10. A computing device, characterized in that, It includes a memory, a processor, and a computer program stored in the memory and executable on the processor, wherein the processor executes the computer program to implement the program compilation method according to any one of claims 1 to 9.

11. A storage medium, characterized in that, The storage medium stores a computer program, which, when executed by a processor, implements the program compilation method according to any one of claims 1 to 9.

12. A computer program product, characterized in that, The computer program product includes a computer program, which, when executed by a processor, implements the program compilation method as described in any one of claims 1 to 9.