Skip to content

Commit 60afa98

Browse files
authored
Add docs for C and C++ to the website (#183)
1 parent bc46639 commit 60afa98

File tree

6 files changed

+282
-3
lines changed

6 files changed

+282
-3
lines changed

docs/website/components/code.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ const LANGUAGE_TAGS = {
6262
"rust": {"bg": "bg-violet-500", tag: "rust"},
6363
"json": { "bg": "bg-orange-500", tag: "json" },
6464
"toml": { "bg": "bg-orange-500", tag: "toml" },
65+
"c": { "bg": "bg-lime-500", tag: "c" },
66+
"cpp": { "bg": "bg-cyan-500", tag: "c++" },
6567
}
6668

6769
const Code = ({

docs/website/components/languageselect.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export const LANGUAGES = [
2222
{ name: "JavaScript", enabled: true },
2323
{ name: "TypeScript", enabled: true },
2424
{ name: "Rust", enabled: true },
25-
{ name: "C", enabled: false },
26-
{ name: "C++", enabled: false },
25+
{ name: "C", enabled: true },
26+
{ name: "C++", enabled: true },
2727
{ name: "C#", enabled: false },
2828
{ name: "Java", enabled: false },
2929
{ name: "Golang", enabled: false },

docs/website/pages/docs/loading.mdx

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,184 @@ Carton::load(
212212
},
213213
)
214214
```
215+
</LanguageItem>
216+
<LanguageItem forLang='c'>
217+
218+
# Loading a model
219+
220+
<div className="flex items-center space-x-3 not-prose">
221+
<p>Select a programming language:</p>
222+
<LanguageSelect/>
223+
</div>
224+
225+
Once you have a packed model, you can load it with a file path or URL. There are two ways to load a model from C. The first uses callbacks:
226+
227+
```c forLang='c'
228+
#include "carton.h"
229+
230+
void load_callback(Carton *model, CartonStatus status, void *callback_arg);
231+
232+
int main()
233+
{
234+
int load_callback_arg = 123;
235+
carton_load("https://carton.pub/google-research/bert-base-uncased", load_callback, (void *)load_callback_arg);
236+
237+
// Make sure the program doesn't end before the async task completes
238+
sleep(60);
239+
}
240+
```
241+
242+
This approach can be useful for integrating with existing async/event systems like [libevent](https://libevent.org/) or [libuv](https://libuv.org/).
243+
244+
One of the caveats is that these callbacks are executed from within opaque Carton-owned threads. As a general rule, it's important to avoid doing blocking I/O or extended periods of CPU-bound work within these callbacks. Doing so could block other tasks within Carton's internal async runtime from executing.
245+
246+
To help ease these restrictions, we provide another approach with `CartonAsyncNotifier`. This lets users wait for or poll for new callbacks on a thread they control, removing the above restrictions and making basic C integrations simpler:
247+
248+
```c forLang='c'
249+
#include "carton.h"
250+
251+
int main()
252+
{
253+
// Create an async notifier
254+
CartonAsyncNotifier *notifier;
255+
carton_async_notifier_create(&notifier);
256+
257+
// Load the model
258+
Carton *model;
259+
CartonNotifierCallback callback;
260+
void *callback_arg = (void *)23;
261+
carton_async_notifier_register(notifier, &callback, &callback_arg);
262+
carton_load("https://carton.pub/google-research/bert-base-uncased", (CartonLoadCallback)callback, callback_arg);
263+
264+
// Wait for the model to load
265+
void *notifier_callback_arg_out;
266+
CartonStatus status;
267+
carton_async_notifier_wait(notifier, (void **)&model, &status, &notifier_callback_arg_out);
268+
assert(notifier_callback_arg_out == (void *)23);
269+
270+
// ...
271+
}
272+
```
273+
274+
With both approaches, Carton loads the model (caching it locally if necessary).
275+
276+
Callbacks and notifications are available for every async function in Carton's interface.
277+
278+
For complete, runnable examples of loading and running a model from C, take a look at this [callback example](https://github.com/VivekPanyam/carton/blob/main/source/carton-bindings-c/tests/basic.c) or this [notifier example](https://github.com/VivekPanyam/carton/blob/main/source/carton-bindings-c/tests/notifier.c).
279+
280+
For more info on async functions in the Carton C interface, see [here](https://github.com/VivekPanyam/carton/blob/main/source/carton-bindings-c/README.md).
281+
282+
If you don't yet have a packed model, take a look at the [packing docs](/docs/packing) or explore the [community model registry](https://carton.pub).
283+
284+
285+
</LanguageItem>
286+
<LanguageItem forLang='c++'>
287+
288+
# Loading a model
289+
290+
<div className="flex items-center space-x-3 not-prose">
291+
<p>Select a programming language:</p>
292+
<LanguageSelect/>
293+
</div>
294+
295+
Once you have a packed model, you can load it with a file path or URL. There are three ways to load a model from C++. The first uses futures:
296+
297+
```cpp forLang='c++'
298+
#include <iostream>
299+
300+
#include "carton.hh"
301+
302+
int main()
303+
{
304+
// Load a model, wait for the future to complete, unwrap the result
305+
auto model = carton::Carton::load("https://carton.pub/google-research/bert-base-uncased").get().get_or_throw();
306+
307+
// Create an input tensor
308+
uint64_t shape[]{1};
309+
auto tensor = carton::Tensor(carton::DataType::kString, shape);
310+
tensor.set_string(0, "Today is a good [MASK].");
311+
312+
// Create a map of inputs
313+
std::unordered_map<std::string, carton::Tensor> inputs;
314+
inputs.insert(std::make_pair("input", std::move(tensor)));
315+
316+
// Run inference, wait for the future to complete, unwrap the result
317+
auto out = model.infer(std::move(inputs)).get().get_or_throw();
318+
319+
// Get the output tensors
320+
const auto tokens = out.get_and_remove("tokens");
321+
const auto scores = out.get_and_remove("scores");
322+
323+
const auto scores_data = static_cast<const float *>(scores.data());
324+
325+
std::cout << "Got output token: " << tokens.get_string(0) << std::endl;
326+
std::cout << "Got output scores: " << scores_data[0] << std::endl;
327+
}
328+
```
329+
330+
In the above example, `load` and `infer` both return `std::future`s.
331+
332+
The second approach uses callbacks:
333+
334+
```cpp forLang='c++'
335+
#include "carton.hh"
336+
337+
void load_callback(carton::Result<carton::Carton> model_result, void *arg);
338+
339+
int main()
340+
{
341+
// Load a model
342+
int load_callback_arg = 42;
343+
carton::Carton::load(
344+
"https://carton.pub/google-research/bert-base-uncased",
345+
load_callback,
346+
(void *)load_callback_arg);
347+
348+
// Make sure the program doesn't end before the async task completes
349+
sleep(60);
350+
}
351+
```
352+
353+
This approach can be useful for integrating with existing async/event systems like [libevent](https://libevent.org/) or [libuv](https://libuv.org/).
354+
355+
One of the caveats is that these callbacks are executed from within opaque Carton-owned threads. As a general rule, it's important to avoid doing blocking I/O or extended periods of CPU-bound work within these callbacks. Doing so could block other tasks within Carton's internal async runtime from executing.
356+
357+
To help ease these restrictions, we provide a third approach with `carton::AsyncNotifier`. This lets users wait for or poll for new callbacks on a thread they control, removing the above restrictions. It also makes waiting on several futures more efficient because you get notified when one is ready instead of having to poll all of them.
358+
359+
```cpp forLang='c++'
360+
#include "carton.hh"
361+
362+
int main()
363+
{
364+
// Create an async notifier
365+
carton::AsyncNotifier<carton::Carton> load_notifier;
366+
367+
// Load a model
368+
carton::Carton::load(
369+
"https://carton.pub/google-research/bert-base-uncased",
370+
load_notifier.handle(),
371+
(void *)42);
372+
373+
// Wait for the model to load
374+
auto [model_result, arg] = load_notifier.wait();
375+
assert(arg == (void *)42);
376+
auto model = model_result.get_or_throw();
377+
378+
// ...
379+
}
380+
```
381+
382+
With all three approaches, Carton loads the model (caching it locally if necessary).
383+
384+
Futures, callbacks and notifications are available for every async function in Carton's interface.
385+
386+
For complete, runnable examples of loading and running a model from C++, take a look at this [callback example](https://github.com/VivekPanyam/carton/blob/main/source/carton-bindings-cpp/tests/callback.cc), this [future example](https://github.com/VivekPanyam/carton/blob/main/source/carton-bindings-cpp/tests/future.cc) or this [notifier example](https://github.com/VivekPanyam/carton/blob/main/source/carton-bindings-cpp/tests/notifier.cc).
387+
388+
For more info on async functions in the Carton C++ interface, see [here](https://github.com/VivekPanyam/carton/blob/main/source/carton-bindings-cpp/README.md).
389+
390+
If you don't yet have a packed model, take a look at the [packing docs](/docs/packing) or explore the [community model registry](https://carton.pub).
391+
392+
215393
</LanguageItem>
216394
<LanguageItem>
217395

docs/website/pages/docs/metadata.mdx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import LanguageSelect, {LanguageSwitch, LanguageItem} from "@/components/languageselect";
22

3+
<LanguageSwitch>
4+
<LanguageItem forLang='python,rust,javascript,typescript'>
5+
36
# Model Metadata
47

58
It's possible to fetch model metadata without loading a model. This approach only fetches the data needed to provide the requested information and is therefore quite efficient even with large models.
@@ -311,5 +314,17 @@ console.log(info.manifest_sha256)
311314
</LanguageItem>
312315
</LanguageSwitch>
313316

317+
318+
</LanguageItem>
319+
<LanguageItem>
320+
321+
This language currently does not support fetching model metadata. Please check the [quickstart guide](/quickstart) for more info or select a different language.
322+
323+
<div className="flex not-prose">
324+
<LanguageSelect/>
325+
</div>
326+
</LanguageItem>
327+
</LanguageSwitch>
328+
314329
import DocsLayout from '@/components/docslayout'
315330
export default ({children}) => <DocsLayout>{children}</DocsLayout>

docs/website/pages/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export default function Home() {
134134
// Display each language twice
135135
[1, 2].flatMap((idx) => LANGUAGES.map((lang) => <span key={`${lang}-${idx}`} className={`${roboto_mono.className} select-none uppercase px-20 text-slate-500`}>
136136
{lang}
137-
{["python", "rust"].indexOf(lang.toLowerCase()) == -1 && <span className='text-sky-400'>*</span>}
137+
{["python", "rust", "c", "c++"].indexOf(lang.toLowerCase()) == -1 && <span className='text-sky-400'>*</span>}
138138
</span>))
139139
}
140140
</div>

docs/website/pages/quickstart.mdx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,88 @@ import LanguageSelect, {LanguageSwitch, LanguageItem} from "@/components/languag
88
<LanguageSelect/>
99
</div>
1010

11+
<LanguageSwitch>
12+
<LanguageItem forLang='c,c++'>
13+
14+
```bash linePrompt='$' forLang='c'
15+
# Pick the appropriate file for your OS and arch
16+
wget https://nightly-assets.carton.run/bindings/carton_c_aarch64-apple-darwin.tar.gz
17+
wget https://nightly-assets.carton.run/bindings/carton_c_aarch64-unknown-linux-gnu.tar.gz
18+
wget https://nightly-assets.carton.run/bindings/carton_c_x86_64-apple-darwin.tar.gz
19+
wget https://nightly-assets.carton.run/bindings/carton_c_x86_64-unknown-linux-gnu.tar.gz
20+
```
21+
22+
```bash linePrompt='$' forLang='c++'
23+
# Pick the appropriate file for your OS and arch
24+
wget https://nightly-assets.carton.run/bindings/carton_cpp_aarch64-apple-darwin.tar.gz
25+
wget https://nightly-assets.carton.run/bindings/carton_cpp_aarch64-unknown-linux-gnu.tar.gz
26+
wget https://nightly-assets.carton.run/bindings/carton_cpp_x86_64-apple-darwin.tar.gz
27+
wget https://nightly-assets.carton.run/bindings/carton_cpp_x86_64-unknown-linux-gnu.tar.gz
28+
```
29+
30+
&nbsp;
31+
# Load and run a model
32+
33+
If you want to run an existing carton model (or "a carton" for short), you can just pass in a file path or URL.
34+
35+
```c forLang='c'
36+
#include "carton.h"
37+
38+
void load_callback(Carton *model, CartonStatus status, void *callback_arg)
39+
{
40+
// ...
41+
}
42+
43+
int main()
44+
{
45+
int load_callback_arg = 123;
46+
carton_load("https://carton.pub/google-research/bert-base-uncased", load_callback, (void *)load_callback_arg);
47+
48+
// Make sure the program doesn't end before the async task completes
49+
sleep(60);
50+
}
51+
```
52+
53+
```cpp forLang='c++'
54+
#include <iostream>
55+
56+
#include "carton.hh"
57+
58+
int main()
59+
{
60+
// Load a model, wait for the future to complete, unwrap the result
61+
auto model = carton::Carton::load("https://carton.pub/google-research/bert-base-uncased").get().get_or_throw();
62+
63+
// Create an input tensor
64+
uint64_t shape[]{1};
65+
auto tensor = carton::Tensor(carton::DataType::kString, shape);
66+
tensor.set_string(0, "Today is a good [MASK].");
67+
68+
// Create a map of inputs
69+
std::unordered_map<std::string, carton::Tensor> inputs;
70+
inputs.insert(std::make_pair("input", std::move(tensor)));
71+
72+
// Run inference, wait for the future to complete, unwrap the result
73+
auto out = model.infer(std::move(inputs)).get().get_or_throw();
74+
75+
// Get the output tensors
76+
const auto tokens = out.get_and_remove("tokens");
77+
const auto scores = out.get_and_remove("scores");
78+
79+
const auto scores_data = static_cast<const float *>(scores.data());
80+
81+
std::cout << "Got output token: " << tokens.get_string(0) << std::endl;
82+
std::cout << "Got output scores: " << scores_data[0] << std::endl;
83+
}
84+
```
85+
86+
See the ["Loading a model"](/docs/loading) docs for complete examples of how to load a model and run inference.
87+
88+
At the moment, packing models and fetching metadata are not supported from C or C++.
89+
90+
</LanguageItem>
91+
<LanguageItem>
92+
1193
```bash linePrompt='$' forLang='python'
1294
pip install cartonml-nightly
1395
```
@@ -296,6 +378,8 @@ async fn main() {
296378

297379
Carton routes all of its log messages to the console. If you want to see trace logging, you may need to enable the verbose log level in your browser's console.
298380

381+
</LanguageItem>
382+
</LanguageSwitch>
299383
</LanguageItem>
300384
</LanguageSwitch>
301385

0 commit comments

Comments
 (0)