Skip to content

Commit

Permalink
[C API] Initial implementation (uber#400)
Browse files Browse the repository at this point in the history
### Summary:

An initial basic implementation of a C API for Neuropod.

### Test Plan:

Added a test that loads a model, runs inference, and verifies the output. More unit tests and integration tests should be added in the future
  • Loading branch information
VivekPanyam authored Jul 23, 2020
1 parent d7bf8b0 commit eae86ce
Show file tree
Hide file tree
Showing 15 changed files with 489 additions and 2 deletions.
26 changes: 26 additions & 0 deletions source/neuropod/bindings/c/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (c) 2020 UATC, LLC
#
# 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
#
# http://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.

cc_library(
name = "c_api",
srcs = glob(["*.cc"]),
hdrs = glob(["*.h"]),
visibility = [
"//neuropod:__subpackages__",
],
deps = [
"//neuropod:neuropod_hdrs",
"//neuropod/internal",
],
)
52 changes: 52 additions & 0 deletions source/neuropod/bindings/c/c_api.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

// Inspired by the TensorFlow C API

#include "neuropod/bindings/c/c_api.h"

#include "neuropod/bindings/c/c_api_internal.h"
#include "neuropod/bindings/c/np_tensor_allocator_internal.h"
#include "neuropod/bindings/c/np_valuemap_internal.h"

// Load a model given a path
void NP_LoadNeuropod(const char *neuropod_path, NP_Neuropod **model, NP_Status *status)
{
*model = new NP_Neuropod();

(*model)->model = std::make_unique<neuropod::Neuropod>(neuropod_path);
}

// Free a model
void NP_FreeNeuropod(NP_Neuropod *model)
{
delete model;
}

// Run inference
// Note: The caller is responsible for freeing the returned NP_NeuropodValueMap
void NP_Infer(NP_Neuropod *model, const NP_NeuropodValueMap *inputs, NP_NeuropodValueMap **outputs, NP_Status *status)
{
*outputs = new NP_NeuropodValueMap();
(*outputs)->data = std::move(*model->model->infer(inputs->data));
}

// Get an allocator for a model
NP_TensorAllocator *NP_GetAllocator(NP_Neuropod *model)
{
auto out = new NP_TensorAllocator();
out->allocator = model->model->get_tensor_allocator();
return out;
}
25 changes: 25 additions & 0 deletions source/neuropod/bindings/c/c_api_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#pragma once

#include "neuropod/neuropod.hh"

#include <memory>

struct NP_Neuropod
{
std::unique_ptr<neuropod::Neuropod> model;
};
46 changes: 46 additions & 0 deletions source/neuropod/bindings/c/np_status.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#include "neuropod/bindings/c/np_status_internal.h"

// Used for creating and deleting new status messages
NP_Status *NP_NewStatus()
{
return new NP_Status();
}

void NP_DeleteStatus(NP_Status *status)
{
delete status;
}

// Clear a status
void NP_ClearStatus(NP_Status *status)
{
status->code = NEUROPOD_OK;
status->message.clear();
}

// Used for getting details about a status
NP_Code NP_GetCode(const NP_Status *status)
{
return status->code;
}

// Get the error message (if any)
const char *NP_GetMessage(const NP_Status *status)
{
return status->message.c_str();
}
5 changes: 4 additions & 1 deletion source/neuropod/bindings/c/np_status.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ typedef struct NP_Status NP_Status;
NP_Status *NP_NewStatus();
void NP_DeleteStatus(NP_Status *status);

// Clear a status
void NP_ClearStatus(NP_Status *status);

// Possible status codes
typedef enum NP_Code
{
Expand All @@ -38,7 +41,7 @@ typedef enum NP_Code
NP_Code NP_GetCode(const NP_Status *status);

// Get the error message (if any)
const char *NP_Message(const NP_Status *status);
const char *NP_GetMessage(const NP_Status *status);

#ifdef __cplusplus
}
Expand Down
27 changes: 27 additions & 0 deletions source/neuropod/bindings/c/np_status_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#pragma once

#include "neuropod/bindings/c/np_status.h"

#include <memory>
#include <string>

struct NP_Status
{
std::string message;
NP_Code code;
};
35 changes: 35 additions & 0 deletions source/neuropod/bindings/c/np_tensor.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#include "neuropod/bindings/c/np_tensor.h"

#include "neuropod/bindings/c/np_tensor_internal.h"
#include "neuropod/internal/neuropod_tensor_raw_data_access.hh"

// For non-string tensors, get a pointer to the underlying data
// Returns nullptr if called on a string tensor
void *NP_GetData(NP_NeuropodTensor *tensor)
{
return neuropod::internal::NeuropodTensorRawDataAccess::get_untyped_data_ptr(*tensor->tensor->as_tensor());
}

// Releases a tensor. The memory might not be deallocated immediately if the tensor is still
// referenced by a value-map object or used by an infer operation.
// This should be called on every tensor returned by the C API.
// See the notes in `np_valuemap.h` and `np_tensor_allocator.h` for more detail.
void NP_FreeTensor(NP_NeuropodTensor *tensor)
{
delete tensor;
}
35 changes: 35 additions & 0 deletions source/neuropod/bindings/c/np_tensor_allocator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#include "neuropod/bindings/c/np_tensor_allocator_internal.h"
#include "neuropod/bindings/c/np_tensor_internal.h"

// Free an allocator
void NP_FreeAllocator(NP_TensorAllocator *allocator)
{
delete allocator;
}

// Allocate a tensor with a specified type and shape
// Note: the caller is responsible for calling NP_FreeTensor on the returned tensor
NP_NeuropodTensor *NP_AllocateTensor(NP_TensorAllocator *allocator, size_t num_dims, int64_t *dims, NP_TensorType type)
{
std::vector<int64_t> d(dims, dims + num_dims);

auto out = new NP_NeuropodTensor();
out->tensor = allocator->allocator->allocate_tensor(d, static_cast<neuropod::TensorType>(type));

return out;
}
26 changes: 26 additions & 0 deletions source/neuropod/bindings/c/np_tensor_allocator_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#pragma once

#include "neuropod/backends/tensor_allocator.hh"
#include "neuropod/bindings/c/np_tensor_allocator.h"

#include <memory>

struct NP_TensorAllocator
{
std::shared_ptr<neuropod::NeuropodTensorAllocator> allocator;
};
26 changes: 26 additions & 0 deletions source/neuropod/bindings/c/np_tensor_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#pragma once

#include "neuropod/bindings/c/np_tensor.h"
#include "neuropod/internal/neuropod_tensor.hh"

#include <memory>

struct NP_NeuropodTensor
{
std::shared_ptr<neuropod::NeuropodValue> tensor;
};
62 changes: 62 additions & 0 deletions source/neuropod/bindings/c/np_valuemap.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* Copyright (c) 2020 UATC, LLC
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
http://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.
*/

#include "neuropod/bindings/c/np_tensor_internal.h"
#include "neuropod/bindings/c/np_valuemap_internal.h"

// Create a new NeuropodValueMap
NP_NeuropodValueMap *NP_NewValueMap()
{
return new NP_NeuropodValueMap();
}

// Free a NeuropodValueMap
void NP_FreeValueMap(NP_NeuropodValueMap *nvm)
{
delete nvm;
}

// Insert a tensor into the provided map
// Overwrites any existing tensors with the same name
// Note: this does not transfer ownership and the caller is still responsible for calling NP_FreeTensor on
// `tensor`
void NP_InsertTensor(NP_NeuropodValueMap *nvm, const char *name, NP_NeuropodTensor *tensor)
{
nvm->data[name] = tensor->tensor;
}

// Given a NP_NeuropodValueMap, find a tensor with name `name` and return it
// If such a tensor is not found, returns nullptr
// Note: the caller is responsible for calling NP_FreeTensor on the returned tensor
NP_NeuropodTensor *NP_GetTensor(const NP_NeuropodValueMap *nvm, const char *name)
{
auto &map = nvm->data;
auto item = map.find(name);
if (item == map.end())
{
return nullptr;
}

auto retval = new NP_NeuropodTensor();
retval->tensor = item->second;

return retval;
}

// Removes a specified tensor from the provided map (if it exists)
void NP_RemoveTensor(NP_NeuropodValueMap *nvm, const char *name)
{
nvm->data.erase(name);
}
Loading

0 comments on commit eae86ce

Please sign in to comment.