[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