blob: 7a1f568b57d61e922d3c585963584e9520570576 [file]
// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef IREE_TASK_TOPOLOGY_H_
#define IREE_TASK_TOPOLOGY_H_
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include "iree/base/api.h"
#include "iree/base/internal/threading.h"
#include "iree/task/tuning.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
//===----------------------------------------------------------------------===//
// NUMA queries
//===----------------------------------------------------------------------===//
// A NUMA node or processor group ordinal.
typedef uint32_t iree_task_topology_node_id_t;
// Use any NUMA node (usually the first).
#define IREE_TASK_TOPOLOGY_NODE_ID_ANY ((iree_task_topology_node_id_t)-1)
// Returns the total number of NUMA nodes in the system or 1 if the query is
// not available on the platform.
iree_host_size_t iree_task_topology_query_node_count(void);
// Returns the NUMA node ID of the currently executing thread or 0 if the query
// is not available on the platform.
iree_task_topology_node_id_t iree_task_topology_query_current_node(void);
//===----------------------------------------------------------------------===//
// Topology group (worker thread(s) assigned to a processor)
//===----------------------------------------------------------------------===//
// A bitmask indicating which other groups from 0 to N may constructively share
// caches. For example, a value of 0b1100 indicates that group 2 and 3 share.
typedef uint64_t iree_task_topology_group_mask_t;
#define IREE_TASK_TOPOLOGY_GROUP_MASK_ALL UINT64_MAX
#define IREE_TASK_TOPOLOGY_GROUP_BIT_COUNT \
(sizeof(iree_task_topology_group_mask_t) * 8)
// Information about a particular group within the topology.
// Groups may be of varying levels of granularity even within the same topology
// based on how the topology is defined.
typedef struct iree_task_topology_group_t {
// Group index within the topology matching a particular bit in
// iree_task_topology_group_mask_t.
uint8_t group_index;
// A name assigned to executor workers used for logging/tracing.
char name[32 - /*group_index*/ 1];
// Processor index in the cpuinfo set.
uint32_t processor_index;
// Ideal thread affinity for threads within this group.
// All threads within the group share the same affinity and this is what
// allows us to model Simultaneous Multi-Threading (SMT) (aka hyperthreading).
iree_thread_affinity_t ideal_thread_affinity;
// A bitmask of other group indices that share some level of the cache
// hierarchy. Workers of this group are more likely to constructively share
// some cache levels higher up with these other groups. For example, if the
// workers in a group all share an L2 cache then the groups indicated here may
// all share the same L3 cache.
iree_task_topology_group_mask_t constructive_sharing_mask;
} iree_task_topology_group_t;
// Initializes |out_group| with a |group_index| derived name.
void iree_task_topology_group_initialize(uint8_t group_index,
iree_task_topology_group_t* out_group);
//===----------------------------------------------------------------------===//
// Topology
//===----------------------------------------------------------------------===//
// Task system topology information used to define the workers within an
// executor.
//
// Topologies are used to statically configure task executors by defining the
// total number of workers in the worker pool and how those workers map to
// hardware compute resources.
//
// Users can allocate topologies, populate them with zero or more groups, and
// then pass them to the executor to construct the desired configuration. To
// ease testing and debugging topologies can be formatted as string values and
// round tripped through flags, though obviously the value of such encodings are
// machine-dependent.
//
// Several helper constructors are available that query the machine topology
// and attempt to derive some (hopefully) useful task system topology from it.
// We can add the more common heuristics over time to the core and leave the
// edge cases for applications to construct.
typedef struct iree_task_topology_t {
iree_host_size_t group_count;
iree_task_topology_group_t groups[IREE_TASK_EXECUTOR_MAX_WORKER_COUNT];
} iree_task_topology_t;
// Initializes an empty task topology.
void iree_task_topology_initialize(iree_task_topology_t* out_topology);
// Deinitializes a topology structure.
void iree_task_topology_deinitialize(iree_task_topology_t* topology);
// Parses a serialized topology in string form.
iree_status_t iree_task_topology_parse(iree_string_view_t value,
iree_task_topology_t* out_topology);
// Formats the topology as a string value that can be parsed with
// iree_task_topology_parse.
bool iree_task_topology_format(const iree_task_topology_t* topology,
iree_host_size_t buffer_capacity, char* buffer,
iree_host_size_t* out_buffer_length);
// Returns the group capacity in the topology structure.
iree_host_size_t iree_task_topology_group_capacity(
const iree_task_topology_t* topology);
// Returns the total group count defined by the topology.
iree_host_size_t iree_task_topology_group_count(
const iree_task_topology_t* topology);
// Returns the group information for the given group index.
const iree_task_topology_group_t* iree_task_topology_get_group(
const iree_task_topology_t* topology, iree_host_size_t group_index);
// Pushes a new group onto the topology set.
// The provided group data will be copied into the topology structure.
iree_status_t iree_task_topology_push_group(
iree_task_topology_t* topology, const iree_task_topology_group_t* group);
//===----------------------------------------------------------------------===//
// Topology initialization helpers
//===----------------------------------------------------------------------===//
// Initializes a topology with the specified number of groups.
// 0 is a valid value, indicating that only donated threads will be used to
// perform work. Groups will have no specific affinity and rely on the OS
// scheduler to ensure they are distributed in a meaningful way; this generally
// works out as threads created within a process are usually rotated across
// preferred processors by default.
void iree_task_topology_initialize_from_group_count(
iree_host_size_t group_count, iree_task_topology_t* out_topology);
// Initializes a topology with one group for each physical core with the given
// NUMA node ID (usually package or cluster). Up to |max_core_count| physical
// cores will be selected from the node.
void iree_task_topology_initialize_from_physical_cores(
iree_task_topology_node_id_t node_id, iree_host_size_t max_core_count,
iree_task_topology_t* out_topology);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // IREE_TASK_TOPOLOGY_H_