======================================== Mercury feedback compilation framework ======================================== Introduction ============ In many cases it's useful to feedback information into the compiler. For example after profiling the execution of a program it may be useful to use the profiling information to make smarter optimization decisions. Immediate applications include feedback driven implicit parallelism, inlining and any optimization that many intoruce introduce procedures. Tools may write-out feedback data based on any information, (profiling information is an example). The relevant optimization passes in the compiler may read the feedback information and act on it. Different optimizations will wish to use the feedback system, each may store different data, against different modules. Each time feedback data is written, it should not clobber existing feedback data for other optimizations, but should write over previous feedback data for the current optimization. Interface ========= Tools should be able to 'put' feedback data into the feedback files, This should behave as described above. The put predicate should be described as. :- pred feedback.put(feedback_state::in, feedback_state::out, string::in, string::in, univ::in) is det. feedback.put(!State, Module, Optimization, Info) To query the feedback files one can retrieve a value for a given module. The state is not changed and this is reflected by no output variable for the feedback state. If no information can be returned then maybe's no option is returned. :- pred feedback.get(feedback_state::in, string::in, string::in, maybe(univ)::out) is det. feedback.get(!State, Module, Optimization, MaybeInfo) A Predicate with the interface below will read in the feedback information. Stratergies to cache this information to prevent re-reading it are discussed below. :- pred feedback.read(string::in, feedback_state::out, io::di, io::uo) is det. feedback.read(Path, FeedbackState, !IO) To write out the feedback file. This behaves as described in the section above. It maintains feedback data for optimizations that haven't been described by use of the put predicate. and removes any other feedback data before adding newly-registered feedback data. :- pred feedback.write(feedback-state::in, io::di, io::uo) is det. feedback.write(FeedbackState, !IO) Ideas ===== As mentioned above, the feedback.read predicate should possibly cache data. As many optimizations may 'read' the same feedback files, this should be done once and cached to minimize operating system calls (disc access should be cached). A solution to this is tieing this into the compliers globals structure. So that when command line arguments are processed a decision is made to read the feedback information, it is read it and kept in this globals structure for any optimization to use. In a first implementation the decision to read in feedback data can probably be determined by a single command line switch, specifing the path of a feedback file to read. For reading feedback information it would be simplest to store feedback for different modules in different files. So that each invocation of mmc doesn't read more data than is required. This would be my preferred implementation. Alternatively, all the feedback information could be stored in a single file. The first benefit is that it would be easier to write the feedback data. Secondly if the internal format is human readable, a programmer can debug their feedback data generation code by reading/checking a single file. Zoltan proposed the idea that this second type of file should always be written even if we opt for the first implementation. Given this, and the other benefits to this second option I propose to implement the this option. And possibly implement the first option in the future. The other major consideration is the datatype for the data each optimization may store. Here I have used univ which I believe can be written out and read in to the files easily. Otherwise we can use the 'term' type.