Skip to content

Commit 21fbca4

Browse files
csullivanylc
authored andcommitted
[Hexagon] Introduce new DeviceAPI (apache#9355)
* Compile hexagon device api from runtime/hexagon/hexagon when building for hexagon and USE_HEXAGON_DEVICE is not set. * Add hexagon_common.h utilities including custom tvm runtime logging for hexagon. * Introduce HexagonBuffer class to store hexagon allocation metadata. * Add HexagonDeviceAPIv2 for use on hexagon. * Add hexagon packed function wrapper. * Add custom linked param lookup for hexagon that wraps params in an unmanaged HexagonBuffer. * Add custom hexagon module based of library module node. * Apply clang formatting * Apply cpplint changes.
1 parent 46109c4 commit 21fbca4

File tree

8 files changed

+768
-12
lines changed

8 files changed

+768
-12
lines changed

cmake/modules/Hexagon.cmake

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,22 @@ if(BUILD_FOR_HEXAGON)
5353
include_directories(SYSTEM ${HEXAGON_SDK_INCLUDES} ${HEXAGON_QURT_INCLUDES})
5454
endif()
5555

56-
if(USE_HEXAGON_LAUNCHER STREQUAL "ON")
57-
set(USE_HEXAGON_DEVICE "${PICK_SIM}")
58-
else()
59-
if(USE_HEXAGON_DEVICE STREQUAL "OFF")
60-
list(APPEND COMPILER_SRCS src/target/opt/build_hexagon_off.cc)
61-
return()
62-
elseif(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}" AND
63-
NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}")
64-
set(ERROR_MSG
65-
"USE_HEXAGON_DEVICE must be one of [${PICK_NONE}|${PICK_SIM}|${PICK_HW}]")
66-
message(SEND_ERROR "${ERROR_MSG}")
67-
return()
56+
# Don't run these checks when compiling Hexagon device code,
57+
# e.g. when compiling the TVM runtime for Hexagon.
58+
if (NOT BUILD_FOR_HEXAGON)
59+
if(USE_HEXAGON_LAUNCHER STREQUAL "ON")
60+
set(USE_HEXAGON_DEVICE "${PICK_SIM}")
61+
else()
62+
if(USE_HEXAGON_DEVICE STREQUAL "OFF")
63+
list(APPEND COMPILER_SRCS src/target/opt/build_hexagon_off.cc)
64+
return()
65+
elseif(NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_SIM}" AND
66+
NOT USE_HEXAGON_DEVICE STREQUAL "${PICK_HW}")
67+
set(ERROR_MSG
68+
"USE_HEXAGON_DEVICE must be one of [${PICK_NONE}|${PICK_SIM}|${PICK_HW}]")
69+
message(SEND_ERROR "${ERROR_MSG}")
70+
return()
71+
endif()
6872
endif()
6973
endif()
7074

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "hexagon_buffer.h"
21+
22+
#include <tvm/runtime/module.h>
23+
24+
#include <string>
25+
#include <utility>
26+
27+
#include "hexagon_common.h"
28+
29+
namespace tvm {
30+
namespace runtime {
31+
namespace hexagon {
32+
33+
static size_t GetDataAlignment(const DLDataType dtype) {
34+
size_t align = (dtype.bits / 8) * dtype.lanes;
35+
if (align < kAllocAlignment) return kAllocAlignment;
36+
return align;
37+
}
38+
39+
HexagonBuffer::HexagonBuffer(int ndim, const int64_t* shape, DLDataType dtype,
40+
Optional<String> scope) {
41+
ICHECK_LE(ndim, 1) << "Hexagon currently only supports flat allocations "
42+
<< "and arrays of flat allocations.";
43+
44+
size_t alignment = GetDataAlignment(dtype);
45+
// TODO(csullivan): Extend to support arrays of allocations.
46+
// Move assignment from r-value constructed flat allocation.
47+
*this = HexagonBuffer(shape[0] * (dtype.bits / 8) * dtype.lanes, alignment, scope);
48+
}
49+
50+
HexagonBuffer::HexagonBuffer(size_t nbytes, size_t alignment, Optional<String> scope) {
51+
void* ptr = nullptr;
52+
int ret = posix_memalign(&ptr, alignment, nbytes);
53+
if (ret != 0) {
54+
throw std::bad_alloc();
55+
}
56+
allocations_.push_back(ptr);
57+
SetStorageScope(scope);
58+
}
59+
60+
HexagonBuffer::HexagonBuffer(void* data, Optional<String> scope) : managed_{false} {
61+
SetStorageScope(scope);
62+
allocations_.push_back(data);
63+
}
64+
65+
HexagonBuffer::~HexagonBuffer() {
66+
if (managed_) {
67+
for (auto& ptr : allocations_) {
68+
free(ptr);
69+
}
70+
}
71+
}
72+
73+
HexagonBuffer::HexagonBuffer(HexagonBuffer&& other)
74+
: allocations_(other.allocations_),
75+
managed_(other.managed_),
76+
storage_scope_(other.storage_scope_) {
77+
other.allocations_.clear();
78+
other.managed_ = false;
79+
other.storage_scope_ = StorageScope::kDDR;
80+
}
81+
82+
HexagonBuffer& HexagonBuffer::operator=(HexagonBuffer&& other) {
83+
std::swap(allocations_, other.allocations_);
84+
std::swap(managed_, other.managed_);
85+
std::swap(storage_scope_, other.storage_scope_);
86+
return *this;
87+
}
88+
89+
void* HexagonBuffer::GetPointer() {
90+
if (!allocations_.size()) {
91+
return nullptr;
92+
}
93+
return (allocations_.size() > 1) ? allocations_.data() : allocations_[0];
94+
}
95+
96+
HexagonBuffer::StorageScope HexagonBuffer::GetStorageScope() const { return storage_scope_; }
97+
98+
void HexagonBuffer::SetStorageScope(Optional<String> scope) {
99+
if (!scope.defined()) {
100+
storage_scope_ = StorageScope::kDDR;
101+
} else {
102+
if (scope.value() == "global") {
103+
storage_scope_ = StorageScope::kDDR;
104+
} else if (scope.value() == "global.vtcm") {
105+
storage_scope_ = StorageScope::kVTCM;
106+
} else {
107+
CHECK(false) << "Encountered unknown HexagonBuffer storage scope: "
108+
<< std::string(scope.value());
109+
}
110+
}
111+
}
112+
113+
HexagonBuffer* IsHexagonBuffer(DLTensor* tensor) {
114+
if (TVMDeviceExtType(tensor->device.device_type) == kDLHexagon) {
115+
return static_cast<HexagonBuffer*>(tensor->data);
116+
}
117+
return nullptr;
118+
}
119+
120+
} // namespace hexagon
121+
} // namespace runtime
122+
} // namespace tvm
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#ifndef TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_BUFFER_H_
21+
#define TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_BUFFER_H_
22+
23+
#include <tvm/runtime/c_runtime_api.h>
24+
#include <tvm/runtime/device_api.h>
25+
#include <tvm/runtime/logging.h>
26+
#include <tvm/runtime/ndarray.h>
27+
#include <tvm/runtime/packed_func.h>
28+
29+
#include <vector>
30+
31+
namespace tvm {
32+
namespace runtime {
33+
namespace hexagon {
34+
35+
class HexagonBuffer {
36+
public:
37+
/* \brief Allocate memory within hexagon accessible memory
38+
* scopes.
39+
*
40+
* \param ndim The number of dimensions of physical storage
41+
* to allocate.
42+
*
43+
* \param shape The shape of the ndarray for which to allocate
44+
* physical storage.
45+
*
46+
* \param dtype The data type of the physical storage.
47+
*
48+
* \param scope Optional storage scope indicating the memory
49+
* space in which to allocate. Defaults to global system
50+
* memory (DDR).
51+
*/
52+
HexagonBuffer(int ndim, const int64_t* shape, DLDataType dtype, Optional<String> scope);
53+
54+
/* \brief Allocate memory within hexagon accessible memory
55+
* scopes.
56+
*
57+
* \param nbytes The number of bytes of flat physical storage
58+
* to allocate.
59+
*
60+
* \param alignment The byte alignment to be used when allocating.
61+
*
62+
* \param scope Optional storage scope indicating the memory
63+
* space in which to allocate. Defaults to global system
64+
* memory (DDR).
65+
*/
66+
HexagonBuffer(size_t nbytes, size_t alignment, Optional<String> scope);
67+
68+
/* \brief Construct a hexagon buffer from externally allocated storage.
69+
*
70+
* \param data The externally allocated storage.
71+
*
72+
* \param scope Optional storage scope indicating the memory
73+
* space in the external allocation belongs. Assumes global system
74+
* memory if not provided.
75+
*/
76+
explicit HexagonBuffer(void* data, Optional<String> scope = Optional<String>());
77+
78+
//! \brief Destruction deallocates the underlying allocations.
79+
~HexagonBuffer();
80+
81+
//! \brief Prevent copy construction of HexagonBuffers.
82+
HexagonBuffer(const HexagonBuffer&) = delete;
83+
84+
//! \brief Prevent copy assignment with HexagonBuffers.
85+
HexagonBuffer& operator=(const HexagonBuffer&) = delete;
86+
87+
//! \brief Allow move construction.
88+
HexagonBuffer(HexagonBuffer&&);
89+
90+
//! \brief Allow move assignment.
91+
HexagonBuffer& operator=(HexagonBuffer&&);
92+
93+
//! \brief Return pointer to allocation or allocations.
94+
void* GetPointer();
95+
96+
//! \brief Memory scopes managed by a Hexagon Buffer.
97+
enum class StorageScope {
98+
//! \brief System DDR corresponding to global storage.
99+
kDDR,
100+
/*! \brief Vector tightly coupled memory corresponding to
101+
* global.vtcm storage.
102+
*/
103+
kVTCM,
104+
};
105+
106+
//! \brief Return storage scope of underlying allocation.
107+
StorageScope GetStorageScope() const;
108+
109+
private:
110+
//! \brief Assign a storage scope to the buffer.
111+
void SetStorageScope(Optional<String> scope);
112+
/*! \brief Array of allocations required by the buffer.
113+
*
114+
* For a 1d (flat) storage, a single contiguous allocation will
115+
* result. For 2d storage, (count, nbytes) = shape, which will
116+
* result in `count` discrete allocations.
117+
*/
118+
std::vector<void*> allocations_;
119+
/*! \brief Whether the allocation(s) present are managed
120+
* and should be deallocated upon destruction.
121+
*/
122+
bool managed_{true};
123+
/*! \brief The underlying storage type in which the allocation
124+
* resides.
125+
*/
126+
StorageScope storage_scope_;
127+
};
128+
129+
HexagonBuffer* IsHexagonBuffer(DLTensor* tensor);
130+
131+
} // namespace hexagon
132+
} // namespace runtime
133+
} // namespace tvm
134+
135+
#endif // TVM_RUNTIME_HEXAGON_HEXAGON_HEXAGON_BUFFER_H_

0 commit comments

Comments
 (0)