[Mlir-commits] [mlir] [mlir] Target Description and Cost Model in MLIR (PR #85141)
Mike Urbach
llvmlistbot at llvm.org
Wed Mar 13 16:51:54 PDT 2024
================
@@ -0,0 +1,514 @@
+//===- SYSTEMDESC.h - class to represent hardware configuration --*- C++
+//-*-===//
+//
+// Part of the LLVM Project, 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Hardware configuration provides commonly used hardware information to
+// different users, such as optimization passes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_SUPPORT_SYSTEMDESC_H
+#define MLIR_SUPPORT_SYSTEMDESC_H
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/Support/FileUtilities.h"
+#include "mlir/Support/LogicalResult.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/JSON.h"
+
+/// Sytem description file contains a list of device descriptions that
+/// each describe a device (e.g., CPU, GPU, ASIC, etc.) in the system.
+/// Example:
+/// [
+/// {
+/// "ID": 1,
+/// "TYPE": "CPU",
+/// "DESCRIPTION": "Intel Xeon 8480",
+/// "L1_CACHE_SIZE_IN_BYTES": 8192,
+/// ...
+/// },
+/// {
+///
+/// },
+/// ...
+/// ]
+namespace mlir {
+
+/// Describes the individual device from the system description
+class DeviceDesc {
+public:
+ /// Some typedefs
+ using DeviceID = uint32_t;
+ using DevicePropertyName = std::string;
+ struct DevicePropertyValue {
+ enum Tag { INT, DOUBLE, INT_VECTOR, DOUBLE_VECTOR } tag;
+ struct Data {
+ int64_t iValue;
+ double dValue;
+ std::vector<int64_t> ivValue;
+ std::vector<double> dvValue;
+
+ Data() : iValue(0), dValue(0.0), ivValue({0}), dvValue({0.0}) {}
+ ~Data() {}
+ } data;
+
+ DevicePropertyValue() = default;
+ DevicePropertyValue(const mlir::DeviceDesc::DevicePropertyValue &rhs) {
+ this->tag = rhs.tag;
+ if (this->tag == INT)
+ this->data.iValue = rhs.data.iValue;
+ else if (this->tag == DOUBLE)
+ this->data.dValue = rhs.data.dValue;
+ else if (this->tag == INT_VECTOR)
+ this->data.ivValue = rhs.data.ivValue;
+ else
+ this->data.dvValue = rhs.data.dvValue;
+ }
+ bool operator==(const mlir::DeviceDesc::DevicePropertyValue &rhs) const {
+ return tag == rhs.tag &&
+ ((tag == INT && data.iValue == rhs.data.iValue) ||
+ (tag == DOUBLE && data.dValue == rhs.data.dValue) ||
+ (tag == INT_VECTOR && data.ivValue == rhs.data.ivValue) ||
+ (tag == DOUBLE_VECTOR && data.dvValue == rhs.data.dvValue));
+ }
+ bool operator!=(const mlir::DeviceDesc::DevicePropertyValue &rhs) const {
+ return !(*this == rhs);
+ }
+ };
+ using DevicePropertiesMapTy =
+ std::map<DevicePropertyName, DevicePropertyValue>;
+
+ typedef enum { CPU, GPU, SPECIAL } DeviceType;
+
+ /// Basic constructor
+ DeviceDesc() = delete;
+ DeviceDesc(DeviceID id, DeviceType type) : ID(id), type(type) {}
+ bool operator==(const mlir::DeviceDesc &rhs) const {
+ return ID == rhs.getID() && type == rhs.getType() &&
+ deviceProperties == rhs.getProperties();
+ }
+ bool operator!=(const mlir::DeviceDesc &rhs) const { return !(*this == rhs); }
+
+ /// Type converters
+ static DeviceID strToDeviceID(const std::string &id_str) {
+ llvm::Expected<int64_t> id = llvm::json::parse<int64_t>(id_str);
+ if (!id)
+ llvm::report_fatal_error("Value of \"ID\" is not int");
+ return static_cast<DeviceID>(id.get());
+ }
+ static DeviceType strToDeviceType(const std::string &type_str) {
+ if (type_str == "CPU")
+ return DeviceType::CPU;
+ else if (type_str == "GPU")
+ return DeviceType::GPU;
+ else if (type_str == "SPECIAL")
+ return DeviceType::SPECIAL;
+ llvm::report_fatal_error("Value of \"Type\" is not CPU, GPU, or SPECIAL");
+ }
+
+ /// Set description
+ DeviceDesc &setDescription(std::string desc) {
+ description = desc;
+ return *this;
+ }
+ /// Set property
+ DeviceDesc &setProperty(llvm::StringRef name, int64_t iv) {
+ DevicePropertyValue value;
+ value.tag = DevicePropertyValue::Tag::INT;
+ value.data.iValue = iv;
+ auto inserted =
+ deviceProperties.insert(std::make_pair(std::string(name), value));
+ if (!inserted.second && inserted.first->second != value) {
+ llvm::report_fatal_error("Duplicate device property name found:" + name);
+ }
+ return *this;
+ }
+ DeviceDesc &setProperty(llvm::StringRef name, double dv) {
+ DevicePropertyValue value;
+ value.tag = DevicePropertyValue::Tag::DOUBLE;
+ value.data.dValue = dv;
+ auto inserted =
+ deviceProperties.insert(std::make_pair(std::string(name), value));
+ if (!inserted.second && inserted.first->second != value) {
+ llvm::report_fatal_error("Duplicate device property name found:" + name);
+ }
+ return *this;
+ }
+ DeviceDesc &setProperty(llvm::StringRef name,
+ const std::vector<int64_t> &ivv) {
+ DevicePropertyValue value;
+ value.tag = DevicePropertyValue::Tag::INT_VECTOR;
+ value.data.ivValue = ivv;
+ auto inserted =
+ deviceProperties.insert(std::make_pair(std::string(name), value));
+ if (!inserted.second && inserted.first->second != value) {
+ llvm::report_fatal_error("Duplicate device property name found:" + name);
+ }
+ return *this;
+ }
+ DeviceDesc &setProperty(llvm::StringRef name,
+ const std::vector<double> &idv) {
+ DevicePropertyValue value;
+ value.tag = DevicePropertyValue::Tag::DOUBLE_VECTOR;
+ value.data.dvValue = idv;
+ auto inserted =
+ deviceProperties.insert(std::make_pair(std::string(name), value));
+ if (!inserted.second && inserted.first->second != value) {
+ llvm::report_fatal_error("Duplicate device property name found:" + name);
+ }
+ return *this;
+ }
+ // We provide convenience interface to handle int/float value as string
+ DeviceDesc &setProperty(llvm::StringRef name, const std::string &json_value) {
+ if (json_value.length() > 0 && json_value[0] == '[') {
+ // Parse as an array
+ llvm::Expected<std::vector<int64_t>> ivv =
+ llvm::json::parse<std::vector<int64_t>>(json_value);
+ if (ivv) {
+ *this = this->setProperty(name, ivv.get());
+ return *this;
+ }
+
+ llvm::Expected<std::vector<double>> idv =
+ llvm::json::parse<std::vector<double>>(json_value);
+ if (idv) {
+ *this = this->setProperty(name, idv.get());
+ return *this;
+ }
+ } else {
+ // int64_t because llvm::json has int64_t support (not int)
+ llvm::Expected<int64_t> iv = llvm::json::parse<int64_t>(json_value);
+ if (iv) {
+ *this = this->setProperty(name, iv.get());
+ return *this;
+ }
+
+ // Int type failed, try float now.
+ // double because llvm::json has double support (not float)
+ llvm::Expected<double> dv = llvm::json::parse<double>(json_value);
+ if (dv) {
+ *this = this->setProperty(name, dv.get());
+ return *this;
+ }
+ }
+
+ llvm::report_fatal_error(
+ "Neither int/float/vector value in Device Description: key " + name);
+ }
+
+ /// Get ID
+ DeviceID getID() const { return ID; }
+ /// Get device type
+ DeviceType getType() const { return type; }
+ /// Get device description
+ std::string getDescription() const { return description; }
+ /// Get all of device properties
+ const DevicePropertiesMapTy &getProperties() const {
+ return deviceProperties;
+ }
+ /// Get property value: returns the value of the property with given name, if
+ /// it exists. Otherwise throws exception (TODO)
+ std::optional<int64_t> getPropertyValueAsInt(llvm::StringRef name) const {
+ // check that property with the given name exists
+ auto iter = deviceProperties.find(std::string(name));
+ if (iter == deviceProperties.end()) {
+ return std::nullopt;
+ }
+ // TODO: we can do a tag check here.
+ return iter->second.data.iValue;
+ }
+ std::optional<double> getPropertyValueAsFloat(llvm::StringRef name) const {
+ // check that property with the given name exists
+ auto iter = deviceProperties.find(std::string(name));
+ if (iter == deviceProperties.end()) {
+ return std::nullopt;
+ }
+ // TODO: we can do a tag check here.
+ return iter->second.data.dValue;
+ }
+
+ /// Special functions
+ auto getAllDevicePropertyNames() const {
+ return llvm::map_range(
+ deviceProperties,
+ [](const DevicePropertiesMapTy::value_type &item) -> llvm::StringRef {
+ return item.first;
+ });
+ }
+
+ /// We use a list of key-value pairs to represent a system description in
+ /// JSON.
+ using DeviceDescJSONTy = std::map<std::string, std::string>;
+ static DeviceDesc
+ parseDeviceDescFromJSON(const DeviceDescJSONTy &device_desc);
+
+ // -----------------------------------------------------------------------
+ // CPU specific methods
----------------
mikeurbach wrote:
IMHO specific things like this shouldn't be in the core DeviceDesc.
https://github.com/llvm/llvm-project/pull/85141
More information about the Mlir-commits
mailing list