blob: ede9dd642a8962a80b09f31db0442cb1a80490c4 [file] [log] [blame]
/*
* Copyright (c) 2021 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/****************************************************************************
* Includes
****************************************************************************/
#include "command_stream.hpp"
#include <inttypes.h>
#include <stdio.h>
using namespace std;
namespace EthosU {
namespace CommandStream {
/****************************************************************************
* DataPointer
****************************************************************************/
DataPointer::DataPointer() : data(nullptr), size(0) {}
DataPointer::DataPointer(const char *_data, size_t _size) : data(_data), size(_size) {}
bool DataPointer::operator!=(const DataPointer &other) {
if (size != other.size) {
return true;
}
for (size_t i = 0; i < size; i++) {
if (data[i] != other.data[i]) {
return true;
}
}
return false;
}
/****************************************************************************
* PmuConfig
****************************************************************************/
Pmu::Pmu(ethosu_driver *_drv, const PmuEvents &_config) : drv(_drv), config(_config) {
// Enable PMU block
ETHOSU_PMU_Enable_v2(drv);
// Enable cycle counter
ETHOSU_PMU_CNTR_Enable_v2(drv, ETHOSU_PMU_CCNT_Msk);
// Configure event types
for (size_t i = 0; i < config.size(); i++) {
ETHOSU_PMU_Set_EVTYPER_v2(drv, i, config[i]);
ETHOSU_PMU_CNTR_Enable_v2(drv, 1 << i);
}
}
void Pmu::clear() {
ETHOSU_PMU_CYCCNT_Reset_v2(drv);
ETHOSU_PMU_EVCNTR_ALL_Reset_v2(drv);
}
void Pmu::print() {
printf("PMU={cycleCount=%llu, events=[%" PRIu32 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 "]}\n",
ETHOSU_PMU_Get_CCNTR_v2(drv),
ETHOSU_PMU_Get_EVCNTR_v2(drv, 0),
ETHOSU_PMU_Get_EVCNTR_v2(drv, 1),
ETHOSU_PMU_Get_EVCNTR_v2(drv, 2),
ETHOSU_PMU_Get_EVCNTR_v2(drv, 3));
}
uint64_t Pmu::getCycleCount() const {
return ETHOSU_PMU_Get_CCNTR_v2(drv);
}
uint32_t Pmu::getEventCount(size_t index) const {
return ETHOSU_PMU_Get_EVCNTR_v2(drv, index);
}
/****************************************************************************
* CommandStream
****************************************************************************/
CommandStream::CommandStream(const DataPointer &_commandStream,
const BasePointers &_basePointers,
const PmuEvents &_pmuEvents) :
drv(ethosu_reserve_driver()),
commandStream(_commandStream), basePointers(_basePointers), pmu(drv, _pmuEvents) {
// Disable clock gating, else the NPU PMU will be clock gated and report too few cycles
ethosu_set_clock_and_power(&drv->dev, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE);
// Use simplified driver setup
ethosu_set_power_mode(drv, true);
}
CommandStream::~CommandStream() {
ethosu_set_power_mode(drv, false);
ethosu_release_driver(drv);
}
int CommandStream::run(size_t repeat) {
// Base pointer array
uint64_t baseAddress[ETHOSU_DRIVER_BASEP_INDEXES];
size_t baseAddressSize[ETHOSU_DRIVER_BASEP_INDEXES];
for (size_t i = 0; i < ETHOSU_DRIVER_BASEP_INDEXES; i++) {
baseAddress[i] = reinterpret_cast<uint64_t>(basePointers[i].data);
baseAddressSize[i] = reinterpret_cast<size_t>(basePointers[i].size);
}
while (repeat-- > 0) {
int error = ethosu_invoke(
drv, commandStream.data, commandStream.size, baseAddress, baseAddressSize, ETHOSU_DRIVER_BASEP_INDEXES);
if (error != 0) {
printf("Inference failed. error=%d\n", error);
return 1;
}
// Wait for interrupt
while (true) {
uint16_t status;
ethosu_get_status_mask(&drv->dev, &status);
// Return if NPU raise error status
if (status & 0xcc) {
printf("Job failed with error. status=0x%08x\n", status);
return 1;
}
// Break loop if job is no longer running
if ((status & 1) == 0) {
break;
}
// Sleep waiting on interrupt
__WFI();
}
}
return 0;
}
DataPointer &CommandStream::getCommandStream() {
return commandStream;
}
BasePointers &CommandStream::getBasePointers() {
return basePointers;
}
Pmu &CommandStream::getPmu() {
return pmu;
}
}; // namespace CommandStream
}; // namespace EthosU