Improve simulation and trace performance using compiler-generated simulation optimization metadata
Compiler-generated metadata enhances debugging efficiency by optimizing binary emulation and reducing trace size, addressing the inefficiencies in reproducing runtime errors and tracing in software applications.
Patent Information
- Application Number
- CN201980082004.X
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Priority Date
- 2018-12-11
- Filing Date
- 2019-12-03
- Publication Date
- 2024-12-31
- Estimated Expiration
- 2039-12-03
AI Technical Summary
Debugging software applications is time-consuming due to the need to reproduce and locate runtime errors, and existing debugging tools face inefficiencies in bit-accurate tracing, especially in production environments.
Utilize compiler-generated simulation optimization metadata to capture high-level program behavior, enabling emulator optimizations that reduce the workload and overhead of simulating machine code instructions while preserving externally visible side effects.
Improves the efficiency of binary emulation and reduces the size of bit-accurate traces, saving computing resources and memory by optimizing the execution of machine code based on source code behavior.
Smart Images

Figure CN113196243B_ABST
Abstract
Description
Background Art
[0001] When developing software applications, developers often spend a lot of time "debugging" the application code to find runtime errors (e.g., undesired behavior and software crashes) in the code. In doing so, developers can take several approaches to reproduce and locate source code faults (bugs), such as observing the behavior of the program based on different inputs, inserting debugging code (e.g., printing variable values, tracing branches of execution, etc.), temporarily removing code sections, etc. Tracking down the code that causes a given undesired behavior or software crash can take up a large portion of application development time.
[0002] To assist developers in the code debugging process, many types of debugging software applications ("debuggers") have been developed. These tools provide developers with the ability to track, visualize, and change the execution of computer code. For example, a debugger can visualize the execution of code instructions, can present memory and register values at different times during code execution, can enable developers to change the code execution path, and / or can enable developers to set breakpoints to pause application execution and present the program state when the breakpoint is triggered.
[0003] Emerging forms of debugging applications enable "time travel", "reverse" or "historical" debugging, in which the execution of one or more program threads is recorded / traced by software and / or hardware tracing into one or more trace files. Using some tracing techniques, these (multiple) trace files contain a "bit accurate" trace of the execution of each traced thread, which can then be used to replay the execution of each traced thread at a later time for forward and backward analysis. Using bit accurate tracing, the prior execution of each traced thread can be reproduced to the granularity of its single machine code instruction.
[0004] Some trace recording techniques record bit-accurate traces based in part on processor data influxes (e.g., cache misses, uncached reads, etc.) recorded during the processor's execution of each traced thread's machine code instructions. These recorded processor data influxes enable a time travel debugger to later reproduce any memory values read by these machine code instructions during the reproduction of the traced thread. Although bit-accurate traces can be achieved via hardware (e.g., by modifying the physical processor to assist in recording data influxes to the processor), in many cases, it may be advantageous to record bit-accurate traces using binary emulation, which emulates the execution of the object code at the software emulator. However, binary emulation increases the overhead of bit-accurate traces, which may limit the situations in which bit-accurate traces are actually recorded in a production environment. Summary of the invention
[0005] At least some embodiments described herein improve the efficiency of binary simulation.These embodiments utilize the simulation optimization metadata generated by the compiler, and the simulation optimization metadata captures the high-level program behavior expressed in the source code, so as to perform simulator optimization while simulating the execution of the machine code instructions generated from the source code.Using the knowledge of these high-level program behaviors, these simulator optimizations can reduce the workload that the simulator needs to perform in order to simulate the execution of these machine code instructions--obtaining the equivalent results of the machine code instructions actually executed at the processor at the same time.For example, simulator optimization may reduce the number of steps required for the execution of one or more machine code instructions to simulate (that is, compared with executing (multiple) those instructions directly at the processor), and / or may completely omit one or more machine code instructions.But, these simulator optimizations retain the externally visible side effects (for example, such as externally visible memory writes for the threads of its simulation (multiple) those instructions) of the execution of those machine code instructions that are meaningful according to the source code and its language memory model. In this way, embodiments of the present invention can use information available to the compiler in the source code - but which may not typically be explicitly captured in the corresponding machine code - to perform emulator optimizations that optimize the execution of the behavior specified in the source code while avoiding some of the inefficiencies of emulating the machine code with the same fidelity that a processor would obtain when executing the machine code.
[0006] Embodiments may also record bit-accurate traces when executing binary emulation of machine code that has been enhanced with emulation optimization metadata generated by a compiler. These bit-accurate traces are equivalent to the bit-accurate traces that would have been recorded based on executing the same machine code directly at the processor. In embodiments, the tracer may also utilize emulation optimization metadata to further reduce the size of these equivalent bit-accurate traces.
[0007] Some embodiments relate to methods, systems, and computer program products that use metadata that preserves behavior expressed in source code to effectively simulate the execution of machine code compiled from the source code. Based on accessing compiler metadata associated with executable machine code executed as part of a thread, these embodiments identify one or more behaviors of the source code that are not implied by the machine code from which the machine code was compiled. Based on the identified one or more behaviors of the source code from which the machine code was compiled, these embodiments can identify one or more emulator optimizations that can be applied during simulation of the execution of the thread, the one or more emulator optimizations reducing the number of steps required to execute one or more machine code instructions in the simulated machine code while preserving one or more side effects visible externally to the thread. The one or more emulator optimizations include at least one of: (i) reducing the number of emulator operations required to simulate the execution of one or more machine code instructions, or (ii) omitting one or more machine code instructions from the simulation. While simulating execution of machine code as part of execution of a simulated thread, one or more emulator optimizations are applied to at least: (i) reduce the number of emulator operations required to simulate execution of one or more machine code instructions while preserving one or more side effects, or (ii) omit one or more machine code instructions from the simulation while preserving one or more side effects.
[0008] Based at least on the execution of the emulated machine code, some embodiments may also record a trace that can be used to reproduce the execution of the emulated machine code. This trace is equivalent to the trace recorded without applying one or more emulator optimizations.
[0009] This summary is provided to introduce some concepts in a simplified form, which are further described in the detailed description below. This summary is neither intended to identify key features or essential features of the claimed subject matter nor to be used as an aid in determining the scope of the claimed subject matter. BRIEF DESCRIPTION OF THE DRAWINGS
[0010] In order to describe 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 presented by reference to specific embodiments of the invention illustrated in the accompanying drawings. Understanding that these drawings depict only typical embodiments of the invention and are not therefore 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 1An example computer architecture is shown that supports efficient simulation of the execution of machine code compiled from source code using metadata that preserves the behavior expressed in the source code, and that can also support recording of the simulated execution into one or more bit-accurate traces;
[0012] Figure 2 Figure illustrates an example of generating and retaining simulation optimization metadata during code compilation;
[0013] Figure 3 illustrates an example of a simulator that may be used to perform binary simulation in a manner that utilizes simulation optimization metadata during binary simulation; and
[0014] Figure 4 The figure illustrates a flow chart of an example method for using metadata that preserves behavior expressed in source code to efficiently emulate the execution of machine code compiled from the source code. DETAILED DESCRIPTION
[0015] At least some embodiments described herein improve the efficiency of binary emulation. These embodiments utilize the emulation optimization metadata generated by the compiler to perform emulator optimization while emulating the execution of the machine code instructions generated from the source code, and the emulation optimization metadata captures the high-level program behavior expressed in the source code. Using the knowledge of these high-level program behaviors, these emulator optimizations can reduce the workload that the emulator needs to perform in order to emulate the execution of these machine code instructions--obtaining the equivalent results of the actual execution of the machine code instructions at the processor at the same time. For example, emulator optimization may reduce the number of steps required for the execution of emulation one or more machine code instructions (that is, compared with directly executing (multiple) those instructions at the processor), and / or may completely omit one or more machine code instructions. However, these emulator optimizations retain the externally visible side effects of the execution of those machine code instructions that are meaningful according to the source code and its language memory model (for example, such as the memory write visible outside the thread, (multiple) those instructions are simulated for the thread). In this way, embodiments of the present invention can use information available to the compiler in the source code - but which may not typically be explicitly captured in the corresponding machine code - to perform emulator optimizations that optimally execute the behavior specified in the source code while avoiding some of the inefficiencies of emulating the machine code with the same fidelity that a processor would obtain when executing the machine code.
[0016] In this specification, obtaining "equivalent results" of executing machine code at a processor while simulating machine code means: simulating machine code in a way that exhibits behavior that would be legal according to the original source code (i.e., based on the memory model of the programming language of the source code), even if the simulated machine code does not actually capture those behaviors. Therefore, if the simulator simulates behaviors that the compiler may have generated, then the simulator using the optimizations herein can produce "equivalent results" when simulating machine code, even if those behaviors are not captured in the actual machine code being simulated. For example, given different compiler implementation choices, different compiler optimization settings, different compile time constraints (e.g., availability of registers), etc., using simulation optimization metadata, the simulator can merge reads and / or writes to the same memory location, reorder memory accesses, etc. in a manner that a compiler might have.
[0017] As mentioned, an embodiment utilizes compiler-generated simulation optimization metadata that captures high-level program behavior expressed in source code but that may not be easily identified from the resulting machine code. This simulation optimization metadata can capture any type of information available to the compiler at compile time, such as variable dependencies, memory ordering constraints (e.g., memory barriers / fences, acquire / release semantics, etc.), volatility of memory locations, properties of code segmentation (e.g., whether a function depends only on its parameters, whether a function depends on an alias, etc.), when a pointer has been "taken" by another entity, etc. Although this information can be identified from the source code, much of this information is lost or obfuscated in the resulting machine code. Therefore, the simulation optimization metadata retains this information for later use by the simulator.
[0018] For example, many modern processors can execute individual machine code instructions at a given processing unit (core) in an order different from the order in which the software developer wrote them, or more typically, the order in which the compiler generated them from the source code. This "out-of-order" execution enables the processor to more fully utilize its internal processing unit resources (e.g., execution units), which are often highly parallelized. For example, if two (or more) machine code instructions in a given code stream are independent of each other, a single processing unit may be able to execute these instructions in parallel, rather than waiting for one instruction to complete before executing the next instruction serially. In order to be able to reorder memory operations while retaining correctness, modern processors and programming languages adopt a "memory model" that defines how memory effects are globally visible in a multi-processor / multi-threaded environment. In particular, the memory model defines how multiple threads can interact through shared memory, including how they can access shared data. Therefore, the memory model defines what types of out-of-order cross-thread memory observations are legal when executing multiple threads.
[0019] Out-of-order execution can be applied to many types of machine code instructions, including instructions that perform memory operations (i.e., operations that read from or write to a memory hierarchy, typically including one or more caches and system memory). Due to out-of-order execution and / or memory hierarchy design, memory access operations performed at one processing unit may be perceived by another processing unit (or another processor) as occurring in an order different from the order specified in the original stream of machine code instructions. Therefore, many programming languages and / or compilers enable software developers to specify memory ordering constraints (e.g., memory barriers, acquire / release semantics, etc.), memory volatility, etc., through annotations to specific locations in the source code. Such annotations prevent many compiler optimizations, such as omitting corresponding memory accesses, reordering memory accesses relative to any other memory accesses, assuming invariants and lifting memory accesses out of loops, etc. In the specific example of the C / C++ language / compiler, for example, such annotations may include adding the keyword "volatile" to types, variable definitions, and / or memory accesses. Some compilers also provide custom intrinsic functions, such as "_ReadWriteBarrier" in MICROSOFT's VISUAL C++ compiler, which, when included in source code, prevents the compiler from reordering memory accesses around function calls without regard to their volatility.
[0020] When issuing machine code instructions for a given processor instruction set architecture (ISA), the compiler may rely heavily on the memory model of the ISA to ensure that the memory ordering constraints specified by these developers are followed. For example, when compiling source code with a strongly ordered ISA as a target (e.g., such as the x86 and x86-64 series processor ISAs from INTEL and Advanced Micro Devices ("AMD"), where each memory load carries implicit acquisition semantics and each memory bank carries implicit release semantics), it is often sufficient for the compiler to place the generated machine code instructions for accessing memory in the same order as in the source code, and to rely on the implicit acquisition and release semantics of the generated machine code instructions to ensure the memory ordering constraints specified by the developer. However, although these machine code instructions follow the behaviors specified by the developer from the source code, these behaviors themselves are not easily identified from the generated machine code instructions, and / or are not actually implied in the generated machine code instructions. In this way, when the source code is translated into machine code, information related to certain source code behaviors may be lost. In an embodiment, the compiler can generate simulation optimization metadata that retains a record of these behaviors.
[0021] In addition, the compiler operates within the physical constraints of the target processor (e.g., the availability of registers and / or the availability of processor instructions, depending on the target processor ISA and / or processor model / generation within a given ISA), and within human-imposed constraints (e.g., compiler implementation choices, compiler optimization choices, available computing resources during compilation, target processor model / generation, etc.). These constraints can affect the machine code that is the output of the compiler. In this way, the compiler can generate very different sets of machine code from the same source code, each of which follows the behavior expressed in the source code given different physical and / or human-imposed constraints.
[0022] One example of an optimization that can be performed during binary emulation—based on source code behavior obtained from emulation optimization metadata generated by the compiler—is to combine memory accesses that are coalesce into a single memory access based on the language memory model of the source code. Other examples of emulator optimizations may include: pinning frequently requested memory (e.g., corresponding to stack variables) into a cache (e.g., L1) to avoid going to memory for those accesses; using available registers such as Advanced Vector Extensions ("AVX") registers to store data from coalesceable memory accesses; not treating function calls as acquire and / or release barriers; coalescing memory accesses to the same cache line; grouping together validation of all cache values against system memory for stack data before and / or after a function call, etc.
[0023] Embodiments may also record bit-accurate traces when executing binary emulation of machine code that has been enhanced with emulation optimization metadata generated by a compiler. These bit-accurate traces are equivalent to the bit-accurate traces that would have been recorded based on executing the same machine code directly at the processor. In embodiments, the tracer may also utilize emulation optimization metadata to further reduce the size of these equivalent bit-accurate traces.
[0024] For a given sequence of machine code instructions and the inputs and outputs of those instructions, there may be more than one efficient way to capture the execution of those instructions into a bit-accurate trace. In this specification, a bit-accurate trace is "equivalent" to another trace if, when those traces are reproduced, they will produce exactly the same sequence of instructions, with exactly the same set of inputs and outputs on each of those instructions. To illustrate, assume that a machine code reads a memory location three times, and for each of those three reads, it reads the same value. One trace of the execution of that machine code might store information for the first read, while relying on the fact that the other two reads implicitly read the same value. An equivalent trace of that same machine code might store information for the first read and the third read, with the second read being inferred from the first read, while another equivalent trace might store information for the first read and the second read, with the third read being inferred, and so on.
[0025] In addition to the inherent benefits provided by performing bit-accurate tracing when relying on compiler-generated emulation optimization metadata for binary emulation, bit-accurate tracing can also directly exploit this compiler-generated emulation optimization metadata in order to improve tracing performance and / or reduce trace size. For example, the tracer can use such metadata to perform fewer checks on memory accesses that can be merged into a single memory according to the language memory model of the source code, thereby reducing the number of memory accesses by reordering memory accesses to perform consistency checks together (i.e., with system memory), to avoid recording the execution of a single instruction of a function that depends only on its parameters, and so on.
[0026] As will be appreciated by those skilled in the art, and as will be further described herein, binary emulation and / or trace file generation that rely on compiler-generated simulation optimization metadata can result in a variety of technical improvements over conventional binary emulation. For example, binary emulation that relies on compiler-generated simulation optimization metadata can improve the speed of binary emulation and / or can reduce the computing resources required to perform binary emulation. Combining such binary emulation with trace file generation reduces the overhead associated with performing bit-accurate tracing, opening up situations in which the overhead associated with performing bit-accurate tracing can be acceptable. In addition, utilizing simulation optimization metadata can reduce the size of the resulting trace file, saving memory, disk space, and / or network bandwidth, compared to conventional techniques.
[0027] In order to achieve the above objectives, Figure 1 An example computing environment 100 is illustrated that supports efficient simulation of execution of machine code compiled from source code using metadata that preserves behavior expressed in the source code, and that can also support logging of the simulated execution to one or more bit-accurate traces. As depicted, computing environment 100 can 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, and persistent storage 104 that are communicatively coupled using one or more communication buses 107.
[0028] Embodiments within the scope of the present invention 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 computer system. Computer-readable media that store computer-executable instructions and / or data structures are computer storage devices. 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 computer-readable media: computer storage devices and transmission media.
[0029] Computer storage is a physical hardware device that stores computer-executable instructions and / or data structures. Computer storage includes various computer hardware such as RAM, ROM, EEPROM, solid-state drive ("SSD"), flash memory, phase-change memory ("PCM"), optical disk storage, magnetic disk storage or other magnetic storage devices, or any other hardware device(s) that can be used to store program code in the form of computer-executable instructions or data structures and that can be accessed and executed by processor 102 to implement the functionality disclosed herein. Thus, for example, computer storage may include depicted system memory 103 and / or depicted persistent storage 104, which may each store computer-executable instructions and / or data structures.
[0030] Transmission medium can include network and / or data link, and it can be used to carry the program code in the form of computer executable instruction or data structure, and it can be accessed by computer system 101." network " is defined as one or more data link, and it makes it possible to transmit electronic data between computer system and / or module and / or other electronic equipment. When transmitting or providing information to computer system on network or another communication connection (or hard wire, wireless or hard wire or wireless combination), computer system can be considered as transmission medium by connection. Above-mentioned combination also should be included in the scope of computer readable medium.
[0031] In addition, upon reaching various computer system components, program code in the form of computer-executable instructions or data structures may be automatically transferred from transmission media to computer storage devices (or vice versa). For example, computer-executable instructions or data structures received over a network or data link may be buffered in RAM within a network interface module (e.g., "NIC") and then ultimately transferred to system memory 103 and / or more non-volatile computer storage devices (e.g., persistent storage 104) at computer system 101. Thus, it should be understood that computer storage devices may be included in computer system components that also (or even primarily) utilize transmission media.
[0032] Computer-executable instructions include, for example, instructions and data that cause a general purpose computer system, a special purpose computer system, or a special purpose processing device to perform a function or group of functions when executed at one or more processors 102. Computer-executable instructions may be, for example, binary, intermediate format instructions (such as assembly language), or even source code.
[0033] Those skilled in the art will appreciate that the present invention can be put into practice in a network computing environment with many types of computer system configurations, including personal computers, desktop computers, laptop computers, message processors, handheld devices, multiprocessor systems, microprocessor-based 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, where both local and remote computer systems that are linked (or by a combination of hardwired data links, wireless data links, or by hardwired and wireless data links) through a network perform tasks. In this way, 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.
[0034] As illustrated, the persistent storage device 104 can store computer executable instructions and / or data structures representing application programs, such as, for example, emulators 104a, tracers 104b, and applications 104c (e.g., which can be user mode applications and / or codes executed in kernel mode). In general, the emulator 104a can be used to emulate the execution of the binary code (i.e., machine code instructions) of the application 104c at the emulation processor, while utilizing the emulation optimization metadata 104d generated by the compiler embedded in or associated with the binary code to reduce the workload spent on the execution of the emulation binary code. If included, the tracer 104b can record a bit-accurate trace of the execution of the emulation. The trace can be temporarily stored in the system memory 103 (i.e., as shown in the trace 103e), and can potentially be permanently stored in the persistent storage device 104 (i.e., as shown in the trace 104e).
[0035] The emulator 104a and the tracer 104b can each be a standalone application, can be integrated into the same application (such as a debugging suite), or can be integrated into another software component - such as an operating system kernel, a hypervisor, a cloud structure, etc. In this way, those skilled in the art will also understand that the present invention can be practiced in a cloud computing environment to simulate and / or trace the execution of an application 104c, the execution of which can be distributed across multiple computer systems. The cloud computing environment can be distributed, although this is not required. When distributed, the cloud computing environment can be distributed internationally within an organization and / or have components owned across multiple organizations. In this specification and herein, "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, applications, and services). The definition of "cloud computing" is not limited to any of the other several advantages that can be obtained from such a model when properly deployed.
[0036] The cloud computing model can consist of various characteristics, such as on-demand self-service, broad network access, resource pooling, rapid elasticity, measurable services, etc. The cloud computing model can also take 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"). The cloud computing model can also be deployed using different deployment models such as private cloud, community cloud, public cloud, hybrid cloud, etc.
[0037] Some embodiments, such as cloud computing environments, may include a system that includes one or more hosts, each of which is capable of running one or more virtual machines. During operation, the virtual machine emulates an operating computing system, supports an operating system, and perhaps also supports one or more other applications. In some embodiments, each host includes a hypervisor that emulates virtual resources for the virtual machine using physical resources abstracted from the perspective of the virtual machine. The hypervisor also provides appropriate isolation between virtual machines. Therefore, 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.
[0038] Whether the embodiments herein operate at a single computer system 101 or across multiple computer systems, Figure 1104 and 105. Some of the components of each processor 102 that can be used to implement the various embodiments described herein are detailed. As shown, each processor 102 can include (among other things) one or more processing units 105 (e.g., processor cores) and one or more caches 106. After the code to be executed is loaded into system memory 103 (e.g., as shown by emulator 103a, tracer 103b, and application 103c / metadata 103d in system memory 103), each processing unit 105 loads and executes machine code instructions via cache 106. During execution of these instructions at parallel execution unit 105b, the instructions can use internal processor registers 105a as temporary storage locations, and can read and write to various locations in system memory 103 via cache 106 (e.g., using the "data" portion of cache 106). If processing unit 105 requires data (e.g., code or application runtime data) that is not yet stored in cache 106, then processing unit 105 may initiate a "cache miss," which causes the required data to be retrieved from system memory 103 and stored in cache 106—while potentially "evicting" some other data from cache 106 back to system memory 103.
[0039] Typically, cache 106 includes multiple "cache lines," where each cache line stores a chunk of memory from a backing store, such as system memory 103. For example, Figure 1 Cache 106 is symbolically illustrated using table 106a, where each row (i.e., cache line) in table 106a stores at least an address and a value. An address may refer to a location (e.g., a memory cell) in system memory 103. An address may be a physical address (e.g., an actual physical location in system memory 103), or an address may be a virtual address (e.g., an address mapped to a physical address to provide an abstraction). For example, a virtual address may be used to support memory isolation between different processes executed at processor 102.
[0040] In an embodiment, the trace 103e / 104e is recorded based at least in part on utilizing a processor cache (e.g., a hardware cache such as cache 106, an emulated cache, etc.) to record data read by the machine code instructions of the subject application. These embodiments are based on the following observation: a processor (e.g., such as processor 102 or an emulated processor) forms a semi-closed or quasi-closed system. For example, once the portion of the data (i.e., code data and runtime application data) of a given thread of a subject application (e.g., application 104c) is loaded into the processor's cache (e.g., cache 106), the processor itself can execute the thread (without any external input) as a time-burst semi-closed or quasi-closed system. In particular, a processing unit (e.g., one of processing units 105) can execute one or more of the machine code instructions of the thread in the code portion of the processor cache while using the runtime data stored in the data portion of the processor cache and while using the processor's internal registers. When a processing unit needs some information to be flushed in (e.g., because a machine code instruction is accessing (or will access) code or runtime data that is not yet in the processor cache or stored in uncacheable memory, because additional (multiple) machine code instructions are needed, etc.), the processing unit can trigger a cache miss to cause the information to be brought into the processor's cache from system memory, or perform an uncached read. The processing unit can then continue to execute one or more additional machine code instructions using the new information until the new information is needed again (e.g., due to a read of data that is not yet in the cache, due to a read from uncacheable memory, etc.). Thus, a bit-accurate representation of the execution of a given thread can be recorded based in part on recorded data sufficient to reproduce any data read by the thread's machine code instructions during its execution (e.g., associated with the thread's cache misses and uncached reads). This trace data can then be used as input to the thread's machine code instructions to reproduce the thread's original execution.
[0041] As mentioned above, the simulator 104a can simulate the execution of the binary code of the application 104c at the simulation processor, while utilizing the simulation optimization metadata 104d generated by the compiler embedded in or associated with the binary code. The metadata 104d is generated by the compiler (e.g., static compiler, just-in-time compiler, etc.) in the process of compiling the source code into machine code instructions, and captures the behavior of the source code that may be lost or at least obfuscated in the machine code instructions. For example, as mentioned, these behaviors can be any type of information available to the compiler at compile time, such as variable dependencies, memory ordering constraints (e.g., memory barriers, acquire / release semantics, etc.), volatility of memory locations, properties of code segmentation (e.g., whether a function depends only on its parameters, whether a function depends on aliasing, etc.), when a pointer has been "taken" by another entity, etc.
[0042] Figure 2 The figure shows an example 200 of generating and preserving simulation optimization metadata 104d during code compilation. In the example 200, the metadata is specific to memory ordering constraints, but those skilled in the art will recognize that similar or additional techniques can be used to preserve virtually any type of source code behavior. Although the metadata 104d can be stored in any file or data structure associated with the output binary, the example 200 presents an embodiment in which the metadata 104d is stored within the output binary itself. Figure 2 Only one example 200 of how simulation optimization metadata may be generated and retained is shown, and it will be appreciated that particular implementations of the embodiments herein may generate and retain simulation optimization metadata in a variety of other ways.
[0043] Generally speaking, Figure 2 Depicted are one or more input source code files 201 (referred to as source code 201) as input to a compiler tool chain, one or more intermediate object code files 202 (referred to as object code 202) generated by the compiler tool chain from the source code 201, and an output executable image 203 generated by the compiler tool chain from the object code 202. Figure 2 Two functions 204a and 204b in source code 201 are symbolically represented. In these functions 204a, 204b, Figure 2 Symbolically represents some explicit developer-specified behaviors in the source code (although embodiments may also identify more intrinsic source code behaviors). These explicit developer-specified behaviors include: annotations 205a (e.g., annotation keywords, such as "volatile" in C / C++), which are Figure 2, and an intrinsic 205b (e.g., an intrinsic function call, such as "_ReadWriteBarrier" in VISUAL C++), which is represented symbolically as an interpretation point. Figure 2 205a and intrinsic 205b both represent the expected memory ordering constraints specified by the developer. For example, annotation 205a can define ordering constraints on one or more corresponding source code statements, while intrinsic 205b can define ordering constraints on one or more source code statements after the intrinsic.
[0044] As shown by arrows 211a and 211b, the compiler toolchain generates target code 202 from source code 201 (e.g., one target code file for each source code file). Arrow 211c shows that the compiler toolchain can generate a block 204a' of machine code instructions from the source code of function 204a, while arrow 211d shows that the compiler toolchain can also generate a block 204b' of machine code instructions from the source code of function 204b. In an embodiment, these machine code instructions are symbolically represented in target code 202, such as by using an offset from the beginning of each block (i.e., corresponding to the beginning of each function). The long dashed line in block 204a' represents a specific machine code instruction generated from the (multiple) source code statements corresponding to comment 205a. On the other hand, the short dashed line in block 204b' represents a specific instruction, which is a no-operation / pseudo-instruction generated from intrinsic 205b.
[0045] The target code 202 also includes two data structures 206a and 206b. These data structures are Figure 2 206a, 206b represent metadata generated by the compiler toolchain for each block 204a', 204b' of machine code instructions. As shown, data structure 206a includes a metadata portion of the machine code instructions in the long dashed line in block 204a', while data structure 206b includes a metadata portion of the machine code instructions in the short dashed line in block 204a'.
[0046] In an embodiment, data structures 206a, 206b may be considered to include memory ordering metadata, and are therefore referred to herein as "memory ordering tables". In an embodiment, these memory ordering tables contain entries, each of which identifies a machine code instruction by its offset. These memory ordering tables may also identify a specific type of memory ordering constraint, such as a read barrier, a write barrier, or a read / write barrier. In some embodiments, the type of memory ordering constraint may even be omitted, with each entry being considered a read / write barrier.
[0047] As shown by arrow 211e, the compiler tool chain generates an executable image 203 from the target code 202. As depicted, the executable image 203 can include a header 209 and different segments 210. For example, the executable image 203 can include a PE or ELF header, a segment header, etc. The executable image 203 can also include a .text segment, a .data segment, etc. It is worth noting that the header 209 and the segment 210 do not have to appear in the order depicted and can be scattered. In implementation, one or more headers (e.g., segment headers) in the header 203 can identify the available segments 210 and specify how to load these segments into the memory for execution. In implementation, the .text segment can include machine code instructions from various target code files 202, which are now being referenced by the instruction memory address. On the other hand, the .data segment can include program data, such as variable values, constants, and other data used by the machine code instructions.
[0048] As indicated by arrows 211f and 211g, in example 200, data structures 206a, 206b from object code 202 are combined and inserted into one or more of segments 210 of the executable image. Figure 2 In example 200, data structure 207 (which aggregates data structures 206a, 206b) is shown in the .data segment of the executable image. An implementation may choose to include simulation optimization metadata in one or more of the segments of the executable image. For example, the use of the .data segment (e.g., Figure 2 Optimization of the metadata may benefit data availability (i.e., metadata can be loaded and remain resident in memory, even for the original target architecture), but the metadata may then take up memory even on machines that do not actually utilize the metadata. To reduce memory usage, an alternative implementation may select segments that are discarded by the binary loader of the original target architecture, thereby reclaiming the memory space occupied by the emulation-optimized metadata.
[0049] Data structure 207 can be viewed as a memory ordering table that contains an aggregation of memory ordering tables from target code 202. Similar to the tables discussed above in conjunction with target code 202, each entry in data structure 207 can identify a specific type of memory ordering constraint, such as a read barrier, a write barrier, or a read / write barrier. In implementation, entries in data structure 207 reference corresponding machine code instructions by instruction memory addresses. As indicated by arrow 211h, data structure 207 can be identified by one or more headers 209 in header 209.
[0050] The executable image 203 may include additional simulation optimization metadata generated by the compiler toolchain. For example, Figure 2Also illustrated is a data structure 208 within executable image 203. In an embodiment, data structure 208 includes instruction memory address range information, and thus may be viewed as a "range table". In particular, data structure 208 may identify which range(s) of memory addresses are covered by machine code instructions generated by a compiler (which also creates simulation optimization metadata). Data structure 208 may also be identified by one or more of headers 209, as indicated by arrow 211h.
[0051] Data structure 208 may be useful when executable image 203 contains machine code instructions that originate from sources other than object code 202, such as from a statically linked shared library. In these cases, data structure 208 may be used by the binary emulator to determine, for each instruction memory address, whether corresponding emulation optimization metadata is available for that instruction memory address. If a given instruction memory address is covered by the range specified in data structure 208, then the binary emulator may continue to query data structure 207. Otherwise, if the instruction memory address is not covered by the range specified in data structure 208, then the binary emulator may determine that no emulation optimization metadata is available for that address, and therefore pessimistically emulate a memory barrier where appropriate.
[0052] It is noteworthy that some embodiments may indicate (either explicitly or implicitly) that one or more blocks of one or more machine code instructions lack corresponding simulation optimization metadata (e.g., such as (multiple) data structures 206a, 206b and / or data structure 207). These indications may be present during any stage of compilation, such as in the target file and / or in the resulting executable image. For example, these indications may be made using no-op / pseudo instructions, additional metadata stored in the target code and / or in the resulting executable image. For example, these indications may help avoid searching for simulation optimization metadata during code simulation, and / or ensure that the simulator treats (multiple) of these blocks of (multiple) instructions pessimistically - such as by treating them as memory barriers.
[0053] Figure 3 FIG. 3 shows an emulator 301 (eg, corresponding to Figure 1emulator 104a) that can be used to perform binary emulation (e.g., of application 104c) in a manner that utilizes emulation optimization metadata (e.g., metadata 104d) during binary emulation. As depicted, emulator 301 includes various components (e.g., metadata access 302, behavior identification 303, optimization identification 304, processor emulation 305, optimization application 306, etc.) that represent various functions that emulator 301 can implement according to various embodiments described herein. It should be understood that these components - including their identities and arrangements - are merely depicted to help describe various embodiments of emulator 301 described herein, and these components are not limited to how software and / or hardware can implement various embodiments of emulator 301 described herein or various embodiments of specific functions thereof.
[0054] The metadata access component 302 accesses compiler-generated metadata associated with the machine code being emulated by the emulator 300. For example, if the application 104c includes Figure 2 The executable image 203, the metadata access component 302 can access the executable image 203 including the metadata access component 302. Figure 2 The metadata 104d of the described data structures 207, 208, or any other suitable compiler generated metadata. As mentioned, the metadata may record any type of information including source code behavior that is known at compile time and may be useful to know during simulation.
[0055] Based on the metadata accessed by the metadata access component 302, the behavior identification component 303 identifies one or more behaviors of the source code from which the machine code is compiled, but the one or more behaviors may not be implied in the machine code (or at least obfuscated or not easily identified in the machine code being simulated). These behaviors may include, for example, variable dependencies, memory ordering constraints (e.g., memory barriers, acquire / release semantics, etc.), memory volatility, function-level metadata (e.g., whether a function depends only on its parameters, whether a function depends on an alias), whether a pointer has been "adopted" by another entity, etc. In some embodiments, the metadata 104d may even explicitly specifically identify things that can be omitted in the simulator. For example, the metadata 104d may identify flags of processors that are not relied upon. Although physical processors intrinsically calculate their flags during normal operation, software simulators do extra work to calculate and maintain them. Therefore, if the simulator can avoid calculating / maintaining flags that are not consumed, there is a potential for substantial savings to the simulator.
[0056] Based on the (multiple) behaviors identified by the behavior identification component 303, the optimization identification component 304 identifies one or more simulator optimizations that can be applied in the simulation process of the subject machine code. In general, these optimizations reduce the number of steps required for the execution of the simulated machine code as part of a thread, while obtaining the equivalent results of directly executing the machine code at the processor or simulating the machine code without using these optimizations. In general, this can include: retaining any side effects that are visible outside the thread and meaningful according to the language memory model of the original source code and the source code, even if these side effects may deviate from the behavior that would be seen when the optimization is not applied. These simulator optimizations can either reduce the simulator operands required for the execution of the simulated one or more machine code instructions, or completely omit one or more machine code instructions from the simulation.
[0057] For example, assume that the behavior identification component 303 identifies two or more storage locations (e.g., corresponding to variables or data structures) from metadata 104d that are mutually dependent. Using this knowledge, the optimization identification component 304 may be able to identify the way to reorder the simulation of one or more machine code instructions (e.g., causing less memory access). This is possible because the compiler often generates machine code instructions that reorder operations in a busy manner to the execution unit 105b of the processing unit 105, but this order may not be the most effective for the simulator-this may not be subject to the physical limitations of the processor (such as a fixed number of available processor registers). Using the knowledge of dependencies, the optimization identification component 304 may even be able to identify the way to completely eliminate the execution of one or more machine code instructions. For example, if-based on the knowledge of data dependencies-the optimization identification component 304 can identify that there is no other data to which it depends, then one or more operations may be able to be completely eliminated. For example, depending on the result of the branch / condition, the compiler can generate instructions in a general code path whose output is only used in some code paths. The compiler may do this because when executing this code at a hardware processor, the additional runtime execution cost when the outputs of these instructions are not used is less than the runtime execution benefit from having already calculated the output values when the data is needed. The emulator may sufficiently alter the performance characteristics of the code execution (e.g., including the ability to run instructions simultaneously, perform speculation, etc.) such that the negative costs may outweigh the benefits when running the code on the emulator. In this way, the emulator may omit such instructions from the general code path.
[0058] As another example, assume that the behavior identification component 303 identifies one or more specific memory barriers from the metadata 104d. Using knowledge of the memory barriers, the optimization identification component 304 may be able to identify memory reads and / or memory writes that can be omitted entirely. In particular, multiple writes to the same memory location may be able to be merged into one write if all of them occur before the same release barrier (i.e., all write operations except one are eliminated). Similarly, multiple reads to the same memory location may be able to be merged into one read if all of them occur after the same acquire barrier.
[0059] As another example, assume that the behavior identification component 303 identifies function-level information for one or more functions from metadata 104d. For example, metadata 104d may have identified that a particular function depends only on its parameters. In this case, the optimization identification component 304 may be able to identify the use of registers rather than memory for any local variables in the function, or may even be able to identify native functions with the same behavior that can be called without emulating the function. Additionally or alternatively, metadata 104d may have identified that a particular function does not rely on memory aliases. In this case, the simulator 301 may not need to ensure that data can be accessed by memory addresses or similar aliases, and the optimization identification component 304 may therefore be able to identify locations (e.g., registers, some other temporary register spaces available to the simulator, etc.) for relocating data, which can be more effectively accessed by the simulator 301. Additionally or alternatively, metadata 104d may have identified a particular function that does not use memory barriers itself. Typically, the simulator 301 may treat the call to a function as a memory barrier, limiting the available simulator optimizations around the call. However, if the metadata 104d indicates that this is not the case for a given function, the optimization identification component 304 may be able to identify ways to perform reads and writes within the function more efficiently, such as by avoiding going all the way to memory for reads / writes.
[0060] As another example, assume that the behavior identification component 303 identifies from the metadata 104d whether an entity already has a memory pointer pointing to it that is "adopted" by another entity. If so, the entity is aliasable, so the simulator 301 may need to be careful not to place the entity's data in a location that does not support aliasing. Otherwise, if the entity's memory pointer is not aliased (or cannot be aliased), then the optimization identification component 304 may be able to identify a method to store the entity's data in a location that is fast (e.g., a scratch space in the simulated processor) rather than a memory location, if this is advantageous.
[0061] Other example optimizations may coalesce registers, pin frequently requested memory into cache, use AVX registers to store data from coalesceable memory accesses, coalesce memory accesses to the same cache line, group validation of all cache values together before and / or after function calls against system memory for stack data.
[0062] Processor emulation component 305 emulates execution of subject machine code at a software emulated processor. During this emulation, optimization application component 306 applies optimizations identified by optimization identification component 304. As discussed, these optimizations may operate to reduce the number of emulator operations required for execution of emulated subject code instructions while preserving external side effects, or machine code may be omitted entirely from the emulation.
[0063] In view of the foregoing, Figure 4 FIG. 4 is a flow chart of an example method 400 for using metadata that preserves behavior expressed in source code to efficiently emulate the execution of machine code compiled from the source code. Figure 1-Figure 3 Method 400 is described with reference to the architecture, components, and examples of FIG.
[0064] like Figure 4 As shown in , method 400 includes an action 401 of accessing simulation optimization metadata generated by a compiler. In some embodiments, action 401 includes accessing compiler metadata associated with executable machine code executed as part of a thread. For example, based on a simulation of the execution of application 104d, metadata access component 303 can access metadata 104d. The metadata can retain any type of information available to the compiler that compiles application 104c, and such information may be useful for improving simulation performance. As discussed, this can include information such as: variable dependencies, memory ordering constraints, memory volatility, function-level metadata, whether a pointer has been "adopted" by another entity, etc.
[0065] Method 400 also includes an act 402 of identifying one or more source code behaviors. In some embodiments, act 402 includes identifying one or more behaviors of the source code that are not implied by the machine code from which the machine code is compiled. For example, behavior identification component 304 can identify any behavior retained in metadata 104d (e.g., such as variable dependencies, memory ordering constraints, memory volatility, function-level metadata, whether a pointer has been "adopted" by another entity, etc.). As noted, these behaviors may not be explicitly identified in the machine code and / or may be difficult to determine from the machine code. For example, the compiler may have relied on behaviors in the target ISA that are not explicitly identified in the executable code (e.g., acquire / release semantics) to enforce source code behaviors. In addition, the machine code may imply behaviors that are not actually present in the source code (such as behaviors guaranteed by the target ISA).
[0066] Method 400 also includes an action 403 of identifying (multiple) simulator optimizations. In some embodiments, action 403 includes identifying one or more simulator optimizations that can be applied during the simulation of the execution of the thread, which reduce the number of steps required for the simulation of the execution of one or more machine code instructions of the machine code. This operation can be completed while retaining one or more side effects of the execution of one or more machine code instructions visible outside the thread. These simulator optimizations may include at least one of the following: (i) reducing the number of simulator operations required for the simulation of the execution of one or more machine code instructions, or (ii) omitting one or more machine code instructions from the simulation. For example, based on the behavior identified in action 402, the optimization identification component 305 can identify simulator optimizations / shortcuts that can be taken to simulate the code of application 104c, while producing equivalent results that have been executed at (multiple) processors 102 for application 104c or have not yet been optimized / shortcuts. As a result, it is meaningful to execute the externally visible side effects of each thread according to the original source code and the language memory model of the source code, even if these side effects may deviate from the behavior that would be seen when the optimization / shortcut is not adopted. As discussed in conjunction with the optimization identification component 304, these optimizations / shortcuts can include things such as reordering memory accesses, coalescing reads and / or writes around register barriers, using registers or other emulator scratch space instead of going to memory, pinning frequently requested memory to cache, etc. The result of these optimizations / shortcuts is that the code of the application 104c is emulated using fewer emulator steps than would otherwise be required, including potentially omitting emulation of some of the code of the application 104c entirely.
[0067] Method 400 also includes an act 404 of applying optimization(s) during machine code emulation. In some embodiments, act 404 includes, while emulating execution of the machine code as part of execution of the emulated thread, applying one or more emulator optimizations to at least: (i) reduce the number of emulator operations required to emulate execution of the one or more machine code instructions while preserving one or more side effects, or (ii) omit one or more machine code instructions from emulation while preserving one or more side effects. For example, while processor emulation component 305 emulates code of application 104c, optimization application component 306 can apply the optimizations / shortcuts identified in act 404.
[0068] In view of the above discussion, these optimizations may include, for example: omitting one or more memory accesses when a function depends only on its inputs or when a function does not induce aliases; relocating data from memory to registers when a function does not depend on aliases; avoiding going to memory for one or more reads or one or more writes when a function does not use memory barriers; merging multiple memory reads to the same memory address after the same acquire barrier; merging multiple memory writes to the same memory address before the same release barrier; reordering the emulation of one or more machine code instructions or omitting at least one machine code instruction based on variable dependencies; avoiding calculating flags; avoiding storing data of an entity in memory if the entity cannot be aliased; and so on.
[0069] As mentioned, embodiments may also record bit-accurate traces when performing binary emulation of machine code that has been enhanced with emulation optimization metadata generated by a compiler. In this way, method 400 may also include an action 405 of recording a trace of the emulated execution. In some embodiments, action 405 includes recording a trace that can be used to reproduce the emulated execution of the machine code based at least on the emulation of the execution of the machine code. For example, when emulator 104a emulates the execution of application 104d using metadata 104d, tracer 104b may record a bit-accurate trace of the emulated execution to trace 103e / 104e. Because emulator 104a has the equivalent result of executing application 104c without emulation optimization / shortcuts, this trace may be equivalent to a trace recorded without applying emulator optimization.
[0070] In an embodiment, the tracer 104b may also directly utilize the metadata 104d to reduce the trace size. For example, the tracer 104b may use such metadata 104d to perform fewer checks on memory accesses that can be merged into a single memory based on the language memory model of the source code, or to perform consistency checks together by reordering them (i.e., utilizing system memory) to reduce the number of memory accesses. In another example, if the metadata 104d indicates that a function depends only on its parameters, the tracer 104b may be able to record only the inputs to the function - and avoid recording the execution of instructions within the function. In the case where the code for the function is available (e.g., in the application binary, or injected into the trace when recording), the function can be fully reproduced by providing appropriate machine code for these function inputs.
[0071] It is worth noting that performing simulation optimizations / shortcuts may potentially obfuscate the occurrence of race conditions during simulation (e.g., such as by changing the likelihood of a race condition occurring). However, if a trace of the simulation is recorded in act 405, these race conditions may be identified from the trace (e.g., by analyzing the trace to discover two or more unsynchronized accesses to the same memory location occurring across threads, and where one or more of the memory accesses are writes).
[0072] Without departing from the spirit or essential features of the present invention, the present invention may be implemented in other specific forms. The described embodiments should be considered in all respects to be illustrative only and not restrictive. Therefore, the scope of the present invention is indicated by the appended claims rather than the preceding description. All changes within the equivalent meaning and scope of the claims are included within their scope.
Claims
1. A method implemented at a computer system including one or more processors, the method for efficiently simulating the execution of machine code compiled from source code using metadata that preserves behavior expressed in the source code, the method comprising: identifying one or more behaviors of the source code that are not implied by the machine code based on accessing compiler metadata associated with executable machine code executed as part of a thread, the machine code being compiled from the source code; identifying, based on the one or more identified behaviors of the source code, one or more emulator optimizations that can be applied during simulation of execution of the thread, the machine code being compiled from the source code, the one or more emulator optimizations reducing a number of steps required to simulate execution of one or more machine code instructions in the machine code while preserving one or more side effects visible externally of the thread, the one or more emulator optimizations comprising at least one of: (i) reducing a number of emulator operations required to simulate execution of the one or more machine code instructions, or (ii) omitting the one or more machine code instructions from simulation; as well as While simulating execution of the machine code as part of simulating execution of the thread, the one or more emulator optimizations are applied to at least: (i) reduce the number of emulator operands required to simulate execution of the one or more machine code instructions while preserving the one or more side effects, or (ii) omit the one or more machine code instructions from the simulation while preserving the one or more side effects.
2. The method according to claim 1, further comprising: Based at least on simulating execution of the machine code, a trace is recorded that can be used to reproduce the simulated execution of the machine code, the trace being equivalent to a trace that would have been recorded without applying the one or more simulator optimizations.
3. The method of claim 1 , wherein retaining the one or more side effects comprises: One or more external memory behaviors are retained, which are meaningful according to the source code and according to a language memory model of the source code.
4. The method of claim 1 , wherein the one or more behaviors identify a function as depending only on an input to the function, or identify that the function does not induce aliasing, and wherein the one or more simulator optimizations omit one or more memory accesses during execution of machine code corresponding to the function.
5. The method of claim 1, wherein the one or more behavior identification functions do not rely on aliases, and wherein the one or more simulator optimizations relocate data from memory to registers. 6 . The method of claim 1 , wherein the one or more behavior identification functions do not use memory barriers, and wherein the one or more simulator optimizations avoid going to memory for one or more reads or one or more writes.
7. The method of claim 1, wherein the one or more behaviors identify an acquire barrier, and wherein the one or more simulator optimizations coalesce multiple memory reads to the same memory address after the acquire barrier.
8. The method of claim 1, wherein the one or more behaviors identify a release barrier, and wherein the one or more simulator optimizations coalesce multiple memory writes to the same memory address prior to the release barrier.
9. The method of claim 1, wherein the one or more behaviors identify one or more variable dependencies, and wherein the one or more simulators optimize the simulation reordering of one or more machine code instructions, or omit at least one machine code instruction.
10. The method of claim 1, wherein the one or more behaviors identify flags that can be omitted, and wherein the one or more simulator optimizations avoid computing the flags.
11. The method of claim 1, wherein the one or more behaviors identify entities that cannot be aliased, and wherein the one or more simulator optimizations avoid storing data for the entities in memory.
12. A computer system comprising: one or more processors; as well as One or more computer-readable media having computer-executable instructions stored thereon, the computer-executable instructions being executable by the one or more processors to cause the computer system to perform at least the following actions: identifying one or more behaviors of source code that are not implied by the machine code based on accessing compiler metadata associated with executable machine code executed as part of a thread, the machine code being compiled from the source code; identifying, based on the one or more identified behaviors of the source code, one or more emulator optimizations that can be applied during simulation of execution of the thread, the machine code being compiled from the source code, the one or more emulator optimizations reducing a number of steps required to simulate execution of one or more machine code instructions in the machine code while preserving one or more side effects visible externally of the thread, the one or more emulator optimizations comprising at least one of: (i) reducing a number of emulator operations required to simulate execution of the one or more machine code instructions, or (ii) omitting the one or more machine code instructions from simulation; as well as While simulating execution of the machine code as part of simulating execution of the thread, the one or more emulator optimizations are applied to at least: (i) reduce the number of emulator operands required to simulate execution of the one or more machine code instructions while preserving the one or more side effects, or (ii) omit the one or more machine code instructions from the simulation while preserving the one or more side effects.
13. A computer system according to claim 12, wherein the computer executable instructions are also executable by the one or more processors to cause the computer system to: based at least on simulating the execution of the machine code, record a trace that can be used to reproduce the simulated execution of the machine code, and the trace is equivalent to the trace recorded without applying the one or more simulator optimizations.
14. The computer system of claim 12, wherein retaining the one or more side effects comprises: One or more external memory behaviors are retained, which are meaningful according to the source code and according to a language memory model of the source code.
15. The computer system of claim 12, wherein the one or more behaviors identify a function as depending only on an input to the function, or identify that the function does not induce aliasing, and wherein the one or more emulator optimizations omit one or more memory accesses during execution of machine code corresponding to the function.
16. The computer system of claim 12, wherein the one or more behavior identification functions do not rely on aliases, and wherein the one or more simulator optimizations relocate data from memory to registers.
17. The computer system of claim 12, wherein the one or more behavior identification functions do not use memory barriers, and wherein the one or more simulator optimizations avoid going to memory for one or more reads or one or more writes.
18. The computer system of claim 12, wherein the one or more behaviors identify an acquire barrier, and wherein the one or more simulator optimizations coalesce multiple memory reads to the same memory address after the acquire barrier.
19. The computer system of claim 12, wherein the one or more behaviors identify a release barrier, and wherein the one or more simulator optimizations coalesce multiple memory writes to the same memory address prior to the release barrier.
20. A computer program product comprising computer executable instructions, the computer executable instructions being executable by one or more processors to cause a computer system to perform at least the following actions: identifying one or more behaviors of source code that are not implied by the machine code based on accessing compiler metadata associated with executable machine code executed as part of a thread, the machine code being compiled from the source code; identifying, based on the one or more identified behaviors of the source code, one or more emulator optimizations that can be applied during simulation of execution of the thread, the machine code being compiled from the source code, the one or more emulator optimizations reducing a number of steps required to simulate execution of one or more machine code instructions in the machine code while preserving one or more side effects visible externally of the thread, the one or more emulator optimizations comprising at least one of: (i) reducing a number of emulator operations required to simulate execution of the one or more machine code instructions, or (ii) omitting the one or more machine code instructions from simulation; as well as While simulating execution of the machine code as part of simulating execution of the thread, the one or more emulator optimizations are applied to at least: (i) reduce the number of emulator operands required to simulate execution of the one or more machine code instructions while preserving the one or more side effects, or (ii) omit the one or more machine code instructions from the simulation while preserving the one or more side effects.