{'fraction_non_alphanumeric': 0.014767255216693418, 'fraction_numerical': 0.0, 'mean_word_length': 5.773913043478261, 'pattern_counts': {'":': 0, '<': 0, '<?xml version=': 0, '>': 0, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
Integrating compile-time and runtime parallelism management through revocable thread serialization

Efficient decomposition of program and data on a scalable MIMD processor is necessary in order to minimize communication and synchronization costs while preserving sufficient parallelism to balance the workload of the processors. Programmer management of these runtime aspects of computation often proves to be very tedious and error-prone, and produces non-scalable, non-portable code. Previous efforts to apply compiler technology have assumed static timing of runtime operations, but real MIMD processors operate with much asynchrony that is difficult for the compiler to anticipate. Also, real programming environments support features that prevent the compiler from having total knowledge of and control over the runtime conditions. Most work recognizing the asynchronous behavior of MIMD machines produce many fine-grained tasks and rely on special hardware support for fast and cheap task creation, synchronization, and context switching. The runtime mechanisms prove to be still expensive and cannot adequately improve the performance of massively data-parallel computations, whose dominant communication and synchronization overhead occurs at the data array references. Efficient decomposition of these programs requires information available from compiler analysis of the source program. We explore a framework for integrating compile-time and runtime parallelism management, whose goal is to have the compiler produce independently-scheduled, asynchronous tasks that will cooperate flexibly and efficiently with a runtime manager to distribute work and allocate system resources. The compiler analyzes the source program to partition parallel loops and data structures, then aligns thread and data partitions from various loops and other parts of the program into groups called detachments to maximize data reference locality within each detachment. The threads in a detachment are then provisionally serialized to form a single-threaded brigade. In the nominal case each brigade is assigned to a processor and executed by a task to completion in the statically scheduled order; its coarse granularity thus saves much communication, synchronization, and task management overhead. Should runtime load balancing be required, program threads can be split off from a brigade at points prioritized by the compiler and executed by tasks on idle processors. Also, if the pre-scheduled thread ordering becomes incompatible with actual runtime dependencies, a deadlock condition is averted by initiating work on a thread split from the blocked task before returning to the blocked task. We expect an overall performance gain when the compiler chooses the approximately correct granularity and thread ordering, so these exceptional cases are in fact relatively rare. We implement this new framework and examine potential policies controlling its compiler choices, and compare its performance data with alternative parallelism management strategies. Thesis Supervisor: Anant Agarwal Title: Associate Professor, EECS