Our computing infrastructure utilises multi core processors and multi processor hardware across the entire spectrum of systems from small mobile devices to huge data centers. These systems offer increased performance and scaling over single-processor systems, but at a significant cost: writing correct concurrent software is notoriously challenging. Programmers must take extreme care to orchestrate synchronisation between threads to avoid non-deterministic errors such as race conditions and atomicity violations that are notoriously difficult to detect, reproduce, or eliminate. This talk will review research on static and dynamic analysis techniques to help detect and localise these kinds of concurrency errors.