A system capable of compiling a source program that comprises a plurality of source operations and one or more loops and/or branches, thereby defining a non-linear sequence of execution of the source operations; wherein the system comprises: a dispatcher configured to step through the sequence including looping through the loops and/or branching at the branches, and to map each source operation to a respective function call each time encountered during the stepping through of the sequence; a trace buffer; an interceptor configured to intercept the function calls from the dispatcher, convert each into a corresponding trace entry comprising a set of one or more trace operations, and insert the trace entries one after another into the trace buffer to thereby form a linear trace of the source program; and a trace manager configured to transfer each of a succession of trace instances from the trace buffer to at least one compiler for compilation into corresponding compiled code, each trace instance comprising a current instance of the trace in the trace buffer or a portion thereof, the trace manager being arranged to receive back the compiled code compiled from each trace instance by the at least one compiler, and send the compiled code to at least one destination device to be executed; wherein the trace manager is configured to, for at least a first of the trace instances, collect statistics on at least one of: i) a compilation time of the compilation of the first one or more trace instances, ii) an execution time of the corresponding compiled code, iii) a frequency of repetition of one or more trace instances, iv) a memory utilization of the corresponding compiled code, and/or v) a device health of the destination device used to run the corresponding compiled code; and, based on said statistics, select which of multiple compilers to use as the at least one compiler to which at least a second of the trace instances is transferred for compilation of the at least one second trace instance by the selected compiler. a dispatcher configured to step through the sequence including looping through the loops and/or branching at the branches, and to map each source operation to a respective function call each time encountered during the stepping through of the sequence; a trace buffer; an interceptor configured to intercept the function calls from the dispatcher, convert each into a corresponding trace entry comprising a set of one or more trace operations, and insert the trace entries one after another into the trace buffer to thereby form a linear trace of the source program; and a trace manager configured to transfer each of a succession of trace instances from the trace buffer to at least one compiler for compilation into corresponding compiled code, each trace instance comprising a current instance of the trace in the trace buffer or a portion thereof, the trace manager being arranged to receive back the compiled code compiled from each trace instance by the at least one compiler, and send the compiled code to at least one destination device to be executed; wherein the trace manager is configured to, for at least a first of the trace instances, collect statistics on at least one of: i) a compilation time of the compilation of the first one or more trace instances, ii) an execution time of the corresponding compiled code, iii) a frequency of repetition of one or more trace instances, iv) a memory utilization of the corresponding compiled code, and/or v) a device health of the destination device used to run the corresponding compiled code; and, based on said statistics, select which of multiple compilers to use as the at least one compiler to which at least a second of the trace instances is transferred for compilation of the at least one second trace instance by the selected compiler.