@@ -57,6 +57,8 @@ struct TORCH_API InterpreterSession {
57
57
// InterpreterSession* I)' instead. We will have no backwards compatibility
58
58
// guarentees for this function.
59
59
ReplicatedObj createMovable (Obj obj);
60
+
61
+ // Converts a `ReplicatedObj` to an `Obj` on this InterpreterSession.
60
62
Obj fromMovable (const ReplicatedObj& obj);
61
63
62
64
protected:
@@ -73,6 +75,9 @@ struct TORCH_API InterpreterSession {
73
75
std::function<void ()> deconstruction_callback_ = nullptr ;
74
76
};
75
77
78
+ // An `Interpreter` represents an invidual subinterpreter created by `torch::deploy`.
79
+ // It allows for the creation of `InterpreterSession` objects which allow users to interact with
80
+ // python objects.
76
81
class TORCH_API Interpreter {
77
82
private:
78
83
void * handle_;
@@ -84,17 +89,22 @@ class TORCH_API Interpreter {
84
89
multipy::optional<EmbeddedFile> torchPluginFile_;
85
90
86
91
public:
92
+ // Creates an Interpreter which is managed by `manager` and using the environment `env`
87
93
Interpreter (InterpreterManager* manager, std::shared_ptr<Environment> env);
94
+
95
+ // Creates an Interpreter manager using environment `env` which is not tied to an Interpreter Manager.
88
96
explicit Interpreter (std::shared_ptr<Environment> env)
89
97
: Interpreter(nullptr , env) {}
90
98
99
+ // Gets a new `InterpreterSession` from this Interpreter.
91
100
InterpreterSession acquireSession () const {
92
101
if (manager_) {
93
102
return InterpreterSession (pImpl_->acquireSession (), manager_);
94
103
} else {
95
104
return InterpreterSession (pImpl_->acquireSession ());
96
105
}
97
106
}
107
+
98
108
~Interpreter ();
99
109
Interpreter (Interpreter&& rhs) noexcept
100
110
: handle_(rhs.handle_),
@@ -113,17 +123,26 @@ class TORCH_API Interpreter {
113
123
114
124
struct Package ;
115
125
126
+ // The default LoadBalancer for torch::deploy which handles allocating and freeing subinterpreters.
116
127
struct TORCH_API LoadBalancer {
128
+
129
+ // Creates a Loadbalancer which handles `n` interpreters.
117
130
explicit LoadBalancer (size_t n)
118
131
: uses_(new uint64_t [8 * n]), allocated_(n), n_(n) {
119
132
// 8*... to avoid false sharing of atomics on the same cache line
120
133
memset (uses_.get (), 0 , 8 * n_ * sizeof (uint64_t ));
121
134
}
135
+
136
+ // Changes the amount of subinterpreters which is handled by the load balancer.
122
137
void setResourceLimit (size_t n) {
123
138
MULTIPY_INTERNAL_ASSERT (n <= allocated_);
124
139
n_ = n;
125
140
}
141
+
142
+ // Allocates an subinterpreter, and return its ID which is used to free it.
126
143
int acquire ();
144
+
145
+ // Frees the subinterpreter with ID `where`. This ID is returned by `LoadBalancer::acquire()`
127
146
void free (int where);
128
147
129
148
private:
@@ -134,13 +153,21 @@ struct TORCH_API LoadBalancer {
134
153
size_t n_;
135
154
};
136
155
156
+ // An `InterpreterManager` handles the interaction of multiple subinterpreters such as allocating
157
+ // subinterpreters, or load balancing the subinterpreters.
137
158
struct TORCH_API InterpreterManager {
159
+
160
+ // constructor for `InterpreterManager` which takes the number of interpreters
161
+ // (usually correlates to number of cores on your cpu), and a pointer to an `Environment`.
162
+ // The defualt uses the local python env.
138
163
explicit InterpreterManager (
139
164
size_t nInterp = 2 ,
140
165
std::shared_ptr<Environment> env = std::make_shared<NoopEnvironment>());
141
166
142
- // get a free model, guarenteed that no other user of acquireOne has the same
143
- // model. It _is_ possible that other users will be using the interpreter.
167
+ // get a free InterpreterSession, guarenteed that no other user of acquireOne has the same
168
+ // InterpreterSession. It _is_ possible that other users will be using the interpreter if there are
169
+ // no free InterpreterSessions. Unless you are very careful to only use free interpreters, then do not assume
170
+ // that the `Obj`s are isolated from each other.
144
171
InterpreterSession acquireOne () {
145
172
int where = resources_.acquire ();
146
173
InterpreterSession I = instances_[where].acquireSession ();
@@ -154,11 +181,18 @@ struct TORCH_API InterpreterManager {
154
181
at::ArrayRef<Interpreter> allInstances () {
155
182
return instances_;
156
183
}
184
+
185
+ // debugging tool to control the size of the loadBalancer
186
+ // and change the number of interpreters on the fly
157
187
void debugLimitInterpreters (size_t N) {
158
188
AT_ASSERT (N <= instances_.size ());
159
189
resources_.setResourceLimit (N);
160
190
}
191
+
192
+ // loads a package from a file with name `uri`
161
193
Package loadPackage (const std::string& uri);
194
+
195
+ // loads a package from a `PyTorchStreamReader` or any class other which uses `ReadAdapterInterface`
162
196
Package loadPackage (
163
197
std::shared_ptr<caffe2::serialize::ReadAdapterInterface> reader);
164
198
@@ -171,10 +205,12 @@ struct TORCH_API InterpreterManager {
171
205
registeredModuleSource_[std::move (name)] = std::move (src);
172
206
}
173
207
174
- // Util function for debugging.
208
+ // Util function for debugging which outputs the number of registered modules .
175
209
size_t countRegisteredModuleSources () {
176
210
return registeredModuleSource_.size ();
177
211
}
212
+
213
+ // Converts `obj` from on `InterpreterSession` I into a `ReplicatedObj`.
178
214
ReplicatedObj createMovable (Obj obj, InterpreterSession* I);
179
215
InterpreterManager (const InterpreterManager&) = delete ;
180
216
InterpreterManager& operator =(const InterpreterManager&) = delete ;
@@ -204,33 +240,51 @@ struct TORCH_API ReplicatedObjImpl {
204
240
InterpreterManager* manager_;
205
241
};
206
242
243
+ // A python object which is Replicated from an `Obj` such that it is able to move around to different `InterpreterSessions`
244
+ // by using `InterpreterSession::fromMovable(ReplicatedObj)`
207
245
struct TORCH_API ReplicatedObj {
246
+
247
+ // Default constructor for `ReplicatedObj`
208
248
ReplicatedObj () : pImpl_(nullptr ) {}
249
+
250
+ // Creates an `InterpreterSession` using `onThisInterpreter`. If `onThisInterpreter` is
251
+ // a `nullptr', then the associated `InterpreterManager` allocates it.
209
252
InterpreterSession acquireSession (
210
253
const Interpreter* onThisInterpreter = nullptr ) const ;
211
254
at::IValue operator ()(at::ArrayRef<at::IValue> args) const {
212
255
auto I = acquireSession ();
213
256
return I.self (args).toIValue ();
214
257
}
215
258
259
+ // Calls an `ReplicatedObj` callable, with arguments given by the tuple args and named arguments given by the dictionary
260
+ // kwargs. This is done on an arbitrary `InterpreterSession` which belongs to the `ReplicatedObj`'s manager.
216
261
[[nodiscard]] at::IValue callKwargs (
217
262
std::vector<at::IValue> args,
218
263
std::unordered_map<std::string, c10::IValue> kwargs) const {
219
264
auto I = acquireSession ();
220
265
return I.self .callKwargs (std::move (args), std::move (kwargs)).toIValue ();
221
266
}
222
267
268
+ // Calls an `ReplicatedObj` callable, with named arguments given by the dictionary kwargs.
269
+ // This is done on an arbitrary `InterpreterSession` which belongs to the `ReplicatedObj`'s manager.
223
270
[[nodiscard]] at::IValue callKwargs (
224
271
std::unordered_map<std::string, c10::IValue> kwargs) const {
225
272
auto I = acquireSession ();
226
273
return I.self .callKwargs (std::move (kwargs)).toIValue ();
227
274
}
228
275
229
- [[nodiscard]] bool hasattr (const char * name) const {
276
+ // Returns true if `ReplicatedObj` has attribute with name `attr` and false otherwise.
277
+ // This is done on an arbitrary `InterpreterSession` which belongs to the `ReplicatedObj`'s manager.
278
+ [[nodiscard]] bool hasattr (const char * attr) const {
230
279
auto I = acquireSession ();
231
- return I.self .hasattr (name );
280
+ return I.self .hasattr (attr );
232
281
}
282
+
283
+ // Deletes `ReplicatedObj` from onThisInterpreter, if onThisInterpreter is `nullptr`,
284
+ // unload is called on all interpreters belonging to the ReplicatedObject's InterpreterManager
233
285
void unload (const Interpreter* onThisInterpreter = nullptr );
286
+
287
+ // Converts `ReplicatedObj` to `Obj` on `InterpreterSession` `I`
234
288
Obj toObj (InterpreterSession* I);
235
289
236
290
private:
@@ -242,21 +296,24 @@ struct TORCH_API ReplicatedObj {
242
296
friend struct InterpreterManager ;
243
297
};
244
298
299
+ // PythonMethodWrapper is a more specific instance of a
300
+ // ReplicatedObj which represents a python method, and
301
+ // is therefore callable and has argument names accessible.
245
302
class PythonMethodWrapper : public torch ::IMethod {
246
- // PythonMethodWrapper is a more specific instance of a
247
- // ReplicatedObj which represents a python method, and
248
- // is therefore callable and has argument names accessible.
249
303
public:
250
304
// TODO(whc) make bound method pickleable, then directly construct from that
305
+
251
306
PythonMethodWrapper (
252
307
torch::deploy::ReplicatedObj model,
253
308
std::string methodName)
254
309
: model_(std::move(model)), methodName_(std::move(methodName)) {}
255
310
311
+ // return the name of the python method.
256
312
const std::string& name () const override {
257
313
return methodName_;
258
314
}
259
315
316
+ // overrides the `()` operater to call the underlying python method.
260
317
c10::IValue operator ()(
261
318
std::vector<c10::IValue> args,
262
319
const IValueMap& kwargs = IValueMap()) const override {
@@ -274,6 +331,7 @@ class PythonMethodWrapper : public torch::IMethod {
274
331
std::string methodName_;
275
332
};
276
333
334
+ // An object to encapsulate a `torch::package` which can act as part (or entire) environment for subinterpreters.
277
335
struct TORCH_API Package {
278
336
// shorthand for getting the object as a pickle resource in the package
279
337
ReplicatedObj loadPickle (const std::string& module, const std::string& file) {
@@ -308,12 +366,15 @@ struct TORCH_API Package {
308
366
}
309
367
#endif
310
368
369
+ // Allocates an `InterpreterSession` and load the appropriate torch.package with it.
311
370
InterpreterSession acquireSession () {
312
371
auto I = manager_->acquireOne ();
313
372
I.self =
314
373
I.impl_ ->createOrGetPackageImporterFromContainerFile (containerFile_);
315
374
return I;
316
375
}
376
+
377
+ // Converts an `Obj` from `InterpreterSession` `I` into a `ReplicatedObj`.
317
378
ReplicatedObj createMovable (Obj obj, InterpreterSession* I) {
318
379
return manager_->createMovable (obj, I);
319
380
}
0 commit comments