  Runtime resource management for many-core systems is increasingly complex.
The complexity can be due to diverse workload characteristics with conflicting
demands, or limited shared resources such as memory bandwidth and power.
Resource management strategies for many-core systems must distribute shared
resource(s) appropriately across workloads, while coordinating the high-level
system goals at runtime in a scalable and robust manner.
  To address the complexity of dynamic resource management in many-core
systems, state-of-the-art techniques that use heuristics have been proposed.
These methods lack the formalism in providing robustness against unexpected
runtime behavior. One of the common solutions for this problem is to deploy
classical control approaches with bounds and formal guarantees. Traditional
control theoretic methods lack the ability to adapt to (1) changing goals at
runtime (i.e., self-adaptivity), and (2) changing dynamics of the modeled
system (i.e., self-optimization).
  In this chapter, we explore adaptive resource management techniques that
provide self-optimization and self-adaptivity by employing principles of
computational self-awareness, specifically reflection. By supporting these
self-awareness properties, the system can reason about the actions it takes by
considering the significance of competing objectives, user requirements, and
operating conditions while executing unpredictable workloads.
