A performance optimization method for reverse debugging deterministic replay
By dynamically adjusting the recording granularity and constructing the dependency graph based on thread behavior under race conditions in multi-threaded programs, deterministic replay across architectures is achieved, solving the problems of low efficiency and high cost in existing technologies and achieving highly efficient parallel replay effects.
Patent Information
- Application Number
- CN202511926028.2
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2025-12-19
- Publication Date
- 2026-02-27
- Estimated Expiration
- 2045-12-19
AI Technical Summary
Existing deterministic replay technology suffers from problems such as low efficiency in the recording phase, inability to utilize multi-core computing power in the replay process, and high cross-platform adaptation costs in cross-architecture scenarios. It is particularly difficult to achieve deterministic replay under the race conditions of multi-threaded programs.
By debugging the target program in the first target architecture, generating different record granularities based on the thread lock contention frequency, shared memory access density, and state transition frequency, constructing thread dependency chains and dependency graphs, dividing replay partitions, and executing replay in parallel in the second target architecture, using progress counters and virtual clocks to monitor execution progress, and combining unified representation and synchronous notification processes for cross-architecture events, deterministic replay across architectures is achieved.
It achieves deterministic replay under race conditions in multi-threaded programs across architectures, reduces the amount of recorded data, improves replay efficiency, utilizes multi-core computing power in parallel, and reduces cross-platform adaptation costs.
Smart Images

Figure CN121349842B_ABST
Abstract
Description
TECHNICAL FIELD
[0001] The application belongs to the technical field of computer software development, and particularly relates to a performance optimization method for reverse debugging deterministic replay. BACKGROUND
[0002] Race Condition of multi-threaded programs is one of the most difficult defect types to debug in software development, and its essence is the non-deterministic behavior caused by uncontrolled interaction between threads. Existing deterministic replay technology (such as Mozilla RR) realizes execution trajectory reproduction by recording thread scheduling events and synchronization operations, but still has significant limitations in cross-architecture scenarios and race reproduction, specifically: the recording phase needs to capture all instructions and events, resulting in a sharp decline in program running efficiency; the replay process relies on single-threaded verification, and cannot take advantage of multi-core computing power; the differences between instruction sets and memory model characteristics of different architectures result in high cost of cross-platform adaptation.
[0003] To sum up, how to control the recording granularity of execution state data in the recording process, how to realize cross-architecture replay based on recorded data, and parallelization of the replay process are still technical problems to be solved. SUMMARY
[0004] Therefore, the application provides a performance optimization method for reverse debugging deterministic replay, which realizes deterministic replay of multi-threaded program reverse debugging under complex program race condition.
[0005] The performance optimization method for reverse debugging deterministic replay provided by the application specifically includes the following steps:
[0006] Step 1, debugging the target program in the first target architecture to obtain the lock competition frequency, shared memory access density and state transition frequency of the thread; if the lock competition frequency and the shared memory access density are both greater than the corresponding threshold, start instruction-level recording; if the lock competition frequency and the shared memory access density are both zero, and the state transition frequency is less than the threshold, start state-level recording; otherwise, start event-triggered recording; form a first record;
[0007] Step 2, determining the dependency relationship between threads according to the first record, establishing a thread dependency chain including source thread ID, destination thread ID, dependency type, resource identifier and time difference, the time difference being the time difference between the source thread and the destination thread performing operations on the resource; constructing a dependency graph including thread nodes, event nodes and dependency edges, marking the weight of the dependency edge, and dividing the dependency graph into multiple replay partitions;
[0008] Step 3, binding the CPU core for replay partition in the second target architecture and executing the replay in parallel, the thread maintaining a progress counter and a virtual clock, the progress counter recording the number of events that have been executed, and the virtual clock simulating the execution time, updating the progress counter and the virtual clock after the event is executed; if the virtual clock of the thread is greater than the record value in the first record, triggering the accelerated execution mode until the virtual clock is not greater than the record value; when the thread executes to the start point of the dependent edge, triggering the synchronization notification process to complete the replay.
[0009] Further, the events under different architectures are described by using basic attributes and extended attributes, wherein the basic attributes include atomic operations, synchronization operations and memory barriers, and the extended attributes are metadata for identifying different architecture features;
[0010] In the first target architecture, instructions belonging to the basic event set are identified from the intercepted instructions, the operation code, operand, register or memory address of the instructions are parsed and represented as basic attributes, the metadata of the architecture to which the instructions belong is extracted as extended attributes, and the event format containing the basic attributes and the extended attributes is serialized.
[0011] Further, the weight of the dependent edge is the absolute value of the time difference.
[0012] Further, the way of dividing the dependent graph into multiple replay partitions is:
[0013] Step 3.1, traversing the thread nodes in the dependent graph, adding all thread nodes without pre-dependence to the candidate pool as starting candidates for partition construction;
[0014] Step 3.2, calculating the parallel gain of each thread node in the candidate pool, and preferentially selecting the thread with the highest parallel gain to join the replay partition to be constructed as the core thread, wherein the parallel gain is the ratio of the thread independent execution time to the total number of dependent edges associated with the thread;
[0015] Step 3.3, taking the core thread of the replay partition as a reference, traversing the remaining thread nodes, and gradually adding the threads that have no any dependence relationship with the threads in the replay partition to the replay partition, until the replay partition cannot be expanded or the expected execution time reaches the average load threshold, completing the construction of the current replay partition, wherein the average load threshold is the ratio of the total execution time to the target partition number;
[0016] Step 3.4, creating a new replay partition to be constructed, executing step 3.1, until all thread nodes are allocated to the corresponding replay partition, forming a preliminary partition result;
[0017] Step 3.5, on the basis of the preliminary partitioning result, migrating thread nodes between adjacent replay partitions, calculating the partition load balancing degree after each migration, and retaining the exchange result that increases the load balancing degree, wherein the partition load balancing degree is the ratio of the standard deviation to the average of the execution time of each partition.
[0018] Further, the event execution updates the progress counter and the virtual clock, and sets the virtual clock as the sum of the previous event timestamp and the event execution time, wherein the event execution time is the measured value in the first record.
[0019] Further, the synchronization notification process comprises:
[0020] The thread writes the current event index and the virtual clock into the synchronization notification area of the shared memory, and sends a wake-up notification to the thread waiting for the event; the thread is blocked in the synchronization notification area before executing to the end of the dependent edge, until the wake-up notification is received; after the thread is woken up, the difference between the current virtual clock and the virtual clock in the wake-up notification is calculated, and if the difference is less than the recorded time difference, the remaining time is compensated to maintain the original timing; if the difference is greater than the recorded time difference, it is determined that the replay is abnormal and a debugging interrupt is triggered.
[0021] Further, the instruction verification in the replay process is performed in a hierarchical verification and adaptive sampling manner, comprising:
[0022] In the initial stage of the replay, all fine-grained L1 level checkpoints are enabled, in the stable stage only medium-grained L2 level checkpoints are executed, and in the end stage the L1 level checkpoints are re-enabled;
[0023] If a continuous number of checkpoints pass the verification, the verification interval is extended; otherwise, the time window in which the exception occurs is determined by the coarse-grained L3 level checkpoint, the L2 level checkpoints are traversed within the time window to locate the synchronization operation of the exception, and the instruction-by-instruction comparison is enabled before and after the synchronization operation to finally locate the inconsistent instruction.
[0024] Further, a snapshot management based on hierarchical storage and incremental update strategy is established, specifically:
[0025] In the first target architecture, the address space layout is obtained before the target program is started and executed for the first time, the static data and code segment, the initial state of the global variable, the system resource handle and the hardware state register are read to form a global baseline snapshot, and the global baseline snapshot is stored as a multi-segment file in a manner of separating the code segment, the data segment and the resource segment.
[0026] The thread creates a complete stack memory, a register and an initial data of a TLS area to form a thread private snapshot when the thread is created, and only the thread private snapshot is updated with a modified memory page, a changed register value and a modified variable in the TLS when the thread is woken up from a block, a thread private snapshot version chain is formed according to an update timestamp, and a difference between versions is stored; a hash table is established in units of memory pages, a key is a page start address, and a value is a difference log of the page, and a difference record in the difference log includes a timestamp, an offset, an old value, a new value and an operation thread ID, and the offset is an address in the page;
[0027] In the second target architecture, when the program state at a specified time T is restored, shared memory is restored according to the global baseline snapshot, thread state is restored according to the thread private snapshot, system resource state synchronization is completed by interacting with the operating system, and exception processing and rollback are performed when a check inconsistency occurs in the restoration process.
[0028] Further, the shared memory restoration according to the global baseline snapshot includes: mapping the global baseline snapshot to a recording stage virtual address, traversing a memory page index table, screening a shared memory page with a timestamp not greater than T to generate a to-be-modified page list; for each page in the to-be-modified page list, arranging the page application difference records in ascending order according to the timestamp, and replacing the old value at the offset with the new value from the baseline page data, until all difference records of the page are processed;
[0029] The thread state restoration according to the thread private snapshot includes: finding a thread version chain for each thread, selecting a snapshot version with a timestamp not greater than T and a minimum absolute value difference from T, loading the stack, register state and TLS data of the snapshot, executing the private instruction stream of the thread from the snapshot timestamp to the T time, and updating the register and stack state according to the record.
[0030] Further, the thread node includes a thread ID and a life cycle, the event node includes a shared memory write, a lock release and a lock acquisition type event, the event node is associated with the thread, the event occurrence time and the resource, the dependency edge includes a data dependency, a control dependency and a timing dependency type, and the life cycle of the thread refers to a period from a thread start time to a thread termination time.
[0031] Beneficial effects:
[0032] The application generates first records in three categories of high competition area, low interaction area and transition area according to the lock competition frequency, shared memory access density and state transition frequency of threads when a target program is executed in a first target architecture debugging; extracts three types of dependency relationships of synchronization, data and indirectness between threads from the first records to construct thread dependency chains; constructs a dependency graph containing thread nodes, event nodes and dependency edges based on the first records and the dependency chains, and divides replay partitions according to the number, control and timing dependencies between threads; finally, starts a replay engine in a second target architecture, binds CPU cores for the replay partitions and processes caches, monitors the execution progress through the progress counter and virtual clock of threads, dynamically adjusts the execution speed, guarantees the dependency timing consistency through the synchronization notification process, and completes cross-architecture replay. BRIEF DESCRIPTION OF DRAWINGS
[0033] Figure 1 A flowchart of a performance optimization method of reverse debugging deterministic replay provided by the application is shown. DETAILED DESCRIPTION
[0034] The application will be described in detail below with examples combined with the drawings.
[0035] The core idea of the performance optimization method of reverse debugging deterministic replay provided by the application is as follows: first records are generated in three categories of high competition area, low interaction area and transition area according to the lock competition frequency, shared memory access density and state transition frequency of threads when a target program is executed in a first target architecture debugging; three types of dependency relationships of synchronization, data and indirectness between threads are extracted from the first records to construct thread dependency chains; a dependency graph containing thread nodes, event nodes and dependency edges is constructed based on the first records and the dependency chains, and replay partitions are divided according to the number, control and timing dependencies between threads; finally, a replay engine is started in a second target architecture, CPU cores are bound for the replay partitions and caches are processed, the execution progress is monitored through the progress counter and virtual clock of threads, the execution speed is dynamically adjusted, the dependency timing consistency is guaranteed through the synchronization notification process, and cross-architecture replay is completed.
[0036] The performance optimization method of reverse debugging deterministic replay provided by the application has the flow as shown in Figure 1 The specific steps include the following steps:
[0037] Step 1, debug the execution target program in the first target architecture, dynamically track the thread behavior from the shared memory access layer, the synchronization operation layer and the state transition layer through the lightweight kernel probe, and generate the first feature vector of the thread including the lock contention frequency, the shared memory access density and the state transition frequency; if the lock contention frequency and the shared memory access density are both greater than the corresponding threshold value, it is indicated that the thread is in a high-frequency resource contention state and belongs to a high contention area, and then instruction-level recording is started; if the lock contention frequency and the shared memory access density are both zero, and the state transition frequency is less than the threshold value, it is indicated that the thread is in an independent execution state and belongs to a low interaction area, and then state-level recording is started; otherwise, it is indicated that the thread belongs to a transition area between the high contention area and the low interaction area, and event-triggered recording is started; and the first record is formed.
[0038] The lock contention frequency is the number of lock contentions of the thread within a set time, the shared memory access density is the number of accesses to the shared memory of the thread within the set time, and the state transition frequency is the number of state transitions of the thread within the set time.
[0039] The instruction-level recording is the address, operation code and operand of each instruction executed by the thread, and the register state of the instruction involving the shared resource is additionally recorded. The recording granularity is accurate to the instruction cycle, so as to ensure that the key track of the race condition is not missed.
[0040] The state-level recording is to record the thread state snapshot when the thread enters the low interaction area, when the thread is about to exit the low interaction area, or when the thread state transitions. The thread state snapshot includes the stack pointer, the program counter and the private register value.
[0041] The event-triggered recording is to continuously cache the instructions executed by the thread into the instruction buffer, and when the shared resource access event is detected, the first set of instructions and the last set of instructions in the instruction buffer are immediately recorded persistently, and at the same time, the instruction-level recording is activated for a continuous set time, and after the set time is reached, the instruction is automatically restored to the instruction buffer, so as to avoid full recording of the thread which is about to interact with the resource but has not yet entered the high contention state.
[0042] Further, in order to realize the recording and replay across architectures, the application establishes a unified representation and mapping of cross-architecture events, including:
[0043] Step 1.1, constructing a basic event set and an extended attribute, mapping related operations of different architectures into a unified data format, wherein the basic event set includes basic attributes such as atomic operations, synchronization operations and memory barriers, and the extended attribute is used to identify architecture-related metadata of events under different architectures; metadata, such as segment registers of x86 events;
[0044] Step 1.2, in the first target architecture, the tool adapted to the architecture is used to intercept the executed instructions in full or to monitor the key instructions; the instructions belonging to the basic event set are identified from the intercepted instructions, and the key parameters such as operation code, operand, register and / or memory address are analyzed; then the instructions are mapped to the basic attributes of the abstract events in the basic event set with a unified format according to the key parameters, and the architecture-related metadata associated with the instructions is extracted as the extended attributes of the abstract events;
[0045] Step 1.3, the abstract events converted and containing the basic attributes and the extended attributes are formatted and serialized to realize the standardized storage and transmission of cross-architecture events.
[0046] Step 2, according to the relationship between the threads, the thread start time, the thread termination time, the resources and the operation time of the resources in the first record, the dependency relationship between the threads is determined, including three types of dependency relationships, i.e. synchronization dependency, data dependency and indirect dependency; then, according to the relationship between the threads, a thread dependency chain is established, including source thread ID, destination thread ID, dependency type, resource identifier and time difference, the time difference being the difference between the operation times of the source thread and the destination thread on the resource.
[0047] Step 3, according to the first record and the thread dependency chain, a multi-level directed graph containing thread nodes, event nodes and dependency edges is constructed, denoted as a dependency graph, wherein the thread node contains a thread ID and a life cycle, the event node contains a shared memory write, a lock release and a lock acquisition, etc., the event node is associated with the thread to which it belongs, the event occurrence time and the resource, the dependency edge includes data dependency, control dependency and timing dependency, and each dependency edge is marked with a weight, which can be the absolute value of the time difference; the dependency graph is divided into multiple replay partitions in a manner that threads with data dependency, control dependency and timing dependency are divided into the same partition.
[0048] The life cycle of the thread refers to the period from the thread start time to the thread termination time. The resource can be represented by a resource ID, such as a memory address or a lock ID.
[0049] Since there may be circular dependencies in complex programs, which will directly lead to partition failure, the present application uses depth-first search (DFS) to detect circular dependencies in the dependency graph, and performs a resolution algorithm for each circular dependency, specifically: the dependency edge with the smallest weight in the circular dependency is marked as a forced serial edge, and the related threads are divided into the same partition when dividing the replay partition, so as to ensure that the threads in the loop are executed in series.
[0050] Further, in order to realize the load balancing between the replay partitions and make the number of replay partitions not greater than the number of CPU cores of the second target architecture, the present application establishes a partitioning method based on an improved greedy genetic hybrid algorithm, including:
[0051] Step 3.1, traverse the thread nodes in the dependency graph, add all thread nodes without pre-dependence, i.e. with an in-degree of zero, to the candidate pool as starting candidates for partition construction;
[0052] Step 3.2, calculate the parallel gain of each thread node in the candidate pool, preferentially select the thread with the highest parallel gain to join the current replay partition to be constructed and as the core thread of the partition, wherein the parallel gain is the ratio of the thread-independent execution duration to the total number of dependency edges associated with the thread;
[0053] Step 3.3, take the core thread of the current replay partition as a reference, traverse the remaining thread nodes, and gradually add threads that have no dependency relationship with the threads within the replay partition to the current replay partition until the replay partition cannot be expanded or the estimated execution time of the partition reaches the average load threshold, completing the construction of the current replay partition, wherein the average load threshold is the ratio of the total execution time to the target number of partitions;
[0054] Step 3.4, create a new replay partition to be constructed, execute step 3.1 until all thread nodes are assigned to corresponding partitions, forming a preliminary partition result;
[0055] Step 3.5, perform a thread exchange operation on the preliminary partition result, i.e. migrate thread nodes between adjacent replay partitions, calculate the partition load balancing degree after each migration, and retain the exchange result that improves the load balancing degree, wherein the partition load balancing degree is the ratio of the standard deviation to the average value of the execution time of each partition.
[0056] Step 4, start the replay engine in the second target architecture, bind CPU cores to the replay partitions, and rename the threads within the replay partitions, clean up the cache corresponding to the replay partitions, and execute the replay of the replay partitions in parallel by each CPU; in each CPU core, the thread maintains a progress counter and a virtual clock, wherein the progress counter is used to record the number of events executed, and the virtual clock is used to simulate the execution time, the progress counter and the virtual clock are updated after executing an event, and the virtual clock is set as the sum of the previous event timestamp and the event execution time, and the event execution time is the measured value in the first record;
[0057] Monitor the progress counter and virtual clock of all threads in real time through the shared memory progress table, if the virtual clock of a thread is greater than the recorded value in the first record, trigger the accelerated execution mode to close the pre-set non-critical verification until the virtual clock is not greater than the recorded value in the first record; when the thread executes to the start point of the dependency edge, trigger the synchronization notification process to complete the replay, so as to guarantee the consistency of the dependency timing.
[0058] The synchronization notification process includes:
[0059] The thread writes the current event index and the virtual clock into a synchronization notification area of the shared memory, and sends a wake-up notification to the thread waiting for the event; the thread depending on the event is blocked in the synchronization notification area before executing to the end of the dependence edge until receiving the wake-up notification;
[0060] After the thread depending on the event is woken up, the difference between the current virtual clock and the virtual clock in the wake-up notification is calculated, if the difference is less than the recorded time difference, the remaining time is compensated to maintain the original timing, if the difference is greater than the recorded time difference, it is determined that the replay exception occurs and a debugging interrupt is triggered.
[0061] Further, the present application adopts a layered verification and adaptive sampling method to realize instruction verification in the replay process, which improves the execution efficiency under the premise of ensuring correctness, including:
[0062] All L1-level checkpoints are enabled in the initial stage of the replay to ensure the correctness of the replay starting point, only L2-level checkpoints are executed in the stable stage of the replay, and one L1-level checkpoint is randomly selected every 5 L2-level checkpoints to reduce the overhead, and all L1-level checkpoints are re-enabled in the end stage of the replay to ensure the correct termination state of the program;
[0063] When the verification interval is extended after 5 consecutive checkpoint verifications pass, otherwise, the time window of the abnormality occurrence is determined through the L3-level checkpoint, the L2-level checkpoint is traversed in the time window to locate the synchronization operation of the abnormality, and the instruction-by-instruction comparison is enabled before and after the synchronization operation to finally locate the inconsistent instruction.
[0064] The initial stage of the replay can be selected as the first 10% of the execution time, the stable stage can be 10% to 90% of the execution time, and the end stage can be the last 10% of the execution time.
[0065] The L1-level checkpoint is a fine-grained checkpoint, specifically generated once every N instructions involving shared resources, and records the values of key registers and the operation sequence hash of the last M shared memory instructions, the key registers being program counters, stack pointers and shared memory operation related registers.
[0066] The L2-level checkpoint is a medium-grained checkpoint, specifically generated once every synchronization operation, and records all general register values of the thread, the hash of a set number of elements at the top of the stack, and the list of synchronization objects currently held.
[0067] The L3-level checkpoint is a coarse-grained checkpoint, specifically generated once every set time, and records the global state of the process.
[0068] Under the premise of ensuring the accuracy of state recovery, to solve the problem of large storage overhead and slow recovery speed of full snapshot, the present application establishes a snapshot management method based on layered storage and incremental update strategy, specifically:
[0069] In the first target architecture, before the user code is executed for the first time after the target program is started, an address space layout is acquired, static data and code segments, global variable initial states, system resource handles, and hardware state registers are read to form a global baseline snapshot, and the global baseline snapshot is stored as a multi-segment file in a separated manner according to code segments, data segments, and resource segments;
[0070] When a thread is created, a complete stack memory, general and special registers, and initial data of a TLS region are recorded to form a thread private snapshot, when the thread is woken up from blocking, only the memory page modified, the register value changed, and the variable modified in the TLS are updated to the thread private snapshot, a version chain of the thread private snapshot is formed according to an update timestamp, and only differences between versions are stored;
[0071] A hash table is established in units of memory pages, a key is a page start address, and a value is a difference log of the page, the difference log includes a timestamp, an offset, an old value, a new value, and an operation thread ID, and the offset is an address within the page;
[0072] In the second target architecture, when a program state at a specified time T is restored, shared memory is restored according to the global baseline snapshot, thread state is restored according to the thread private snapshot, system resource state synchronization is completed by interacting with an operating system, and when a check inconsistency occurs during the restoration process, exception processing and rollback are performed.
[0073] The shared memory is restored according to the global baseline snapshot, including:
[0074] The global baseline snapshot is mapped to a recording stage virtual address, a shared memory page with a timestamp not greater than T is filtered by traversing a memory page index table to generate a to-be-modified page list, for each page in the to-be-modified page list, the page is arranged in ascending order according to the timestamp, and an old value at the offset is replaced with a new value from the baseline page data.
[0075] The thread state is restored according to the thread private snapshot, including:
[0076] For each thread, a thread version chain is searched by binary search, a snapshot version with a timestamp not greater than T and a minimum absolute value difference from T is selected, a stack, a register state, and TLS data of the snapshot are loaded, a private instruction stream of the thread is executed from a snapshot timestamp to a T time, and a register and a stack state are updated according to the record.
[0077] System resource state synchronization is completed by interacting with the operating system, including:
[0078] For files, open the file with the same path, set the offset according to the record, and restore the file status flag; for network sockets, create a socket of the same type, set the same options, and simulate the connection state; for signal processing, re-register the signal processing function consistent with the snapshot, and restore the signal mask.
[0079] Exception handling and rollback:
[0080] If the verification is inconsistent, release the currently restored memory page, reload the page corresponding to the global baseline snapshot, enable the record-by-record verification mode to re-verify the application difference, and locate the error record; if it is a record phase error, mark the difference record as an invalid record, and replace it with the previous valid record, and record the error log.
[0081] Embodiments:
[0082] This embodiment takes x86 and ARM architectures as examples, and uses the performance optimization method of reverse debugging deterministic replay provided by the application to realize the replay of multi-threaded program reverse debugging under complex program race conditions from three dimensions of dynamic regulation from record granularity, unified representation of cross-architecture events, and parallel scheduling of replay. The specific process includes:
[0083] S1, adaptive recording based on event dependency. By analyzing the interaction intensity of threads and shared resources in real time, the recording accuracy is dynamically adjusted to minimize redundant data while ensuring that the race condition is reproducible.
[0084] S1.1, thread behavior image construction, the recording phase realizes non-intrusive tracking of thread behavior through lightweight kernel probes such as kprobe on x86 platform or eBPF on ARM platform, which specifically includes three levels of monitoring:
[0085] Shared memory access layer, intercept all load and store operations involving global variables and heap memory, record the target address, operation type (read or write), operation value and thread ID at the time of access; synchronization operation layer, monitor acquire or release of lock (pthread_mutex_t), wait or post of semaphore (sem_t), signal or broadcast of condition variable (pthread_cond_t) operations, record the synchronization object address, operation type and return result; state transition layer, through the kernel thread scheduler hook function, capture the transition events of threads between running, blocked, runnable three states, record the transition time and trigger reason, such as waiting for input and output, lock acquisition failure.
[0086] Based on the above monitoring data, a feature vector is generated for each thread, including lock contention frequency, unit: times per millisecond; shared memory access density, unit: times per millisecond; state transition frequency, unit: times per ten milliseconds, wherein each parameter is calculated in real time through a 100ms sliding window. For example, if the thread has 8 lock contention, 120 shared memory access, and 3 state transitions in 100ms, the feature vector is [0.08, 1.2, 0.3].
[0087] S1.2, dynamically record the granularity switching rule, and preset three feature vector threshold intervals. The recording granularity is automatically switched according to the interval to which the real-time feature vector of the thread belongs:
[0088] High contention area: when the lock contention frequency is greater than 0.05 and the shared memory access density is greater than 1.0, it is activated. At this time, the thread is in a high-frequency resource contention state, and instruction-level recording needs to be started: through a binary instrumentation tool such as DynamoRIO, the address, operation code and operand of each instruction executed by the thread are captured, and for instructions involving shared resources, such as mov instructions accessing global variables and atomic operation instructions, additional register states are recorded, such as x86's eax or ebx, ARM's x0 or x1. The recording granularity is accurate to the instruction cycle, ensuring that the key track of the race condition is not missed.
[0089] Low interaction area: when the lock contention frequency and the shared memory access density are both 0, and the state transition frequency is less than 0.1 and remains above 10ms, it is activated. At this time, the thread is in an independent execution state, such as processing local variable calculation logic, and switches to state-level recording, that is, only thread state snapshots are recorded at certain times, and the intermediate instruction stream is completely ignored.
[0090] Transition area: the state outside the above two intervals, start event triggered recording, system maintains instruction buffer, can accommodate 100 instructions, continuously cache thread execution instructions but not persistent storage; when detecting shared resource access events, such as first reading global variables, immediately record the first 50 instructions and the last 200 instructions in the buffer for a total of 250 instructions, and activate instruction-level recording for 10ms, then automatically restore the buffer mode.
[0091] The granularity switching is realized through the cooperation of the kernel mode and the user mode. When the kernel mode hook detects that the thread feature vector is out of bounds, it notifies the user mode recording module through a signal such as SIGUSR1. The module switches the mode after completing the recording of the current instruction cycle, ensuring that there is no data loss in the switching process.
[0092] S1.3, pre-marking of dependency chain, establishing a dependency relationship chain for all recorded events according to the thread, resource and time triplets, and the specific rules are:
[0093] When thread A releases resource R, such as unlocking mutex, and thread B acquires resource R after that, it is marked as direct dependency from A to B, and the dependency type is synchronous dependency and the time difference is the difference between the time when B acquires and the time when A releases; when thread A writes to address M, and thread B reads address M after that, and no other thread modifies M during this period, it is marked as direct dependency from A to B, and the type is data dependency and the time difference; indirect dependency is formed by direct dependency transmission, such as A to B and B to C, then there is A to C, only direct dependency is stored to reduce redundancy.
[0094] The dependency chain is stored in a linked list structure, and each node contains the source thread ID, target thread ID, dependency type, resource identifier and time difference, which provides basic data for subsequent parallel scheduling in the replay phase.
[0095] It breaks through the traditional fixed granularity recording mode, realizes dynamic regulation of recording accuracy through real-time behavior analysis, reduces the data volume in the recording stage by 60% to 70%; the pre-marking of the dependency chain provides a deterministic guarantee for parallel replay, solving the core problem of how to ensure consistency with the original track in parallel execution.
[0096] S2, unified representation and mapping of cross-architecture events, through an abstract event model to shield the hardware differences between x86 and ARM, to realize the core logic to support both architectures and solve the cross-platform timestamp comparability problem.
[0097] S2.1, architecture-independent event model definition, an abstract model containing a basic event set and extended attributes, mapping architecture-dependent operations into a unified format.
[0098] The basic event set covers all operations that may affect inter-thread interaction, including:
[0099] The atomic operation uniformly represents the x86 lock cmpxchg, xadd and ARM ldrex, strex, cas instructions, and the format is: ATOMIC, operation type, target address, old value, new value, where the operation type includes compare and exchange, increment or decrement, load or store, etc.
[0100] The synchronization operation uniformly represents the x86 futex system call for implementing locks and the ARM sem_wait system call, and the format is: SYNC, operation type, synchronization object address, result, and the operation type includes acquire, release, wait and wake up, etc.
[0101] Memory barrier unified representation of x86 full barrier mfence, read barrier lfence, write barrier sfence and ARM data memory barrier dmb, data synchronization barrier dsb, instruction synchronization barrier isb, format: BARRIER, barrier type, scope, where barrier type is mapped to read, write, full three categories, and scope is marked as intra-process or cross-process.
[0102] Extended attributes attach architecture-specific metadata to each event, such as the segment register impact of x86 events, such as whether the fs segment participates in address calculation, the condition execution flags of ARM events, such as whether the C flag affects instruction execution, these attributes do not affect cross-platform event comparison, but are used for accurate instruction mapping when replaying.
[0103] S2.2, instruction set adaptation layer design, the adaptation layer is an intermediate layer between the abstract event model and the hardware instruction, responsible for instruction capture and event conversion, and special adaptation logic is designed for different architectures.
[0104] x86 platform adaptation: intercept each instruction through the INS_AddInstrumentFunction callback function of the Pin tool, parse the opcode and operand of the atomic operation instruction containing the lock prefix, such as converting lock add dword ptr[eax], 1 into ATOMIC, increment, eax value, old value, old value plus 1; for memory barrier instructions, identify instructions such as mfence through instruction mnemonic, and directly map them to the corresponding barrier type; use the PIN_GetContextRegval function to get the register state before and after instruction execution, and store it as an extended attribute.
[0105] ARM platform adaptation: monitor the target process through the ptrace system call, and when detecting atomic instructions such as memory exclusive load ldxr, exclusive store stxr, etc., get the memory operation value through PTRACE_PEEKDATA, and convert stxr w2, w1, [x0] into ATOMIC, store-exclusive, x0 value, old value, w1 value; for memory barrier instructions such as dmb ish, parse the domain parameters of the instruction, such as ish representing inner shareable, which is mapped to full barrier and intra-process scope; get the ARM register group through PTRACE_GETREGSET, such as the state of x0 to x30, and extract the NZCV bits of the condition flag CPSR register as an extended attribute.
[0106] The abstract events output by the adaptation layer are serialized in the Protocol Buffers format to ensure the efficiency of storage and transmission.
[0107] S2.3, Timestamp normalization, two-level calibration mechanism is designed to solve the hardware difference between x86's TSC (Time Stamp Counter) and ARM's CNTVCT (Counter Virtual Count), i.e. TSC frequency changes dynamically with CPU turbo, while CNTVCT has a fixed frequency.
[0108] Record phase calibration: a calibration event is triggered every 100 ms, and the hardware clock (TSC or CNTVCT) and the system monotonic clock (CLOCK_MONOTONIC) are read at the same time. The difference between the hardware clock value and the system clock value multiplied by the hardware frequency is calculated. The hardware frequency is obtained through system calls, such as x86's cpuid instruction and ARM's cntfrq_el0 register. The difference and the corresponding system time of all calibration points are stored as a calibration curve.
[0109] Playback phase conversion: during playback, for the recorded hardware timestamp T_hw, the corresponding difference Δ is obtained by interpolation of the calibration curve, and then converted to normalized timestamp T_norm = (T_hw - Δ) / hardware frequency, ensuring that the timestamps of x86 and ARM platforms are comparable on the same time scale.
[0110] By abstracting the event model, the architecture difference is isolated in the adaptation layer, and the core logic code reuse rate is improved to more than 90%. The timestamp normalization mechanism solves the fundamental obstacle of cross-platform event timing comparison, making the replay logic not need to perceive the characteristics of the underlying hardware clock.
[0111] S3, Parallel replay based on dependency partitioning, through fine-grained dependency analysis and multi-core collaboration mechanism, the hardware computing power is maximized while ensuring determinism. The core is to divide the thread execution process into parallelizable segments and serializable segments, and to ensure the accuracy of the connection between the two segments through an efficient synchronization mechanism.
[0112] S3.1, Dynamic partitioning of dependency graph, the construction and partitioning of dependency graph is the basis of parallel replay, directly affecting the replay efficiency and determinism.
[0113] S3.1.1, Dependency graph construction.
[0114] With the dependency chain generated in the recording phase as input, a multi-level directed graph containing thread nodes, event nodes and dependency edges is constructed. Among them, the thread node contains thread ID and life cycle, and the life cycle is represented by start timestamp and end timestamp; the event node is subdivided by type into shared memory write, lock release, lock acquisition, etc., and each event node is associated with its own thread, occurrence timestamp and resource identifier, such as memory address or lock ID; the dependency edge is divided into data dependency, control dependency and timing dependency, such as thread B reading the data written by thread A, control dependency such as thread B waiting for thread A to release the lock, and timing dependency such as thread A and B without direct interaction but needing to maintain the execution order.
[0115] For example, thread A writes to address M at time T1, thread B reads M at time T2 (T2>T1), and no other thread modifies M during this period, then a data dependency edge A to B is generated, and the weight is the difference between T2 and T1; thread C releases lock L at T3, and thread D acquires L at T4 (T4>T3), then a control dependency edge C to D is generated, and the weight is the difference between T4 and T3.
[0116] S3.1.2, loop dependency detection and resolution. There may be a loop dependency in a complex program, such as A to B to C to A, which directly leads to partition failure. Through depth-first search, a loop execution resolution algorithm is detected for each loop: select the smallest weight dependency edge in the loop, such as the weight of A to B is 5ms, which is the smallest value in the loop, and mark it as a forced serial edge, and when partitioning, the related threads are included in the same partition to ensure that the threads in the loop are executed in series, and other dependency edges can still participate in parallel partitioning.
[0117] S3.2, multi-core cooperative replay strategy, after partitioning, the determinacy of parallel execution needs to be ensured through fine-grained core binding, progress coordination and synchronization mechanism.
[0118] S3.2.1, core binding and resource isolation, through the cpu_set_t data structure, each partition is bound to a dedicated CPU core, and the binding strategy follows the principle of physical core priority to avoid resource competition caused by hyper-threading. For example, on an 8-core CPU, partition 0 is bound to core 0, partition 1 is bound to core 1, and so on. At the same time, through prctl, the threads in the partition are set with a dedicated name, such as replay-p0-t1 representing thread 1 of partition 0, which is convenient for debugging and performance analysis.
[0119] In order to avoid cache interference, each partition cleans up the L1 and L2 caches of the corresponding core through the x86 clflush instruction or the ARM dc civac instruction before replaying, and locks the cache line of the shared memory region through the mlock system call, to ensure the stability of memory access delay during replay.
[0120] S3.2.2, Parallel advance and progress tracking, each thread within a partition advances autonomously according to the normalized timestamp of the record, maintaining a progress counter for each thread recording the number of events executed and a virtual clock to simulate execution time. When a thread executes, the counter is updated each time an event is completed.
[0121] The partition manager monitors the counters and virtual clocks of all threads in real time through a progress table in shared memory, and when the virtual clock of a thread falls behind the expected value by more than 10%, triggers the accelerated execution mode until the progress is caught up.
[0122] S3.2.3, Synchronization point barrier mechanism, when a thread executes to the start of a dependent edge, such as releasing a lock, triggers a synchronization notification process: the thread writes the current event index and virtual clock to the synchronization notification area in shared memory, and wakes up the thread waiting for the event through futex_wake; the thread waiting for the event, such as the thread waiting for the lock, is blocked in the synchronization notification area through futex_wait before executing to the end of the dependent edge until the notification is detected; after being awakened, the thread calculates the difference between the current virtual clock and the virtual clock in the notification, and if it is less than the recorded time difference, such as T2-T1=5ms, it compensates for the remaining time through busy-wait nanosleep to ensure consistency with the original execution timing; if it is greater than the recorded time difference, it is determined to be a replay anomaly, triggering a debugging interrupt.
[0123] To avoid synchronization overhead, for weakly dependent events such as dependencies with a time difference greater than 100ms, a delayed notification strategy is used, the notifier first records the event, and then sends a notification when the virtual clock approaches the expected time of the dependent party, reducing the waiting time of the dependent party.
[0124] S3.3, Fast instruction stream verification. Existing instruction-by-instruction verification can cause a sharp drop in replay speed, and this embodiment maximizes performance while ensuring correctness through hierarchical verification and adaptive sampling.
[0125] S3.3.1, Hierarchical design of detection points, defining three levels of detection points to cover different granularities of state verification:
[0126] L1 level fine-grained detection point, generated once every 100 instructions involving shared resources, recording the values of key registers and the operation sequence hash of the last 10 shared memory instructions;
[0127] L2 level medium-grained detection point, generated once every time a synchronization operation is completed, such as lock acquisition or release, recording all general-purpose register values of the thread, the hash of the top 20 elements of the stack, and the list of synchronization objects currently held;
[0128] L3 level coarse-grained detection point, generated once every 10ms, recording the global state of the process.
[0129] In the recording phase, the generation and storage of the three-level checkpoints are completed through the aio_write of asynchronous IO, avoiding blocking the main thread execution.
[0130] S3.3.2, adaptive adjustment of verification strategy, dynamically adjust the verification strength according to the program stability during replay:
[0131] When the continuous 5 checkpoints are verified, the verification interval is automatically extended, such as L2 level verification from every 1 synchronization operation to every 3 times.
[0132] S3.3.3, inconsistent processing and debugging support.
[0133] If the verification finds that the state is inconsistent, the system performs a three-level positioning process: fast positioning, determine the 10ms time window of abnormal occurrence through L3 level checkpoints; Fine positioning, traverse L2 level checkpoints in the window to narrow down the exception to a specific synchronization operation; Instruction level positioning, enable instruction by instruction comparison before and after the synchronization operation, and finally locate the specific instruction that causes the inconsistency.
[0134] At the same time, the system automatically saves the memory snapshot and register state at the time of the exception, generates a core file for debugging tools to analyze, and the debugging tools such as GDB.
[0135] Through the circular dependency resolution and load balancing partition algorithm, the parallelization problem in complex dependency scenarios is solved; Three-level checkpoints and adaptive verification strategy realize the dynamic balance of precision and performance; The time compensation mechanism of the synchronization point barrier ensures the time sequence determinacy of parallel execution, and the replay speed is improved by 3 to 5 times compared with the single-threaded scheme.
[0136] S4, snapshot management of on-demand state recovery, through hierarchical storage and incremental update strategy, solves the problem of large storage overhead and slow recovery speed of traditional full snapshot, while ensuring the accuracy of state recovery. Its core is to store state data according to reuse frequency and modification frequency, and only load and assemble the required state when necessary.
[0137] S4.1, hierarchical snapshot architecture. Based on the spatial and temporal locality of program state, the state is divided into three levels, and each level adopts differentiated storage strategy.
[0138] S4.1.1, global baseline snapshot, contains the complete state at the initial stage of process startup, as the benchmark for all subsequent recovery operations.
[0139] Address space layout: get all memory region's virtual address range, read-write-execute permission, mapping type (anonymous or file) and corresponding physical page frame number by parsing / proc / self / maps, which can be assisted by mincore system call; Static data and code segment: the complete data of all read-only memory regions such as.text,.rodata segment, which are stored in the direct memory mapping MAP_SHARED mode to avoid repeated copying; Global variable initialization state: the initial value of global variables in.data and.bss segments, which are stored in memory page granularity; System resource handle: open file descriptor, network socket, signal processing function registration information, etc., get file status flag by fcntl, get socket parameter by getsockopt; Hardware state: CPU state register such as x86's CR0 / CR3, ARM's SCTLR_EL1, floating point unit FPU initialization state, etc., which is read by kernel module.
[0140] Global baseline snapshot is generated only once before the first execution of user code after program startup, such as at the main function entry, and is stored as a multi-segment file including code segment, data segment, resource segment, with the total size controlled within 1.2 times of the initial memory occupancy of the program.
[0141] S4.1.2, thread private snapshot, for the state record of thread exclusive resources, incremental update and version control strategy is adopted: initial snapshot, generated when the thread is created, contains complete stack memory from stack bottom to initial stack top, all general registers and special registers such as x86's RIP, RSP, ARM's PC, SP, and initial data of TLS region; Incremental update, when the thread is woken up from blocking state each time, only the modified memory page in the stack is recorded, the dirty page is marked when page fault is triggered by setting write monitoring through mprotect, the changed register value, and the modified variable in TLS; Version chain, such as the snapshot version of thread T1 at the time of creation is V0 to the version V1 at the first wake-up and the version V2 at the second wake-up, each version only stores the difference with the previous version.
[0142] To reduce storage overhead, thread private snapshot adopts LZ4 algorithm compression, with compression ratio up to 3:1 or more, and fast decompression speed.
[0143] S4.1.3, incremental difference log, for the modification record of shared memory region, global variable, heap shared area, shared library data segment, address index and timeline storage structure are adopted.
[0144] The memory page index table establishes a hash table in units of memory pages, the key is the page start address, and the value is the difference log linked list of the page; the difference record format includes timestamp, offset, old value, new value and operation thread ID, wherein the offset is the address within the page, such as 0 to 4095 bytes, and the length of the value is automatically adapted according to the operation type; the merging optimization adopts a range merging strategy to record only the first old value and the last new value for continuous modification of the same address, such as thread loop increment global variable, and the intermediate steps are marked as fast path, which is directly skipped during replay.
[0145] The difference log is written into a ring buffer in timestamp order, and is automatically written to disk when full, ensuring that the recording process is not blocked.
[0146] S4.2, on-demand snapshot assembly strategy, when replaying, the state at time T is recovered, and the data in the three-level storage needs to be efficiently integrated, the core challenge is how to quickly locate and apply the required modifications, and the specific process is as follows:
[0147] S4.2.1, shared memory recovery, baseline loading maps the code segment and data segment of the global baseline snapshot to the same virtual address as the recording stage through mmap, adopts MAP_FIXED to force address matching, and turns off address space layout randomization (ASLR) to ensure address consistency; page-level filtering, traversing the memory page index table, filtering out all pages with timestamp not greater than T and belonging to the shared memory region to generate a list of pages to be modified; incremental application, for each page in the list, apply the difference record in ascending order of timestamp, starting from the baseline page data, and replacing the old value with the new value at the offset, until all difference records of the page are processed; verification and confirmation, calculating the CRC32 checksum of the recovered shared memory region, and comparing it with the checksum detected at time T in the recording stage, if consistent, proceed to the next step, otherwise trigger page-level detailed check.
[0148] To speed up the recovery of large memory programs, the system adopts preloading and background application mode: priority is given to loading the memory pages required by the current execution, and other pages are recovered asynchronously in the background thread, and page fault interrupt is triggered when accessing unrecovered pages to complete them.
[0149] S4.2.2, thread state recovery, including: snapshot selection, for each thread, find the snapshot version with timestamp no greater than T and closest to T in its version chain by binary search, such as V2 version of thread T1 with timestamp 95ms, T = 100ms, then select V2; basic recovery, load the stack snapshot, register state and TLS data of the version, set thread local storage through x86 pthread_setthreadarea or ARM set_tls; incremental execution, from the snapshot version timestamp to T time, execute the private instruction stream of the thread, at this time there is no need to check, only need to ensure that the register and stack state are updated according to the recorded track; consistency check, compare the program counter of the thread with the L2 level checkpoint record value after recovery, and confirm the success of the recovery if they are consistent.
[0150] For the threads in the blocking state, additionally recover the blocking reason, such as the lock address, semaphore value, to ensure that the scheduling behavior during replay is consistent with the recording phase.
[0151] S4.2.3, system resource state synchronization, when restoring file descriptors, sockets and other system resources, interaction with the operating system is needed, including: for files, open the file with the same path, ensure uniqueness through the recorded inode number, call lseek to set the same offset as the snapshot, and fcntl to restore the file state flags such as O_RDWR, O_NONBLOCK; for network sockets, create the same type of socket such as TCP or UDP, set the same SO_REUSEADDR option, restore the connection state such as connected or listening, but do not actually establish a network connection, and return the recorded data through the simulation of recv or send functions; for signal processing, re-register the signal processing function consistent with the snapshot through sigaction, and restore the signal mask sigprocmask.
[0152] The restoration of system resources is achieved through simulation and interception, avoiding actual impact on external systems such as file systems and networks.
[0153] S4.2.3, exception handling and rollback, if inconsistency occurs during the recovery process, such as memory page CRC mismatch, the system performs a quick rollback, including: releasing the current restored memory page through munmap, and reloading the corresponding page of the global baseline snapshot; enable per-record check mode to reapply the differences, check the intermediate state after each step, and locate the error difference record; if it is an error in the recording phase, mark the difference record as invalid, use the previous valid record instead, and record the error log.
[0154] The three-level hierarchical snapshot realizes on-demand storage of state data, and reduces storage overhead by more than 90% compared with full snapshot; the incremental application based on memory page and the preloading mechanism shorten the state recovery time from milliseconds to microseconds; the simulation and interception recovery of system resources ensure the isolation of the replay environment, avoiding interference with external systems.
[0155] The recording overhead of the present application is significantly reduced, the adaptive recording mechanism controls the performance loss of the program running time to 1.2 to 2 times by dynamically adjusting the granularity, and can meet the recording needs of high-throughput server programs; the replay speed is greatly improved, and the parallel replay engine cooperates with the lightweight verification mechanism to make the replay speed more than 80% of the original execution, greatly shortening the debugging cycle; the cross-platform compatibility is broken through, the unified event model and the timestamp normalization mechanism realize the seamless migration of x86 and ARM platforms, the core code reuse rate is more than 90%, and the development and maintenance cost is reduced; the precision of race reproduction, the fine-grained recording of key events and the dependence chain order preservation mechanism ensure the success rate of race condition reproduction to be 100%, solving the industry pain point that race is difficult to reproduce in complex scenarios.
[0156] To sum up, the above is only a preferred embodiment of the present application, and is not used to limit the protection scope of the present application. Any modification, equivalent replacement, improvement, etc. made within the spirit and principles of the present application shall be included in the protection scope of the present application.
Claims
1. A performance optimization method for reverse debugging deterministic replay, characterized in that, Specifically, the following steps are included: Step 1: Debug and execute the target program in the first target architecture to obtain the lock contention frequency, shared memory access density, and state transition frequency of the thread; if the lock contention frequency and shared memory access density are both greater than the corresponding threshold, then start instruction-level recording; if the lock contention frequency and shared memory access density are both zero, and the state transition frequency is less than the threshold, then start state-level recording; otherwise, start event-triggered recording. The first record is formed; Step 2: Determine the dependencies between threads based on the first record, and establish a thread dependency chain, including source thread ID, destination thread ID, dependency type, resource identifier, and time difference. The time difference is the difference in time between the source thread and the destination thread performing operations on the resource. Construct a dependency graph containing thread nodes, event nodes, and dependency edges, label the dependency edges with weights, and divide the dependency graph into multiple replay partitions. Step 3: In the second target architecture, bind the CPU core to the replay partition and execute the replay in parallel. The thread maintains a progress counter and a virtual clock. The progress counter records the number of events that have been executed, and the virtual clock simulates the execution time. After the event is executed, update the progress counter and the virtual clock. If the virtual clock of the thread is greater than the recorded value in the first record, the accelerated execution mode is triggered until the virtual clock is no greater than the recorded value. When the thread executes to the starting point of the dependent edge, the synchronization notification process is triggered to complete the replay.
2. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, Events under different architectures are described using basic attributes and extended attributes. The basic attributes include atomic operations, synchronization operations, and memory barriers, while the extended attributes are metadata used to identify the characteristics of different architectures. In the first target architecture, the instructions belonging to the basic event set are identified from the intercepted instructions. The opcode, operands, registers or memory addresses of the instructions are parsed and represented as basic attributes. The metadata of the architecture to which the instructions belong is extracted as extended attributes. Then, the event format containing basic attributes and extended attributes is serialized.
3. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, The weight of the dependent edge is the absolute value of the time difference.
4. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, The method of dividing the dependency graph into multiple replay partitions is as follows: Step 3.1: Traverse the thread nodes in the dependency graph and add all thread nodes without prerequisite dependencies to the candidate pool as starting candidates for partition construction. Step 3.2: Calculate the parallel gain of each thread node in the candidate pool, and select the thread with the highest parallel gain to be added to the replay partition to be built as the core thread. The parallel gain is the ratio of the thread's independent execution time to the total number of dependency edges associated with that thread. Step 3.3: Based on the core thread of the replay partition, traverse the remaining thread nodes and gradually add threads that have no dependency relationship with the threads in the replay partition to the replay partition until the replay partition can no longer be expanded or the expected execution time reaches the average load threshold, and complete the construction of the current replay partition. The average load threshold is the ratio of the total execution time to the number of target partitions. Step 3.4: Create new replay partitions to be built. Execute step 3.1 until all thread nodes are assigned to the corresponding replay partitions, forming the initial partitioning results. Step 3.5: For the initial partitioning results, migrate thread nodes between adjacent replay partitions. Calculate the partition load balance after each migration and retain the swap results that increase the load balance. The partition load balance is the ratio of the standard deviation to the average execution time of each partition.
5. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, After the event is executed, the progress counter and virtual clock are updated. The virtual clock is set to the sum of the timestamp of the previous event and the execution time of the event, where the execution time of the event is the measured value in the first record.
6. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, The synchronization notification process includes: The thread writes the current event index and virtual clock into the synchronization notification area of shared memory, and sends a wake-up notification to the threads waiting for the event. The thread is blocked in the synchronization notification area before it reaches the endpoint of the dependent edge, until it receives the wake-up notification. After the thread is woken up, it calculates the difference between the current virtual clock and the virtual clock in the wake-up notification. If the difference is less than the recorded time difference, it compensates for the remaining time to maintain the original timing. If the difference is greater than the recorded time difference, it determines that the replay is abnormal and triggers a debug interrupt.
7. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, A layered verification and adaptive sampling approach is used to perform instruction verification during playback, including: All fine-grained L1 level detection points are enabled in the initial stage of playback, only medium-grained L2 level detection points are executed in the stabilization stage, and L1 level detection points are re-enabled in the final stage. If a set number of consecutive detection points pass the verification, the verification interval is extended; otherwise, the time window for the anomaly to occur is determined by the coarse-grained L3 level detection points. Within the time window, the L2 level detection points are traversed to locate the synchronous operation that caused the anomaly. Before and after the synchronous operation, instruction-by-instruction comparison is enabled to finally locate the instruction that caused the inconsistency.
8. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, Establish snapshot management based on tiered storage and incremental update strategies, specifically as follows: In the first target architecture, the address space layout is obtained before the target program is executed for the first time after it starts. Static data, code segments, initial states of global variables, system resource handles and hardware status registers are read to form a global baseline snapshot. The global baseline snapshot is stored as a multi-segment file in a way that separates code segments, data segments and resource segments. When a thread is created, a thread-private snapshot is formed by recording the complete stack memory, registers, and initial data of the TLS region. When a thread is awakened from blocking, the thread-private snapshot is updated only with the modified memory pages, changed register values, and modified variables in the TLS. A thread-private snapshot version chain is formed based on the update timestamp to store the differences between versions. A hash table is built for each memory page, with the key being the starting address of the page and the value being the difference log of that page. The difference record in the difference log includes the timestamp, offset, old value, new value, and the operating thread ID. The offset is the address within the page. In the second target architecture, when restoring the program state at a specified time T, shared memory is restored based on the global baseline snapshot, thread state is restored based on the thread-private snapshot, system resource state is synchronized through interaction with the operating system, and exception handling and rollback are performed when inconsistencies occur during the restoration process.
9. The performance optimization method for reverse debugging deterministic replay according to claim 8, characterized in that, The process of restoring shared memory based on the global baseline snapshot includes: mapping the global baseline snapshot to the virtual address of the recording phase, traversing the memory page index table, filtering shared memory pages with timestamps no greater than T to generate a list of pages to be modified; for each page in the list of pages to be modified, sorting the page application difference records in ascending order according to the timestamp, and replacing the old value at the offset with the new value sequentially starting from the baseline page data, until all difference records of the page have been processed. The process of restoring the thread state based on the thread's private snapshot includes: searching the thread version chain for each thread, selecting the snapshot version whose timestamp is not greater than T and whose absolute difference from T is the smallest, loading the stack, register state and TLS data of the snapshot, executing the thread's private instruction stream from the snapshot timestamp to time T, and updating the register and stack state according to the records.
10. The performance optimization method for reverse debugging deterministic replay according to claim 1, characterized in that, The thread node contains a thread ID and lifecycle, the event node contains shared memory write, lock release and lock acquisition events, the event node is associated with its own thread, the time of event occurrence and resources, the dependency edge includes data dependency, control dependency and time sequence dependency types, and the thread lifecycle refers to the period from the thread start time to the thread termination time.
Citation Information
Patent Citations
Program tracing for time travel debugging and analysis
CN109643273A
Kernel data race detection method based on static program analysis and fuzzy testing
CN114428733A