Skip to content

Commit

Permalink
Release 18.08
Browse files Browse the repository at this point in the history
  • Loading branch information
TelmoARM committed Aug 31, 2018
1 parent deb3bdb commit ce3e84a
Show file tree
Hide file tree
Showing 37 changed files with 4,045 additions and 1,216 deletions.
66 changes: 66 additions & 0 deletions 1.0/ArmnnDriver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#pragma once

#include <HalInterfaces.h>

#include "ArmnnDriverImpl.hpp"
#include "ArmnnDevice.hpp"

#include <log/log.h>

namespace armnn_driver
{
namespace V1_0
{

class ArmnnDriver : public ArmnnDevice, public ::android::hardware::neuralnetworks::V1_0::IDevice
{
public:
ArmnnDriver(DriverOptions options)
: ArmnnDevice(std::move(options))
{
ALOGV("V1_0::ArmnnDriver::ArmnnDriver()");
}
~ArmnnDriver() {}

public:
Return<void> getCapabilities(
::android::hardware::neuralnetworks::V1_0::IDevice::getCapabilities_cb cb)
{
ALOGV("V1_0::ArmnnDriver::getCapabilities()");

return ArmnnDriverImpl::getCapabilities(m_Runtime, cb);
}

Return<void> getSupportedOperations(
const ::android::hardware::neuralnetworks::V1_0::Model& model,
::android::hardware::neuralnetworks::V1_0::IDevice::getSupportedOperations_cb cb)
{
ALOGV("V1_0::ArmnnDriver::getSupportedOperations()");

return ArmnnDriverImpl::getSupportedOperations(m_Runtime, m_Options, model, cb);
}

Return<ErrorStatus> prepareModel(
const ::android::hardware::neuralnetworks::V1_0::Model& model,
const android::sp<IPreparedModelCallback>& cb)
{
ALOGV("V1_0::ArmnnDriver::prepareModel()");

return ArmnnDriverImpl::prepareModel(m_Runtime, m_ClTunedParameters, m_Options, model, cb);
}

Return<DeviceStatus> getStatus()
{
ALOGV("V1_0::ArmnnDriver::getStatus()");

return ArmnnDriverImpl::getStatus();
}
};

} // armnn_driver::namespace V1_0
} // namespace armnn_driver
277 changes: 277 additions & 0 deletions 1.0/ArmnnDriverImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include "ArmnnDriverImpl.hpp"
#include "ModelToINetworkConverter.hpp"
#include "ArmnnPreparedModel.hpp"
#include "SystemPropertiesUtils.hpp"

#if defined(ARMNN_ANDROID_P)
// The headers of the ML framework have changed between Android O and Android P.
// The validation functions have been moved into their own header, ValidateHal.h.
#include <ValidateHal.h>
#endif

#include <log/log.h>

using namespace std;
using namespace android;
using namespace android::nn;
using namespace android::hardware;

namespace
{

const char *g_Float32PerformanceExecTimeName = "ArmNN.float32Performance.execTime";
const char *g_Float32PerformancePowerUsageName = "ArmNN.float32Performance.powerUsage";
const char *g_Quantized8PerformanceExecTimeName = "ArmNN.quantized8Performance.execTime";
const char *g_Quantized8PerformancePowerUsageName = "ArmNN.quantized8Performance.powerUsage";

void NotifyCallbackAndCheck(const sp<IPreparedModelCallback>& callback,
ErrorStatus errorStatus,
const sp<IPreparedModel>& preparedModelPtr)
{
Return<void> returned = callback->notify(errorStatus, preparedModelPtr);
// This check is required, if the callback fails and it isn't checked it will bring down the service
if (!returned.isOk())
{
ALOGE("V1_0::ArmnnDriverImpl::prepareModel: hidl callback failed to return properly: %s ",
returned.description().c_str());
}
}

Return<ErrorStatus> FailPrepareModel(ErrorStatus error,
const string& message,
const sp<IPreparedModelCallback>& callback)
{
ALOGW("V1_0::ArmnnDriverImpl::prepareModel: %s", message.c_str());
NotifyCallbackAndCheck(callback, error, nullptr);
return error;
}

} // namespace

namespace armnn_driver
{
namespace V1_0
{

Return<void> ArmnnDriverImpl::getCapabilities(
const armnn::IRuntimePtr& runtime,
neuralnetworks::V1_0::IDevice::getCapabilities_cb cb)
{
ALOGV("V1_0::ArmnnDriverImpl::getCapabilities()");

neuralnetworks::V1_0::Capabilities capabilities;
if (runtime)
{
capabilities.float32Performance.execTime =
ParseSystemProperty(g_Float32PerformanceExecTimeName, .1f);

capabilities.float32Performance.powerUsage =
ParseSystemProperty(g_Float32PerformancePowerUsageName, .1f);

capabilities.quantized8Performance.execTime =
ParseSystemProperty(g_Quantized8PerformanceExecTimeName, .1f);

capabilities.quantized8Performance.powerUsage =
ParseSystemProperty(g_Quantized8PerformancePowerUsageName, .1f);

cb(ErrorStatus::NONE, capabilities);
}
else
{
capabilities.float32Performance.execTime = 0;
capabilities.float32Performance.powerUsage = 0;
capabilities.quantized8Performance.execTime = 0;
capabilities.quantized8Performance.powerUsage = 0;

cb(ErrorStatus::DEVICE_UNAVAILABLE, capabilities);
}

return Void();
}

Return<void> ArmnnDriverImpl::getSupportedOperations(
const armnn::IRuntimePtr& runtime,
const DriverOptions& options,
const neuralnetworks::V1_0::Model& model,
neuralnetworks::V1_0::IDevice::getSupportedOperations_cb cb)
{
ALOGV("V1_0::ArmnnDriverImpl::getSupportedOperations()");

vector<bool> result;

if (!runtime)
{
cb(ErrorStatus::DEVICE_UNAVAILABLE, result);
return Void();
}

// Run general model validation, if this doesn't pass we shouldn't analyse the model anyway
if (!android::nn::validateModel(model))
{
cb(ErrorStatus::INVALID_ARGUMENT, result);
return Void();
}

// Attempt to convert the model to an ArmNN input network (INetwork).
ModelToINetworkConverter modelConverter(options.GetComputeDevice(), model,
options.GetForcedUnsupportedOperations());

if (modelConverter.GetConversionResult() != ConversionResult::Success
&& modelConverter.GetConversionResult() != ConversionResult::UnsupportedFeature)
{
cb(ErrorStatus::GENERAL_FAILURE, result);
return Void();
}

// Check each operation if it was converted successfully and copy the flags
// into the result (vector<bool>) that we need to return to Android
result.reserve(model.operations.size());
for (uint32_t operationIdx = 0; operationIdx < model.operations.size(); operationIdx++)
{
bool operationSupported = modelConverter.IsOperationSupported(operationIdx);
result.push_back(operationSupported);
}

cb(ErrorStatus::NONE, result);
return Void();
}

Return<ErrorStatus> ArmnnDriverImpl::prepareModel(
const armnn::IRuntimePtr& runtime,
const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
const DriverOptions& options,
const neuralnetworks::V1_0::Model& model,
const sp<IPreparedModelCallback>& cb,
bool float32ToFloat16)
{
ALOGV("V1_0::ArmnnDriverImpl::prepareModel()");

if (cb.get() == nullptr)
{
ALOGW("V1_0::ArmnnDriverImpl::prepareModel: Invalid callback passed to prepareModel");
return ErrorStatus::INVALID_ARGUMENT;
}

if (!runtime)
{
return FailPrepareModel(ErrorStatus::DEVICE_UNAVAILABLE,
"V1_0::ArmnnDriverImpl::prepareModel: Device unavailable", cb);
}

if (!android::nn::validateModel(model))
{
return FailPrepareModel(ErrorStatus::INVALID_ARGUMENT,
"V1_0::ArmnnDriverImpl::prepareModel: Invalid model passed as input", cb);
}

// Deliberately ignore any unsupported operations requested by the options -
// at this point we're being asked to prepare a model that we've already declared support for
// and the operation indices may be different to those in getSupportedOperations anyway.
set<unsigned int> unsupportedOperations;
ModelToINetworkConverter modelConverter(options.GetComputeDevice(), model,
unsupportedOperations);

if (modelConverter.GetConversionResult() != ConversionResult::Success)
{
FailPrepareModel(ErrorStatus::GENERAL_FAILURE, "ModelToINetworkConverter failed", cb);
return ErrorStatus::NONE;
}

// optimize the network
armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
armnn::OptimizerOptions OptOptions;
OptOptions.m_ReduceFp32ToFp16 = float32ToFloat16;

try
{
optNet = armnn::Optimize(*modelConverter.GetINetwork(),
{options.GetComputeDevice()},
runtime->GetDeviceSpec(),
OptOptions);
}
catch (armnn::Exception &e)
{
stringstream message;
message << "armnn::Exception (" << e.what() << ") caught from optimize.";
FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
return ErrorStatus::NONE;
}

// Check that the optimized network is valid.
if (!optNet)
{
FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
"V1_0::ArmnnDriverImpl::prepareModel: Invalid optimized network", cb);
return ErrorStatus::NONE;
}

// Export the optimized network graph to a dot file if an output dump directory
// has been specified in the drivers' arguments.
ExportNetworkGraphToDotFile(*optNet,
options.GetRequestInputsAndOutputsDumpDir(),
model);

// load it into the runtime
armnn::NetworkId netId = 0;
try
{
if (runtime->LoadNetwork(netId, move(optNet)) != armnn::Status::Success)
{
return FailPrepareModel(ErrorStatus::GENERAL_FAILURE,
"V1_0::ArmnnDriverImpl::prepareModel: Network could not be loaded", cb);
}
}
catch (armnn::Exception& e)
{
stringstream message;
message << "armnn::Exception (" << e.what()<< ") caught from LoadNetwork.";
FailPrepareModel(ErrorStatus::GENERAL_FAILURE, message.str(), cb);
return ErrorStatus::NONE;
}

unique_ptr<ArmnnPreparedModel> preparedModel(new ArmnnPreparedModel(
netId,
runtime.get(),
model,
options.GetRequestInputsAndOutputsDumpDir(),
options.IsGpuProfilingEnabled()
));

// Run a single 'dummy' inference of the model. This means that CL kernels will get compiled (and tuned if
// this is enabled) before the first 'real' inference which removes the overhead of the first inference.
preparedModel->ExecuteWithDummyInputs();

if (clTunedParameters &&
options.GetClTunedParametersMode() == armnn::IGpuAccTunedParameters::Mode::UpdateTunedParameters)
{
// Now that we've done one inference the CL kernel parameters will have been tuned, so save the updated file.
try
{
clTunedParameters->Save(options.GetClTunedParametersFile().c_str());
}
catch (const armnn::Exception& error)
{
ALOGE("V1_0::ArmnnDriverImpl: Failed to save CL tuned parameters file '%s': %s",
options.GetClTunedParametersFile().c_str(), error.what());
}
}

NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel.release());

return ErrorStatus::NONE;
}

Return<DeviceStatus> ArmnnDriverImpl::getStatus()
{
ALOGV("V1_0::ArmnnDriverImpl::getStatus()");

return DeviceStatus::AVAILABLE;
}

} // armnn_driver::namespace V1_0
} // namespace armnn_driver
41 changes: 41 additions & 0 deletions 1.0/ArmnnDriverImpl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#pragma once

#include <HalInterfaces.h>

#include "DriverOptions.hpp"

#include <armnn/ArmNN.hpp>

namespace armnn_driver
{
namespace V1_0
{

class ArmnnDriverImpl
{
public:
static Return<void> getCapabilities(
const armnn::IRuntimePtr& runtime,
::android::hardware::neuralnetworks::V1_0::IDevice::getCapabilities_cb cb);
static Return<void> getSupportedOperations(
const armnn::IRuntimePtr& runtime,
const DriverOptions& options,
const ::android::hardware::neuralnetworks::V1_0::Model& model,
::android::hardware::neuralnetworks::V1_0::IDevice::getSupportedOperations_cb cb);
static Return<ErrorStatus> prepareModel(
const armnn::IRuntimePtr& runtime,
const armnn::IGpuAccTunedParametersPtr& clTunedParameters,
const DriverOptions& options,
const ::android::hardware::neuralnetworks::V1_0::Model& model,
const android::sp<IPreparedModelCallback>& cb,
bool float32ToFloat16 = false);
static Return<DeviceStatus> getStatus();
};

} // namespace armnn_driver::V1_0
} // namespace armnn_driver
Loading

0 comments on commit ce3e84a

Please sign in to comment.