xref: /aosp_15_r20/external/pytorch/aten/src/README.md (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard WorkerThis directory contains the low-level tensor libraries for PyTorch,
2*da0073e9SAndroid Build Coastguard Workeras well as the new ATen C++ bindings.
3*da0073e9SAndroid Build Coastguard Worker
4*da0073e9SAndroid Build Coastguard WorkerThe low-level libraries trace their lineage from the original Torch.  There are
5*da0073e9SAndroid Build Coastguard Workermultiple variants of the library, summarized here:
6*da0073e9SAndroid Build Coastguard Worker
7*da0073e9SAndroid Build Coastguard Worker* TH = TorcH
8*da0073e9SAndroid Build Coastguard Worker* THC = TorcH Cuda
9*da0073e9SAndroid Build Coastguard Worker* THCS = TorcH Cuda Sparse (now defunct)
10*da0073e9SAndroid Build Coastguard Worker* THNN = TorcH Neural Network (now defunct)
11*da0073e9SAndroid Build Coastguard Worker* THS = TorcH Sparse (now defunct)
12*da0073e9SAndroid Build Coastguard Worker
13*da0073e9SAndroid Build Coastguard Worker(You'll also see these abbreviations show up in symbol names.)
14*da0073e9SAndroid Build Coastguard Worker
15*da0073e9SAndroid Build Coastguard Worker## Reference counting
16*da0073e9SAndroid Build Coastguard Worker
17*da0073e9SAndroid Build Coastguard WorkerPyTorch employs reference counting in order to permit tensors to provide
18*da0073e9SAndroid Build Coastguard Workerdiffering views on a common underlying storage.  For example, when you call
19*da0073e9SAndroid Build Coastguard Workerview() on a Tensor, a new THTensor is allocated with differing dimensions,
20*da0073e9SAndroid Build Coastguard Workerbut it shares the same c10::StorageImpl with the original tensor.
21*da0073e9SAndroid Build Coastguard Worker
22*da0073e9SAndroid Build Coastguard WorkerUnfortunately, this means we are in the business of manually tracking reference
23*da0073e9SAndroid Build Coastguard Workercounts inside our C library code.  Fortunately, for most of our library code implementing
24*da0073e9SAndroid Build Coastguard Workertensor operations, there is only one rule you have to remember:
25*da0073e9SAndroid Build Coastguard Worker
26*da0073e9SAndroid Build Coastguard Worker> **Golden Rule of Reference Counting:** You must either FREE or RETURN
27*da0073e9SAndroid Build Coastguard Worker> a pointer which was returned by a function whose name begins with
28*da0073e9SAndroid Build Coastguard Worker> `new` or which you called `retain` on.
29*da0073e9SAndroid Build Coastguard Worker> If you return this pointer, your function name must begin with `new`.
30*da0073e9SAndroid Build Coastguard Worker
31*da0073e9SAndroid Build Coastguard WorkerIn a long function, there may be many invocations of functions with `new` in
32*da0073e9SAndroid Build Coastguard Workertheir name.  Your responsibility is to go through each of them and ensure
33*da0073e9SAndroid Build Coastguard Workerthat there is a matching `free` for it for EACH exit point of the function.
34*da0073e9SAndroid Build Coastguard Worker
35*da0073e9SAndroid Build Coastguard Worker### Examples
36*da0073e9SAndroid Build Coastguard Worker
37*da0073e9SAndroid Build Coastguard WorkerSuppose you want to get a reference to the indices of a sparse tensor.  This
38*da0073e9SAndroid Build Coastguard Workerfunction is called `newIndices`.  The `new` means you MUST free it when you're
39*da0073e9SAndroid Build Coastguard Workerdone (usually at the end of your function.)  (It's worth noting that
40*da0073e9SAndroid Build Coastguard Worker`newIndices` doesn't actually allocate a fresh indices tensor; it just gives
41*da0073e9SAndroid Build Coastguard Workeryou a pointer to the existing one.)  DO NOT directly access the member
42*da0073e9SAndroid Build Coastguard Workervariables of the struct.
43*da0073e9SAndroid Build Coastguard Worker
44*da0073e9SAndroid Build Coastguard Worker```
45*da0073e9SAndroid Build Coastguard WorkerTHIndexTensor *indices = THSTensor_(newIndices)(state, sparse);
46*da0073e9SAndroid Build Coastguard Worker// ... do some stuff ...
47*da0073e9SAndroid Build Coastguard WorkerTHIndexTensor_(free)(state, indices);
48*da0073e9SAndroid Build Coastguard Worker```
49*da0073e9SAndroid Build Coastguard Worker
50*da0073e9SAndroid Build Coastguard WorkerLet's take a look at the implementation of `newIndices`.  This doesn't free the
51*da0073e9SAndroid Build Coastguard Workerreturn result of `newNarrow`, but returns it.  This justifies the `new` in its
52*da0073e9SAndroid Build Coastguard Workername.
53*da0073e9SAndroid Build Coastguard Worker
54*da0073e9SAndroid Build Coastguard Worker```
55*da0073e9SAndroid Build Coastguard WorkerTHIndexTensor *THSTensor_(newIndices)(const THSTensor *self) {
56*da0073e9SAndroid Build Coastguard Worker  // ...
57*da0073e9SAndroid Build Coastguard Worker  return THIndexTensor_(newNarrow)(self->indices, 1, 0, self->nnz);
58*da0073e9SAndroid Build Coastguard Worker}
59*da0073e9SAndroid Build Coastguard Worker```
60*da0073e9SAndroid Build Coastguard Worker
61*da0073e9SAndroid Build Coastguard WorkerPassing an object to another function does NOT absolve you of responsibility
62*da0073e9SAndroid Build Coastguard Workerof freeing it.  If that function holds on to a pointer to the object, it
63*da0073e9SAndroid Build Coastguard Workerwill `retain` it itself.
64*da0073e9SAndroid Build Coastguard Worker
65*da0073e9SAndroid Build Coastguard Worker```
66*da0073e9SAndroid Build Coastguard Worker  THByteStorage *inferred_size = THByteStorage_newInferSize(size, numel);
67*da0073e9SAndroid Build Coastguard Worker  THTensor_(setStorage)(self, tensor->storage, tensor->storageOffset, inferred_size, NULL);
68*da0073e9SAndroid Build Coastguard Worker  c10::raw::intrusive_ptr::decref(inferred_size);
69*da0073e9SAndroid Build Coastguard Worker```
70*da0073e9SAndroid Build Coastguard Worker
71*da0073e9SAndroid Build Coastguard WorkerSometimes, you have a tensor in hand which you'd like to use directly, but
72*da0073e9SAndroid Build Coastguard Workerunder some conditions you have to call, e.g., `newContiguous`, to get it into
73*da0073e9SAndroid Build Coastguard Workerthe correct form:
74*da0073e9SAndroid Build Coastguard Worker
75*da0073e9SAndroid Build Coastguard Worker```
76*da0073e9SAndroid Build Coastguard Worker  if (!(k_->stride(3) == 1) || !(k_->stride[2] == k_->size(3))) {
77*da0073e9SAndroid Build Coastguard Worker    kernel = THTensor_(newContiguous)(k_);
78*da0073e9SAndroid Build Coastguard Worker  } else {
79*da0073e9SAndroid Build Coastguard Worker    THTensor_(retain)(k_);
80*da0073e9SAndroid Build Coastguard Worker    kernel = k_;
81*da0073e9SAndroid Build Coastguard Worker  }
82*da0073e9SAndroid Build Coastguard Worker  ...
83*da0073e9SAndroid Build Coastguard Worker  c10::raw::intrusive_ptr::decref(kernel);
84*da0073e9SAndroid Build Coastguard Worker```
85*da0073e9SAndroid Build Coastguard Worker
86*da0073e9SAndroid Build Coastguard WorkerIn this case, we have (redundantly) called `retain` on `k_`, so that we can
87*da0073e9SAndroid Build Coastguard Workerunconditionally free `kernel` at the end of the function; intuitively, you
88*da0073e9SAndroid Build Coastguard Workerwant it to be possible to replace the conditional expression with an equivalent
89*da0073e9SAndroid Build Coastguard Workerfunction call, e.g., `kernel = THTensor_(newContiguous2D)(k_)`.
90*da0073e9SAndroid Build Coastguard Worker
91*da0073e9SAndroid Build Coastguard Worker### Tips
92*da0073e9SAndroid Build Coastguard Worker
93*da0073e9SAndroid Build Coastguard Worker* If you have an early exit in a function (via a `return`), don't forget to
94*da0073e9SAndroid Build Coastguard Worker  `free` any pointers which you allocated up to this point.  If at all possible,
95*da0073e9SAndroid Build Coastguard Worker  move early exits prior to these allocations, so that you don't have to clean up.
96*da0073e9SAndroid Build Coastguard Worker
97*da0073e9SAndroid Build Coastguard Worker* Very occasionally, you may be able to implement an algorithm more efficiently
98*da0073e9SAndroid Build Coastguard Worker  if you "destroy" its input.  This is a `move`; after moving an object away,
99*da0073e9SAndroid Build Coastguard Worker  you must NOT `free` it.  This is the one exception to the rule, and at the
100*da0073e9SAndroid Build Coastguard Worker  moment there is only one instance of `move` in the code base.
101*da0073e9SAndroid Build Coastguard Worker
102*da0073e9SAndroid Build Coastguard Worker* We use `THError` to signal error cases, and fortunately,
103*da0073e9SAndroid Build Coastguard Worker  you do NOT need to make sure you've freed everything before calling `THError`,
104*da0073e9SAndroid Build Coastguard Worker  because by default, it aborts the entire process.  However, it's good style
105*da0073e9SAndroid Build Coastguard Worker  to call `THError` before performing any allocations, since in some cases we
106*da0073e9SAndroid Build Coastguard Worker  sketchily throw a C++ exception and try to recover (in particular, the test
107*da0073e9SAndroid Build Coastguard Worker  suite does this.)
108