Identify data inconsistencies and data races based on historical debug traces
Through historical debugging and tracking technology, data inconsistency and contention in software code are automatically identified and reported, debugging complexity problems in the existing technology are solved, and debugging efficiency and code quality are improved.
Patent Information
- Application Number
- CN202080032369.4
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Priority Date
- 2019-04-30
- Filing Date
- 2020-04-01
- Publication Date
- 2025-08-19
- Estimated Expiration
- 2040-04-01
AI Technical Summary
The prior art is difficult to automatically identify and report difficult-to-reproduce data inconsistency and data contention in software code, resulting in complex and inefficient debugging processes.
Using historical debugging and tracing technology, automatically identify and report potential data inconsistencies and data contention through the previous execution of replay threads, the debugging components are used to analyze the tracking data, providing automatic identification and visual indication.
It improves the speed and efficiency of the debugging process, can automatically identify data inconsistencies and contention, simplifies the debugging process, and improves the code quality.
Smart Images

Figure CN113785284B_ABST
Abstract
Description
Technical Field
[0001] Embodiments of the present disclosure relate to identifying data inconsistencies and data races based on historical debug traces. Background Art
[0002] Tracking and correcting errors in software code (commonly referred to as "debugging" code) is a core activity in software development. Software errors can lead to many undesirable runtime behaviors (such as execution crashes, runtime anomalies, slow execution performance, incorrect data results, data corruption, etc.). Many difficult-to-reproduce software errors can lead to data inconsistencies during code execution. Some developer errors that lead to these errors include forgetting to initialize variables, or introducing race conditions, in which various threads modify data without using thread synchronization / locking mechanisms to correctly protect the data (e.g., by correctly using mutexes, events, semaphores, spin locks, queue spin locks, etc.). During code execution, these data inconsistency errors manifest as reading a value in memory in the context of a specific thread, while the thread itself does not write a given value to memory. In the example of uninitialized memory, a thread reads from memory that was not previously written. In the case of a race condition, a thread reads a value that it had not previously seen in memory, or a value that it had not written to memory.
[0003] One method developers have used to debug code is to use a "live" debugger. Typically, a live debugger attaches to the execution of a live process and enables the developer to monitor and direct the forward execution of the process. For example, a live debugger can enable the developer to set breakpoints that halt program execution when it reaches a specific instruction, set watchpoints that halt program execution when it accesses a specific memory address, single-step through lines of code as it executes, and so on.
[0004] Emerging forms of diagnostic tools enable "historical" debugging (also known as "time travel" or "reverse" debugging), in which at least portions of the execution of program thread(s) are recorded / traced into one or more trace files (i.e., traces). Using some tracing techniques, the traces can contain very high fidelity "bit accurate" historical trace data, which enables the recorded portion(s) of the traced thread(s) to be virtually "replayed" with extremely high fidelity - even down to the granularity of a single instruction (e.g., machine code instruction, intermediate language code instruction, etc.). Thus, using bit accurate trace data, "historical," "time travel," or "reverse" debuggers enable a developer to monitor and direct not only forward simulation of the traced code (e.g., via breakpoints, watchpoints, single stepping, etc.), but also reverse simulation of the traced code (e.g., via reverse breakpoints, reverse watchpoints, reverse single stepping, etc.). Thus, a developer can monitor and direct the execution of any portion of a program prior to tracing. Summary of the Invention
[0005] At least some embodiments described herein identify and report potential data inconsistencies and / or potential data races based on historical debug tracing. For example, embodiments may include identifying and reporting actual data inconsistencies that occurred during a previous execution of a program and captured during tracing. Thus, these embodiments are able to identify when a read from uninitialized memory or when a data race condition actually occurs and is captured during tracing. In these embodiments, the execution of a thread is replayed from a historical trace. During this replay, an influx of a memory cell is observed. If this is inconsistent with a previous value of the memory cell known to the thread (e.g., because the thread does not know the value of the memory cell, or the observed value is different from the known previous value), then a data inconsistency is observed.
[0006] Other embodiments may include identifying situations where a data race condition may occur even if no actual data inconsistency is captured during tracing. Thus, these embodiments may identify situations where a data race condition may occur even if no actual data race condition is captured during tracing. In these embodiments, the execution of multiple threads is replayed from a historical trace. When a thread synchronization mechanism is active on a first thread, memory accesses by the first thread are traced. If the second thread makes a memory access to a traced memory location while the thread synchronization mechanism is not active on the second thread, then a potential data race has been observed.
[0007] Some embodiments include methods, systems, and computer program products for indicating a data inconsistency observed during a previous execution of a thread. These embodiments include replaying the previous execution of the thread based on a trace representing the previous execution of the thread. These embodiments also include observing an inflow of a value to a memory unit based on replaying the previous execution of the thread. These embodiments also include determining that a value of the memory unit observed from the inflow is inconsistent with a previous value of the memory unit known to the thread. These embodiments also include initiating an indication of the data inconsistency based at least on the value of the memory unit observed from the inflow being consistent with the previous value of the memory unit.
[0008] Other embodiments include methods, systems, and computer program products for indicating a potential data race based on a trace of a previous thread execution. These embodiments include replaying a previous execution of the plurality of threads based on a trace representing the previous execution of the plurality of threads. These embodiments also include identifying, based on the replaying the previous execution of the plurality of threads, activation of a thread synchronization mechanism during a previous execution of a first thread of the plurality of threads. These embodiments also include identifying, based on the replaying the previous execution of the plurality of threads and based on the activation of the thread synchronization mechanism, at least one memory unit accessed by the first thread while the thread synchronization mechanism was effective on the first thread. These embodiments also include identifying, based on the replaying the previous execution of the plurality of threads, memory accesses to the at least one memory unit during a previous execution of a second thread of the plurality of threads without the second thread utilizing the thread synchronization mechanism. These embodiments also include initiating an indication of a potential data race associated with the at least one memory unit based on identifying the memory accesses.
[0009] This Summary is provided to introduce a selection of concepts in a simplified form that are further described below in the Detailed Description. This Summary is not intended to identify key features or essential features of the claimed subject matter, nor is it intended to be used as an aid in determining the scope of the claimed subject matter. BRIEF DESCRIPTION OF THE DRAWINGS
[0010] To illustrate the manner in which the above and other advantages and features of the present invention can be obtained, a more particular description of the invention briefly described above will be drawn by reference to specific embodiments thereof that are illustrated in the accompanying drawings. Understanding that these drawings depict only typical embodiments of the invention and are therefore not to be considered limiting of its scope, the invention will be described and explained with additional specificity and detail through the use of the accompanying drawings, in which:
[0011] Figure 1A An example computing environment is shown that facilitates identifying and reporting potential data inconsistencies and / or potential data races based on historical debug traces;
[0012] Figure 1B Shown Figure 1A Additional details of debugging;
[0013] Figure 2 Shown in which Figure 1A An example of a computing environment being networked with one or more other computer systems;
[0014] Figure 3 An example of a historical debug trace is shown;
[0015] Figure 4AAn example timing diagram is shown including two timelines corresponding to the execution of two threads, and a timeline illustrating accesses of memory units by these threads, including reads from memory that has not been initialized and data inconsistencies;
[0016] Figure 4B An example timing diagram is shown, the timing diagram including two timelines corresponding to the execution of two threads, and a timeline showing accesses of the threads to memory units, including the use of critical sections to protect access to the memory units;
[0017] Figure 4C shows an example timing diagram including two timelines corresponding to the execution of two threads, and a timeline showing accesses of memory units by the threads, including the use of critical sections to protect accesses to the memory units, and including potential data races on the memory units;
[0018] Figure 5 A flowchart illustrating an example method for indicating data inconsistencies observed during a previous execution of a thread; and
[0019] Figure 6 A flow chart of an example method for indicating potential data races based on a trace of previous thread execution is shown. DETAILED DESCRIPTION
[0020] At least some embodiments described herein identify and report potential data inconsistencies and / or potential data races based on historical debug tracing. For example, embodiments may include identifying and reporting actual data inconsistencies that occurred during a previous execution of a program and captured during a trace. Thus, these embodiments are able to identify when a read from uninitialized memory occurs or when a data race condition actually occurs and is captured during a trace. In these embodiments, the execution of a thread is replayed from a historical trace. During this replay, an influx of a memory cell is observed. If this is inconsistent with a previous value of the memory cell known to the thread (e.g., because the thread does not know the value of the memory cell, or the observed value is different from the known previous value), then a data inconsistency has been observed.
[0021] Other embodiments may include identifying situations where data races may occur, even if actual data inconsistencies are not captured during tracing. Thus, these embodiments may identify situations where data race conditions may occur, even if actual data race conditions are not captured during tracing. In these embodiments, execution of multiple threads is replayed from a historical trace.
[0022] In view of the disclosure herein, it will be appreciated that using historical debug traces to automatically identify data inconsistencies and data races can greatly improve the speed and effectiveness of the debugging process and can eliminate data inconsistencies and data races from application code. Furthermore, the embodiments described herein can provide unique debugging capabilities, such as automatically identifying / marking data inconsistencies and races in traces as trace index data and / or automatically identifying / marking data inconsistencies and races through user interface mechanisms.
[0023] Figure 1A An example computing environment 100a is shown that identifies and reports potential data inconsistencies and / or potential data races based on historical debug traces. As shown, the computing environment 100a may include or utilize a special-purpose or general-purpose computer system 101 that includes computer hardware such as, for example, one or more processors 102, system memory 103, persistent storage 104, and / or network device(s) 105, which are communicatively coupled using one or more communication buses 106.
[0024] Embodiments within the scope of the present invention may include physical and other computer-readable media for carrying or storing computer-executable instructions and / or data structures. Such computer-readable media can be any available media that can be accessed by a general-purpose or special-purpose computer system. Computer-readable media that store computer-executable instructions and / or data structures are computer storage media. Computer-readable media that carry computer-executable instructions and / or data structures are transmission media. Thus, by way of example and not limitation, embodiments of the present invention may include at least two distinct types of computer-readable media: computer storage media and transmission media.
[0025] Computer storage media are physical storage media (e.g., system memory 103 and / or persistent storage 104) that store computer-executable instructions and / or data structures. Physical storage media include computer hardware such as RAM, ROM, EEPROM, solid-state drives ("SSD"), flash memory, phase-change memory ("PCM"), optical disk storage, magnetic disk storage or other magnetic storage devices, or any other hardware storage device(s), which may be used to store program code in the form of computer-executable instructions or data structures that may be accessed and executed by a general-purpose or special-purpose computer system to implement the disclosed functionality of the present invention.
[0026] Transmission medium can comprise network and / or data link, and it can be used to carry the program code of computer executable instruction or data structure form and can be accessed by general or special computer system." network " is defined as one or more data links that can transmit electronic data between computer system and / or module and / or other electronic equipment.When information is passed to or provided to computer system by network or another communication connection (hard-wired, wireless or hard-wired or wireless combination), computer system can be considered as transmission medium by connection.The above combination also should be included in the scope of computer readable medium.
[0027] Further, upon reaching various computer system components, program code in the form of computer-executable instructions or data structures can be automatically transferred from transmission media to computer storage media (and vice versa). For example, computer-executable instructions or data structures received over a network or data link can be buffered in RAM within a network interface module (e.g., network device(s) 105) and then ultimately transferred to computer system RAM (e.g., system memory 103) and / or less volatile computer storage media at the computer system (e.g., persistent storage 104). Thus, it should be understood that computer storage media can be included in computer system components that also (or even primarily) utilize transmission media.
[0028] For example, computer-executable instructions include instructions and data that, when executed at one or more processors, cause a general-purpose computer system, a special-purpose computer system, or a special-purpose processing device to perform a certain function or group of functions. For example, computer-executable instructions may be machine code instructions (e.g., binary), intermediate format instructions (such as assembly language), or even source code.
[0029] Those skilled in the art will appreciate that the present invention can utilize many types of computer system configurations to practice in a network computing environment, including personal computers, desktop computers, laptop computers, message processors, handheld devices, multiprocessor systems, based on multiprocessor or programmable consumer electronics, network PCs, minicomputers, mainframe computers, mobile phones, PDAs, tablet computers, pagers, routers, switches etc. The present invention can also be put into practice in a distributed system environment, wherein both local and remote computer systems perform tasks by a network link (by a hardwired data link, a wireless data link or by a combination of a hardwired data link and a wireless data link). Like this, in a distributed system environment, a computer system can include multiple component computer systems. In a distributed system environment, a program module can be located in both local and remote memory storage devices.
[0030] Those skilled in the art will also appreciate that the present invention can be practiced in a cloud computing environment. A cloud computing environment can be distributed, although this is not required. When distributed, a cloud computing environment can be distributed internationally within an organization and / or have components owned across multiple organizations. In this description and the following claims, "cloud computing" is defined as a model for enabling on-demand network access to a shared pool of configurable computing resources (e.g., networks, servers, storage devices, applications, and services). The definition of "cloud computing" is not limited to any of the many other advantages that can be obtained from such a model when properly deployed.
[0031] Cloud computing models can be composed of various characteristics, such as on-demand self-service, broad network access, resource pooling, rapid elasticity, measured services, etc. Cloud computing models can also appear in the form of various service models, such as, for example, software as a service ("SaaS"), platform as a service ("PaaS"), and infrastructure as a service ("IaaS"). Cloud computing models can also be deployed using different deployment models, such as private cloud, community cloud, public cloud, hybrid cloud, etc.
[0032] Some embodiments (such as, cloud computing environment) can include a system that includes one or more hosts that are each capable of running one or more virtual machines. During operation, the virtual machines emulate an operational computing system, thereby supporting an operating system and possibly one or more other applications. In some embodiments, each host includes a hypervisor that emulates virtual resources for the virtual machines using physical resources abstracted from the virtual machine's view. The hypervisor also provides appropriate isolation between the virtual machines. Thus, from the perspective of any given virtual machine, the hypervisor provides the illusion that the virtual machine is interfacing with physical resources, even though the virtual machine is only interfacing with the appearance of physical resources (e.g., virtual resources). Examples of physical resources include processing power, memory, disk space, network bandwidth, media drives, etc.
[0033] like Figure 1AAs shown, each processor 102 may include, among other things, one or more processing units 107 (e.g., processor cores) and one or more caches 108. Each processing unit 107 loads and executes machine code instructions via cache 108. During execution of these machine code instructions at one or more execution units 107b, the instructions may use internal processor registers 107a as temporary storage locations and may read and write to various locations in system memory 103 via cache 108. Typically, cache 108 temporarily caches portions of system memory 103; for example, cache 108 may include a "code" portion that caches portions of system memory 103 that store application code and a "data" portion that caches portions of system memory 103 that store application runtime data. If a processing unit 107 requires data (e.g., code or application runtime data) that is not already stored in cache 108, the processing unit 107 may initiate a "cache miss," causing the required data to be retrieved from system memory 103—possibly while "evicting" some other data from cache 108 back to system memory 103.
[0034] As illustrated, persistent storage 104 can store computer-executable instructions and / or data structures representing executable software components; correspondingly, one or more portions of these computer-executable instructions and / or data structures can be loaded into system memory 103 during execution of the software at processor(s) 102. For example, persistent storage 104 is shown as storing computer-executable instructions and / or data structures corresponding to debug component 109, tracing component 110, emulation component 111, and application(s) 112. Persistent storage 104 can also store data, such as trace(s) 113 that record one or more executions of one or more of application(s) 112.
[0035] Typically, the debug component 109 takes as input one or more traces 113 and, based on analysis of these traces 113, identifies data inconsistencies and / or potential data races, which may correspond to reads of memory that has never been initialized and / or potential data race conditions. After identifying the data inconsistency and / or potential data race, the debug component 109 may initiate an indication of the inconsistency / race, such as by initiating the creation of trace index data and / or initiating a visual indication of the inconsistency / race at a debug user interface. Thus, Figure 1AThe debug component 109 and trace(s) 113 are shown loaded into the system memory (i.e., debug component 109' and trace(s) 113'), and the double-ended arrow between the debug component 109' and trace(s) 113' indicates that the debug component 109' can read from and possibly write to these trace(s) 113'; if data is written to the trace(s) 113', the data may also be persisted to the trace(s) 113 in the persistent storage 104.
[0036] As mentioned, the debug component 109 performs analysis on the trace(s) 113. In embodiments, the analysis may include one or both of static analysis and dynamic analysis. As used herein, static analysis includes the debug component 109 performing analysis based solely on data read from the trace(s) 113. On the other hand, dynamic analysis may use data generated / obtained from replay / simulation of the application(s) 112 based on these trace(s) 113. Thus, Figure 1A It is shown that simulation component 111 can also be loaded into system memory 103 (i.e., simulation component 111'), and application(s) 112 can be simulated by simulation component 111' (i.e., application(s) 112'). The double-ended arrow between debug component 109' and simulation component 111' indicates that debug component 109' can request trace simulation from simulation component 111', and that simulation component 111' can provide the results of the trace simulation to debug component 109'.
[0037] If present, the tracing component 110 may record or "trace" the execution of one or more of the application(s) 112 into the trace(s) 113. The tracing component 110 may record whether the execution of the application(s) 112 is executed directly on the processor(s) 102 or whether it is executed on the processor(s) 102 via a managed runtime. Figure 1A Also shown is that the tracing component 110 can be loaded into the system memory 103 (i.e., the tracing component 110'). The arrow between the tracing component 110' and the trace(s) 113' indicates that the tracing component 110' can record tracing data into the trace(s) 113' (which can then be persisted to the persistent storage 104 as the trace(s) 113).
[0038] Computer system 101 may additionally or alternatively receive one or more of trace(s) 113 from another computer system (eg, using network device(s) 105). For example, Figure 2 An example computing environment 200 is shown, wherein Figure 1AThe computer system 101 is connected to one or more other computer systems 202 (i.e., computer systems 202a through 202n) via one or more networks 201. As shown in example 200, each computer system 202 includes a tracing component 110 and application(s) 112. As such, the computer system 101 can receive one or more trace(s) 113 of previous execution(s) of one or more of the application(s) 112 at the computer system(s) 202 via the network(s) 201.
[0039] It is noted that while debug component 109, tracing component 110, and / or emulation component 111 may each be a separate component or application, they may alternatively be integrated into the same application (such as a debug suite), or may be integrated into another software component—such as an operating system component, a hypervisor, a cloud fabric, etc. Thus, those skilled in the art will also appreciate that the present invention may be practiced in a cloud computing environment of which computer system 101 is a part.
[0040] In an embodiment, debug component 109, tracing component 110, and / or emulation component 111 operate on trace(s) 113 that include high-fidelity, "bit-accurate" trace data representing a previous execution of one or more threads of application 112, and wherein the trace data enables any trace portion(s) of these thread(s) to be emulated (i.e., "replayed") by emulation component 111 down to the granularity of a single instruction (e.g., a machine code instruction, an intermediate language code instruction, etc.). As used herein, a "bit-accurate" trace is a trace that includes sufficient data to enable previously executed code of application 112 (e.g., at computer system 101 and / or at one or more computer systems in computer system 202) to be replayed via emulation by emulation component 111, such that emulation component 111 simulates the execution of the code in substantially the same manner as it was previously executed. Trace component 110 can use a variety of methods to record and represent bit-accurate trace data. Two different families of methods that provide high performance levels and reasonable trace sizes are now briefly summarized, but it is understood that embodiments herein create and operate on traces recorded using other methods. Additionally, optimization may be applied to any of these families of methods, which are not described herein for the sake of brevity.
[0041] The first family of methods is based on the recognition that processor instructions (including virtual machine "virtual processor" instructions) generally fall into one of three categories: (1) instructions identified as "non-deterministic," i.e., do not produce predictable outputs because their outputs are not fully determined by data in general purpose registers (e.g., register 107a) or caches (e.g., cache(s) 108), (2) deterministic instructions whose inputs do not depend on memory values (e.g., they depend only on processor register values or values defined in the code itself), and (3) deterministic instructions whose inputs depend on values read from memory. Thus, in some embodiments, storing sufficient state data to reproduce the execution of an instruction can be accomplished by solving the following problems: (1) how to record non-deterministic instructions that produce outputs that are not fully determined by their inputs, (2) how to reproduce the values of input registers to an instruction depending on registers, and (3) how to reproduce the values of input memory to an instruction depending on memory reads.
[0042] In some embodiments, a first method (or methods) records the execution of non-deterministic instructions into trace (or methods) 113, wherein the non-deterministic instructions generate outputs that are not completely determined by their inputs by storing side effects of the execution of such instructions into trace (or methods) 113. As used herein, "non-deterministic" instructions may include less common instructions that (i) generate non-deterministic outputs each time they are executed (e.g., RDTSC on Intel processors, which writes the number of processor cycles since the last processor reset into a register), (ii) may generate deterministic outputs but depend on inputs that are not tracked during trace recording (e.g., debug registers, timers, etc.), and / or (iii) generate processor-specific information (e.g., CPUID on Intel processors, which writes processor-specific data into registers). Storing side effects of the execution of such instructions may include, for example, storing register values and / or memory values that are changed by the execution of the instructions. In some architectures (e.g., from Intel), processor features (e.g., those found in Virtual Machine Extensions (VMX)) may be used to capture instructions for recording their side effects into trace (or methods) 113.
[0043] Solving how to reproduce the values of the input registers for deterministic instructions (e.g., whose inputs depend only on processor register values) is straightforward because they are the output of the execution of the previous instruction(s). Thus, the first method(s) for recording a trace can reduce the recording of the execution of an entire series of processor instructions to storing data that can be used to reproduce the register values at the beginning of the series. In embodiments, the trace(s) 113 may not even need to store records or intermediate register values for the specific instructions executed in the series. This is because the actual instructions are available from the application code itself. Thus, these instructions can be supplied with the recorded inputs (i.e., the recorded initial set of register values) during replay and executed in the same manner as they were during the trace.
[0044] Finally, the first method(s) for recording traces can address how to reproduce input memory values for deterministic instructions whose inputs depend on the values of memory consumed (i.e., read) by recording the memory values consumed by these instructions into trace(s) 113 - regardless of how the values read by the instructions were written to memory. In other words, some trace(s) 113 may record the values of memory reads, but not the values of memory writes. For example, although values may be written to memory by the current thread, another thread (including the kernel, for example as part of handling an interrupt), or a hardware device, all that is needed to fully replay the instructions of the thread that performed the reads are the values read by the thread's instructions. This is because the values read by the thread (not necessarily all the values written to memory) dictate how the thread executes.
[0045] A second family of methods for recording bit-accurate traces is based on the recognition that a processor (e.g., processor 102) forms a semi-closed or quasi-closed system. For example, once the data portion of a process (i.e., code data and runtime application data) is loaded into cache(s) 108, processor 102 can operate on its own—without any input—as a semi-closed or quasi-closed system for time bursts. Specifically, once cache(s) 108 are loaded with data, one or more of processing units 107 use the runtime data stored in the data portion of cache(s) and registers 107a to execute instructions from the code portion of cache(s) 108. When processing unit 107 needs some information to flow in (e.g., because it is executing, will execute, or may execute an instruction that accesses code or runtime data not in cache(s) 108), a "cache miss" occurs, and information is brought from system memory 103 into cache(s) 108. The processing unit 107 can then continue executing using the new information in the cache(s) 108 until new information is again brought into the cache(s) 108 (e.g., due to another cache miss or an uncached read). Thus, in the second series of methods, the tracing component 110 can record sufficient data to be able to reproduce the influx of information into the cache(s) 108 as the traced processing unit executes.
[0046] The debugging component 109, the tracing component 110, and / or the simulation component 111 also operate on trace(s) 113 created using other historical debugging techniques. For example, another class of historical debugging techniques (referred to herein as "branch trace debugging") relies on reconstructing at least a portion of an entity's execution based on working backward from a dump or snapshot (e.g., a thread's crash dump) that includes a processor branch trace (i.e., including a record of whether a branch was taken). These techniques start with the values (e.g., memory and registers) in this dump or snapshot and use branch traces to partially determine the code execution flow, iteratively replaying the entity's code instructions and working backward and forward to reconstruct intermediate data values (e.g., registers and memory) used by the code until these values reach a steady state. These techniques may be limited in how far back they can reconstruct data values and how many data values they can reconstruct. Nevertheless, the reconstructed historical execution data can be used for historical debugging.
[0047] Another class of historical debugging techniques (referred to herein as "snapshot and replay debugging") periodically records a complete snapshot of an entity's memory space and processor registers as it executes. If the entity relies on data from sources other than the entity's own memory, or from non-deterministic sources, these techniques can also record such data along with the snapshots. These techniques then use the data in the snapshots to replay the execution of the entity's code between snapshots. Notably, "snapshot and replay" techniques sometimes require serialization of multiple threads onto a single processing unit 107 in order to correctly replay the execution of a process.
[0048] Figure 3 An example of a trace 300 is shown, which may correspond to Figure 1A One or more of the trace(s) 113 may be created based on one or more of the aforementioned tracing techniques (e.g., the bit-accurate tracing technique described above). Figure 3 In the example of , trace 300 includes one or more trace data streams 301. Figure 3 , three trace data streams 301 (i.e., trace data streams 301a through 301c) are illustrated. In an embodiment, each trace data stream 301 records the execution of a different thread of code execution from application 112. For example, trace data stream 301a may represent the execution of a first thread of application 112, trace data stream 301b may represent the execution of a second thread of application 112, and trace data stream 301c may represent the execution of a third thread of application 112. As shown, each trace data stream 301 includes multiple data packets 302 (i.e., data packet 302a for data stream 301a, data packet 302b for data stream 301b, and data packet 302c for data stream 301c). Because the specific data recorded in each data packet 302 may vary, they are shown as having different sizes. Typically, when using bit-accurate tracing techniques, each data packet 302 records at least the inputs (e.g., register values, memory values, cache line data, etc.) of one or more executable instructions executed as part of the first thread of application 112. As shown, the trace data stream 301 may also include one or more key frames 303 (e.g., key frames 303a through 303e), which each record sufficient information, such as a snapshot of register and / or memory values, to enable the previous execution of the thread containing the key frame to be replayed by the simulation component 111 starting from the point onward of the key frame 303. In addition, the trace data stream 301 may include one or more sequencing events, such as Figure 3, as shown by the circles numbered 1 to 9 in the diagram. While each trace data stream 301 typically tracks a given thread independently, sequencing events record the occurrence of sequenced events across threads. For example, these sequencing events may correspond to events where threads interact, such as through shared memory, via function calls, etc. While the order of events in trace data stream 301 rotates through the threads in a round-robin fashion for simplicity, it is understood that they often occur in a less predictable manner.
[0049] In an embodiment, the trace 113 may also include the actual code that was executed. Figure 3 , each data packet 302 is shown as including a non-shaded data input portion 304 (i.e., data input portion 304a for data packet 302a, data input portion 304b for data packet 302b, and data input portion 304c for data packet 302c) and a shaded code portion 305 (i.e., code portion 305a for data packet 302a, code portion 305b for data packet 302b, and code portion 305c for data packet 302c). In an embodiment, the code portion 305 in the packet 302 may include executable instructions that are executed based on the corresponding data input. However, in other embodiments, the trace 113 may omit the actual code that is executed, and instead rely on separate access to the code of the application 112 (e.g., from the persistent storage device 104). In these other embodiments, each data packet may, for example, specify the address or offset of the appropriate executable instruction(s). As shown, the trace 113 may include any number of additional data streams 306 (i.e., data streams 306a to 306n), which may store any type of additional trace data. The additional trace data may include, for example, index data, such as occasional memory snapshots, reverse lookup data structures for quickly locating memory addresses / values in the trace data stream 301, and the like.
[0050] Figure 1B Shown to provide Figure 1A Example 100b of additional details of the debugging component 109. Figure 1B 109 includes various subcomponents (e.g., trace access 114, trace analysis 115, output 116, etc.) that represent various functionalities that the debug component 109 can implement in accordance with various embodiments described herein. It is to be understood that the depicted components—including their identities, subcomponents, and arrangements—are merely presented to aid in describing various embodiments of the debug component 109, and that these components / subcomponents are not limiting as to how software and / or hardware can implement various embodiments of the debug component 109 or its specific functionality.
[0051] Trace access component 114 accesses at least one of trace(s) 113. This may mean accessing trace(s) 113 from persistent storage 104 and / or accessing trace(s) 113 from another computer system (e.g., one or more of the computer systems). In an embodiment, accessing a trace 113 causes the trace to be at least partially loaded into system memory 103 (i.e., as shown by trace(s) 113').
[0052] The trace analysis component 115 performs one or more types of analysis on the accessed trace(s) 113 to identify actual or potential reads from uninitialized memory and / or data race conditions. As shown, the trace analysis component 115 may include a data inconsistency analysis component 115a that identifies situations from the trace 113 when a traced thread reads a value from a memory cell that is inconsistent with the thread's knowledge of the previous value of the memory cell (e.g., because the thread is unaware of the previous value of the memory cell, or because the thread previously read or wrote the previous value to the memory cell). These situations may correspond to reads from memory that has not been initialized (i.e., when the thread is unaware of the previous value of the memory cell), or may correspond to data races that were actually caught in the trace 113 (i.e., when a value read from a memory cell is inconsistent with a value previously read or written from the memory cell by the thread). Thus, the data inconsistency analysis component 115a can identify reads from uninitialized memory and / or potential data races that actually occurred during the trace.
[0053] To illustrate these concepts, Figure 4A An example timing diagram 400a is shown, including two timelines corresponding to the execution of two threads (i.e., T1 and T2), and a timeline showing accesses to memory cells by these threads (i.e., MC). Timing diagram 400a may, for example, correspond to the execution of two threads whose previous execution is represented in one or more access traces 113. Based on timeline 400a, data inconsistency analysis component 115a may identify a read from memory that has not been initialized (i.e., at arrow 401a). In particular, the first interaction by thread T1 with the memory cell is at arrow 401a, where thread T1 reads value A. Because this read is thread T1's first interaction with the memory cell, the thread has no prior knowledge of the value of the memory cell. For example, thread T1 has not previously written to the memory cell (which would place a known value in the memory cell). Therefore, when thread T1 reads value A from the memory cell at arrow 401a, the read value (i.e., A) may be the uninitialized value of the memory cell.
[0054] Furthermore, based on timing diagram 400a, the data inconsistency analysis component 115a can identify a read as a potential data race (i.e., at arrow 401d). Specifically, timing diagram 400a shows that, after this first read, thread T1 writes the value B to the memory cell (i.e., at arrow 401b), and then reads the value B from the memory cell (i.e., at arrow 401c). Since the value read at arrow 401c (i.e., B) is consistent with thread T1's prior knowledge of the memory cell value (i.e., B written at arrow 401b), there is no data inconsistency. However, as shown, at arrow 401e, thread T2 later writes the value C to the memory cell, and then thread T1 reads the same value at arrow 401d. Here, the value read at arrow 401d (i.e., C) is consistent with thread T1's prior knowledge of the memory cell value (i.e., B read at arrow 401c). Thus, there is data inconsistency at arrow 401d, which may be a data race.
[0055] It is worth noting that the data inconsistency analysis component 115a can also analyze thread T2 for data inconsistencies and find no data inconsistencies. For example, thread T2's first interaction with the memory unit is at arrow 401e, where thread T2 writes value C. Since the first interaction is a write, this cannot be a read from uninitialized memory. Subsequently, thread T2 reads the same value at arrow 401f. Since the value read at arrow 401f is consistent with the value written at arrow 401e, there is no data inconsistency at arrow 401f.
[0056] As previously mentioned, the “snapshot and replay” technique may require serialization of multiple threads onto a single processing unit 107. If this is the case, the data inconsistency analysis component 115a may be limited to detecting accesses to uninitialized data, rather than other data inconsistencies (i.e., because thread serialization will enforce consistency).
[0057] Additionally or alternatively, trace analysis component 115 may include a data race analysis component 115b that identifies the following situations from trace 113: (i) one traced thread uses a thread synchronization mechanism to protect access to a memory unit, (ii) another traced thread accesses the memory unit without controlling the same thread synchronization mechanism, and (iii) at least one of the thread's accesses to the memory unit is a write. In these situations, a data race is possible even if the data race is not actually captured in trace 113. Thus, data race analysis component 115b can identify situations in which a data race / contention is likely to occur.
[0058] As will be understood by those of ordinary skill in the art, thread synchronization mechanisms (sometimes referred to as thread synchronization primitives, thread locking mechanisms, thread locking primitives, etc.) are techniques for creating "critical sections" in the execution of a thread to protect shared memory during the execution of multiple threads. Some thread synchronization mechanisms are pessimistic, while others are optimistic. Generally speaking, pessimistic thread synchronization mechanisms assume that if multiple threads interact with the same memory location(s) concurrently, a race condition may occur, and therefore prevent concurrent execution of critical sections on different threads (i.e., when threads may concurrently access the same memory location(s). Examples of pessimistic thread synchronization mechanisms include spin locks, mutexes, and semaphores.
[0059] A spin lock causes the thread attempting to acquire it to wait (i.e., "spin") in a loop while repeatedly checking whether the lock is available. Once acquired, spin locks are typically held by a thread until they are explicitly released by the thread, although in some implementations they may be released automatically if the waiting thread (the thread holding the lock) blocks. A mutex grants exclusive access to a shared resource to only one thread. If the first thread acquires a mutex, a second thread attempting to acquire the mutex will be suspended until the first thread releases the mutex. A semaphore controls access to a resource and is created with a maximum count and an initial count. This count is decremented each time a thread enters the semaphore and incremented when a thread releases the semaphore. When the count reaches zero, subsequent requests block until another thread releases the semaphore. When all threads have released the semaphore, the count is at the maximum value specified when the semaphore was created.
[0060] On the other hand, optimistic thread synchronization mechanisms allow critical sections on different threads to execute concurrently and monitor the memory locations accessed during the critical sections to determine whether data races occur; if a race does occur, these mechanisms "roll back" the execution of these threads by rolling back their side effects (e.g., register and memory values changed by their execution) and then re-execute the critical section in a single-threaded manner. Examples of optimistic thread synchronization mechanisms include hardware or software-implemented transactional memory (e.g., the TSX-NI extension to the x86 instruction set architecture (ISA)).
[0061] To illustrate the concept of thread synchronization, Figure 4BAn example timing diagram 400b is shown that includes two timelines corresponding to the execution of two threads (i.e., T1 and T2), and a timeline showing accesses to memory cells by these threads (i.e., MC). For example, timing diagram 400b may correspond to the execution of two threads whose previous execution is represented in one or more accessed traces 113. Each thread in timing diagram 400b may execute from the same code and is shown as repeatedly executing a "critical section" in the code (i.e., execution portions 402a through 402f of threads T1 and T2) created by some thread synchronization mechanism. As Figure 4B As shown in the example using ellipsis, a thread uses a locking technique (e.g., a mutex) to enter a critical section when it needs to access a shared resource, and the other thread must wait for its turn to enter the critical section. This prevents contention when these threads access the same memory location. Figure 4B As shown by arrows 403a to 403f in FIG, each thread accesses (reads and / or writes) a memory unit only during the critical section, and thus the critical section prevents data contention on the memory unit. Figure 4C Additional arrows 403g and 403h are included to illustrate accesses to memory cells (e.g., each corresponding to a read and / or write from a memory cell) without using a critical section. Because these accesses are performed without using a critical section, they may cause data contention on the memory cell. The data contention analysis component 115b may identify such memory accesses as potential contention.
[0062] In an embodiment, the data-race analysis component 115b can treat accesses to a memory location that occur before the initial synchronization primitive protected access (e.g., the access at arrow 403a) (e.g., the access at arrow 403g) differently than accesses that occur later (e.g., the accesses at arrows 403d, 403b, 403e, 403c, 403f, and 403g). In doing so, the data-race analysis component 115b can reduce false positives, such as those that may occur when the traced code initializes a complex data structure that is later protected by a synchronization primitive. Thus, for example, the data-race analysis component 115b can determine that the access at arrow 403h is a potential contention, while it can determine that the access at arrow 403g is not a potential contention. Alternatively, the data-race analysis component 115b can determine that the access at arrow 403g is less likely to be a potential contention than the access at arrow 403h.
[0063] Output component 116 generates output indicating any data inconsistencies identified by data inconsistency analysis component 115a and / or any data races identified by data race analysis component 115b. In embodiments, output component 116 may generate output by writing data to a trace file or causing data to be written to a trace file (e.g., one of trace(s) 113). For example, output component 116 may write (or cause writing) index data that supplements the accessed trace 113 (e.g., as part of one of additional data streams 306) to indicate one or more execution times represented in trace 113 at which data inconsistencies and / or races occurred, one or more code elements associated with the data inconsistencies / races, and the like. In embodiments, output component 116 may generate output by sending output data(s) and / or signals to another software component (e.g., via an API call). In embodiments, output component 116 may generate output by displaying the data at a user interface or causing the data to be displayed at a user interface (e.g., a debugger user interface). For example, output component 116 can cause a debugger user interface to display visual indications along an execution timeline indicating when a data inconsistency / race occurred, display visual indications of one or more code elements associated with the data inconsistency / race, and so on.
[0064] The following discussion refers to many methods and method acts that may be performed by computer system 101. Although method acts may be discussed in a particular order or may be illustrated in flowcharts as occurring in a particular order, no particular order is required unless otherwise specified or because one act depends on another act being completed before the act is performed.
[0065] To at least better understand the analysis of the data inconsistency analysis component 115a, Figure 5 A flow chart of an example method 500 for indicating data inconsistencies observed during a previous execution of a thread is shown. Referring now to Figure 1A 、 1B , 3, 4A and 5 describe method 500.
[0066] As shown, method 500 includes an act 501 of replaying a previous execution of a thread. In some implementations, act 501 includes replaying a previous execution of a thread based on a trace representing the previous execution of the thread. For example, simulation component 111 may replay a previous execution of thread T1 whose execution timeline is in Figure 4A In an embodiment, this simulation may be performed at the request of the data inconsistency analysis component 115a, although it may alternatively be performed for some other reason—such as for general debugging of the application 112 at a debugger. As part of this simulation, the simulation component 111 may replay the Figure 4AOne or more memory accesses to the memory cells represented in , such as one or more memory accesses represented at arrows 401a to 401c and 401d.
[0067] Method 500 also includes an act 502 of observing the inflow of a value into the memory unit. In some implementations, act 502 includes observing the inflow of a value into the memory unit based on replaying a previous execution of the thread. For example, based on simulation by simulation component 111, data inconsistency analysis component 115a may observe the inflow of value A at the execution time point corresponding to arrow 401a, observe the inflow of value B at the execution time point corresponding to arrow 401c, and / or observe the inflow of value C at the execution time point corresponding to arrow 401d.
[0068] Method 500 also includes an act 503 of determining that the observed value is inconsistent with a previous value of the memory cell. In some implementations, act 503 includes determining that the value of the memory cell observed from the inflow is inconsistent with a previous value of the memory cell known to the thread. For example, for each inflow observed, data inconsistency analysis component 115a can determine whether the observed inflow is consistent with a previously known value of the memory cell corresponding to the inflow. As will be appreciated, observing the inflow of a value to the memory cell can include processing a trace data packet (e.g., one of data packets 302a) that indicates that the memory cell stores the value.
[0069] For example, if the observed inflow is value A at the execution time point corresponding to arrow 401a, the data inconsistency analysis component 115a may determine that the inflow is inconsistent with the previous value of the memory unit known by the thread. This is because the thread does not know the previous value of the memory unit. In this case, the inflow at the execution time point corresponding to arrow 401a may be a read from uninitialized memory.
[0070] In the case of an inflow such as at arrow 401a (e.g., a read from uninitialized memory), it will be understood that when it is determined that the value of the memory cell observed from the inflow is inconsistent with the previous value of the memory cell known to the thread in act 503, implementation of act 503 may include determining that the previous value of the memory cell was unknown to the thread based at least on the thread not having previously written to the memory cell.
[0071] Alternatively, if the observed inflow is value C at the execution time point corresponding to arrow 401d, the data inconsistency analysis component 115a can determine that the inflow is inconsistent with the previous value of the memory unit known to the thread. The data inconsistency analysis component 115a can make this determination based on thread T1 reading value B into the memory unit at the execution time point corresponding to arrow 401c (this read may have been replayed by simulation component 111 in action 501). Because thread T1 recently read value B from the memory unit, and because the value read at the execution time point corresponding to arrow 401d is value C, this value is inconsistent with the thread's previous knowledge of the memory unit value. In this case, the inflow at the execution time point corresponding to arrow 401d may be a data race (i.e., written by thread T2 at the execution time point corresponding to arrow 401e). It will be appreciated that thread T2's write to value C may be tracked (e.g., because thread T2's execution is also tracked as related to thread T1), or it may not be tracked (e.g., because thread T2's execution is not tracked as not selected for tracking and / or is unrelated to thread T1). If thread T2's execution is tracked, method 500 may also include an analysis of thread T2 to determine when thread T2 writes a value to a memory unit.
[0072] In the case of an inflow such as at arrow 401d (e.g., a potential race condition), it should be understood that when it is determined that the value of the memory cell observed from the inflow is inconsistent with the previous value of the memory cell known to the thread in act 503, implementation of act 503 may include first determining that the previous value of the memory cell is known to the thread based on at least one of the following: (i) the thread has previously read the previous value from the memory cell, or (ii) the thread has previously written the previous value to the memory cell, and then determining that the value of the memory cell observed from the inflow is different from the previous value of the memory cell.
[0073] Although Figure 5 401c is consistent with the thread's prior knowledge of the memory cell value. The data inconsistency analysis component 115a may make this determination based on thread T1 writing the value B to the memory cell at the execution time point corresponding to arrow 401b (this write may have been replayed by the simulation component 111 in action 501). Because, at the execution time point corresponding to arrow 401c, thread T1 recently wrote the value B to the memory cell (i.e., arrow 401b), and because the value read at the execution time point corresponding to arrow 401c is also value B, this value is consistent with the thread's prior knowledge of the memory cell value.
[0074] Method 500 also includes an act 504 of initiating an indication of a data inconsistency. In some implementations, act 504 includes initiating an indication of a data inconsistency based at least on the value of the memory cell observed from the inflow being consistent with the previous value of the memory cell. For example, based on having identified inconsistencies associated with the inflow at arrow 401a and / or arrow 401d, output component 116 can initiate one or more indications of these inconsistencies. These indications can be at a user interface (e.g., using user interface generation component 116a), in a trace file (e.g., using trace index component 116b), and / or to some other software component. Depending on the type of inconsistency identified in act 503, the indication of a data inconsistency can indicate that the data inconsistency corresponds to at least one of: (i) a read from uninitialized memory or (ii) a potential race condition.
[0075] Thus, in an implementation of act 504, initiating an indication of a data inconsistency may include at least one of: (i) initiating creation of trace index data indicating the data inconsistency (e.g., as part of additional data stream 306 in trace 113), or (ii) initiating a visual indication of the data inconsistency at a debug user interface. If act 504 includes initiating creation of trace index data, the trace index data may include, for example, one or more execution times represented in trace 113 at which the data inconsistency and / or race occurred, one or more code elements associated with the data inconsistency / race, etc. If act 504 includes initiating a visual indication of the data inconsistency at a debug user interface, the visual indication may include, for example, at least one of: (i) a visual indication along an execution timeline indicating when the data inconsistency occurred, or (ii) a visual indication of one or more code elements associated with the data inconsistency. These code elements (e.g., variables, data structures, commands, instructions, etc.) may be accessed on thread T1 (e.g., one or more code elements associated with the read at arrows 104a and / or 104d) and / or may be part of thread T2 (e.g., one or more code elements associated with the write at arrow 104e, which causes data inconsistency in thread T1). Thus, in act 504, the threads may include a first thread, and the one or more code elements associated with the data inconsistency may include one or more of: (i) a first code element from the first thread, or (ii) a second code element from a second thread, whose previous execution is also traced.
[0076] Although method 500 is primarily described in conjunction with analysis of thread T1, it should be understood that method 500 may also be used to perform similar data inconsistency analysis of thread T2. However, method 500 may not actually identify any data inconsistencies within thread T2.
[0077] To at least better understand the analysis of the data race analysis component 115b, Figure 6 A flow chart of an example method 600 for indicating a potential data race based on a trace representing a previous thread execution is shown. Referring now to Figure 1A 、 Figure 1B 、 Figure 3 、 Figure 4C and Figure 6 Describe the method.
[0078] As shown, method 600 includes an act 601 of replaying a previous execution of a plurality of threads. In some implementations, act 601 includes replaying a previous execution of a plurality of threads based on a trace representing the previous execution of the plurality of threads. For example, simulation component 111 may replay a previous execution of threads T1 and T2, whose execution timelines are in Figure 4C In an embodiment, this simulation may be performed at the request of the data race analysis component 115b, although it may alternatively be performed for some other reason—such as for general debugging of the application 112 at a debugger. As part of this simulation, the simulation component 111 may replay the Figure 4C 403h). This may include, for example, replaying the memory access(es) at arrow 403a and the memory access(es) at arrow 403h.
[0079] Method 600 also includes an act 602 of identifying usage of a thread synchronization mechanism by the first thread. In some implementations, act 602 includes identifying activation of the thread synchronization mechanism during a previous execution of a first thread of the plurality of threads based on replaying the previous execution of the plurality of threads. For example, based on replaying thread T1 by simulation component 111, data race analysis component 115b may identify an entry for critical section 402a on thread T1. For example, the entry may include thread T1 calling a function, setting a variable, etc., to initiate an entry or activation of a spin lock, mutex, semaphore, transaction, or some other thread synchronization mechanism.
[0080] Method 600 also includes an act 603 of identifying memory units accessed by the first thread while the synchronization mechanism is active. In some implementations, act 603 includes, based on replaying a previous execution of the plurality of threads and based on activation of the thread synchronization mechanism, identifying at least one memory unit accessed by the first thread while the thread synchronization mechanism is active on the first thread. For example, based on the memory access(es) represented by arrow 403a during critical section 402a, data race analysis component 115b may Figure 4CThe memory cells represented in are identified as being accessed during the critical section and, therefore, protected by the critical section. Notably, data-race analysis component 115b can additionally or alternatively use one or more memory accesses at arrows 403b and / or 403c to identify the memory cells, since these accesses to the memory cells are also performed during critical sections 402b and 402c.
[0081] Method 600 also includes an act 604 of identifying accesses to the memory unit by the second thread without using a thread synchronization mechanism. In some implementations, act 604 includes identifying memory accesses to at least one memory unit during a previous execution of a second thread of the plurality of threads without using a thread synchronization mechanism based on replaying the previous execution of the plurality of threads. For example, the data race analysis component 115b can identify the memory access(es) at arrow 403h as having been executed by thread T2 outside of a critical section and, therefore, as a data race risk.
[0082] It is noteworthy that the data race analysis component 115b may also identify one or more of the memory accesses to the memory cells at arrows 402d to 402f, but determine that they are part of the critical section 402d to 402f and therefore do not present a data race risk. In an embodiment, such accesses within the synchronization primitive protection region may cause an indication of the probability to be stored that the accessed memory cell that is required for future access is also protected by the same primitive(s). In some implementations, the tracking state may be reset upon deallocation of the associated memory cell (e.g., if the allocated cell is tracked via a call to malloc(), the tracking state may be removed via a call to free() when the allocation of the cell is freed). In an embodiment, the tracking state for a memory cell may be a binary value (e.g., "0" if no access is made within the synchronization primitive protection region, or "1" if so), although it may alternatively be something more granular (e.g., a value that increments with each synchronization primitive protected access, where a larger value indicates a greater probability).
[0083] Method 600 also includes an act 605 of initiating an indication of a potential data race. In some implementations, act 605 includes initiating an indication of a potential data race associated with at least one memory cell based on identifying the memory access. For example, based on identifying a data race risk associated with the memory access(es) at arrow 403h, output component 116 can initiate one or more indications of the potential data race. Similar to the embodiment described in conjunction with method 500, these indications can be provided at a user interface (e.g., using user interface generation component 116a), in a trace file (e.g., using trace index component 116b), and / or to some other software component.
[0084] Thus, in an implementation of act 605, initiating an indication of a potential data race may include at least one of: (i) initiating creation of trace index data indicating the potential data race (e.g., as part of additional data stream 306 in trace 113), or (ii) initiating a visual indication of the potential data race at a debug user interface. If act 605 includes initiating creation of trace index data, the trace index data may include, for example, one or more execution times indicated in trace 113 at which the potential data race occurred, one or more code elements associated with the potential data race, etc. If act 605 includes initiating a visual indication of the potential data race at a debug user interface, the visual indication may include, for example, at least one of: (i) a visual indication along an execution timeline indicating when the potential data race occurred, or (ii) a visual indication of one or more code elements associated with the potential data race. These code elements (e.g., variables, data structures, commands, instructions, etc.) may be part of thread T1 (e.g., one or more code elements associated with the access at arrows 403a to 403c) and / or may be part of thread T2 (e.g., one or more code elements associated with the access at arrow 403f, which resulted in a potential data race). Thus, in act 605, the threads may include a first thread, and the one or more code element contentions associated with the data may include one or more of: (i) a first code element from the first thread, or (ii) a second code element from a second thread, whose previous execution is also traced.
[0085] It is worth noting that different thread synchronization mechanisms can enforce different requirements, namely whether all memory reads and / or writes must be performed within the critical section, or whether some of the reads and / or writes can be allowed outside the critical section. In other words, the reading thread and the writing thread can have different requirements. Therefore, before initiating an indication of a potential data race, the data race analysis component 115b can determine whether the (multiple) memory accesses at arrow 403h actually violate the requirements of the thread synchronization mechanism used. Therefore, before action 605, the method 600 may include an action (not depicted) of determining whether the access by the second thread violates the thread synchronization mechanism. In an implementation, the action may include determining whether the memory access to at least one memory unit by the second thread violates the memory access restrictions of the thread synchronization mechanism used by the first thread. Therefore, the method 600 can initiate an indication of a potential data race in action 605 based on having determined that the memory access does violate the memory access restrictions. Therefore, the method 600 can filter out possible "false positives" before initiating an indication of a potential data race.
[0086] For example, a hardware transaction may require a thread performing a write to use a critical section, but may allow a thread performing a read to do so without a critical section. Thus, if they include one or more writes, the memory access(es) at arrow 403h may actually be just a potential data race. Thus, in method 600, if the thread synchronization mechanism includes hardware transactions, determining whether a memory access by the second thread to at least one memory unit violates a memory access restriction of the thread synchronization mechanism used by the first thread may include determining that the memory access is a write that does not use a hardware transaction.
[0087] Although the subject matter has been described in language specific to structural features and / or methodological acts, it is to be understood that the subject matter defined in the appended claims is not necessarily limited to the described features or acts or the order of acts described. Rather, the described features and acts are disclosed as example forms of implementing the claims.
[0088] The present invention may be embodied in other specific forms without departing from its spirit or essential characteristics. The described embodiments are to be considered in all respects only as illustrative and not restrictive. The scope of the present invention is therefore indicated by the appended claims rather than by the foregoing description. All variations that come within the meaning and range of equivalence of the claims are to be included within their scope. When introducing elements in the appended claims, the articles "a," "an," "the," and "said" are intended to indicate the presence of one or more elements. The terms "comprise," "include," and "have" are intended to be inclusive and indicate that there may be additional elements other than the listed elements.
Claims
1. A method, implemented at a computer system, for indicating a data inconsistency observed during a previous execution of a thread, the computer system comprising one or more processors, the method comprising: replaying a previous execution of the thread based on a trace representing the previous execution of the thread; observing an inflow of a value of a memory unit based on replaying the previous execution of the thread, the inflow comprising an interaction between the thread and the value of the memory unit at an execution time point in the replay of the previous execution of the thread; determining that, at the execution point in the replay of the previous execution of the thread, the value of the memory cell observed from the inflow is inconsistent with a previous value of the memory cell known to the thread; and initiating an indication of a data inconsistency based at least on the value of the memory cell observed from the inflow being inconsistent with the previous value of the memory cell; Wherein observing the inflow of the value to the memory unit comprises processing a trace data packet indicating that the memory unit stored the value.
2. The method of claim 1 , wherein determining that the value of the memory cell observed from the inflow is inconsistent with the previous value of the memory cell known by the thread comprises: determining that the previous value of the memory unit is known to the thread based on at least one of: (i) the thread has previously read the previous value from the memory unit, or (ii) the thread has previously written the previous value to the memory unit; as well as It is determined that the value of the memory cell observed from the inflow is different from the previous value of the memory cell.
3. The method of claim 2, wherein initiating the indication of the data inconsistency comprises: Initiates an indication of a potential race condition.
4. The method of claim 1 , wherein determining that the value of the memory cell observed from the inflow is inconsistent with the previous value of the memory cell known to the thread comprises: The previous value of the memory cell is determined to be unknown to the thread based at least on the thread not having previously written to the memory cell.
5. The method of claim 4, wherein initiating the indication of the data inconsistency comprises: An indication to initiate a read from memory that has not been initialized. 6 . The method of claim 1 , wherein the thread comprises a first thread, and wherein the value was written to the memory unit by a second thread during a previous execution of the second thread.
7. The method of claim 6 , wherein the previous execution of the second thread is also tracked, and wherein the method further comprises: A determination is made as to when the second thread writes the value to the memory unit.
8. The method of claim 1 , wherein initiating the indication of the data inconsistency comprises at least one of: (i) initiating creation of tracking index data indicating the data inconsistency, or (ii) initiating a visual indication of the data inconsistency at a debug user interface.
9. The method of claim 1 , wherein initiating the indication of the data inconsistency comprises: Initiating a visual indication of the data inconsistency at a debug user interface, and wherein the visual indication of the data inconsistency at the debug user interface comprises at least one of: (i) a visual indication along an execution timeline indicating when the data inconsistency occurred, or (ii) a visual indication of one or more code elements associated with the data inconsistency.
10. The method of claim 1 , wherein the thread comprises a first thread, and wherein initiating the indication of the data inconsistency comprises: Initiating an indication of one or more code elements associated with the data inconsistency, the one or more code elements comprising one or more of: (i) a first code element from the first thread, or (ii) a second code element from a second thread, a previous execution of which is also traced.
11. The method of claim 1 , wherein the indication of the data inconsistency indicates that the data inconsistency corresponds to at least one of: (i) a read from uninitialized memory, or (ii) a potential race condition.