@@ -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
+ // Create an Interpreter which is managed by `manager` and using the enviroment `env`
87
93
Interpreter (InterpreterManager* manager, std::shared_ptr<Environment> env);
94
+
95
+ // Create an Interpreter manager using enviroment `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
+ // Get 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
+ // create 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
+ // change 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
+ // allocate an subinterpreter, and return its ID which is used to free it.
126
143
int acquire ();
144
+
145
+ // free 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,18 @@ 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 `Enviroment`.
138
162
explicit InterpreterManager (
139
163
size_t nInterp = 2 ,
140
164
std::shared_ptr<Environment> env = std::make_shared<NoopEnvironment>());
141
165
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.
166
+ // get a free InterpreterSession , guarenteed that no other user of acquireOne has the same
167
+ // InterpreterSession . It _is_ possible that other users will be using the interpreter.
144
168
InterpreterSession acquireOne () {
145
169
int where = resources_.acquire ();
146
170
InterpreterSession I = instances_[where].acquireSession ();
@@ -154,11 +178,18 @@ struct TORCH_API InterpreterManager {
154
178
at::ArrayRef<Interpreter> allInstances () {
155
179
return instances_;
156
180
}
181
+
182
+ // debugging tool to control the size of the loadBalancer
183
+ // and change the number of interpreters on the fly
157
184
void debugLimitInterpreters (size_t N) {
158
185
AT_ASSERT (N <= instances_.size ());
159
186
resources_.setResourceLimit (N);
160
187
}
188
+
189
+ // loads a package from a file with name `uri`
161
190
Package loadPackage (const std::string& uri);
191
+
192
+ // loads a package from a `PyTorchStreamReader` or any class other which uses `ReadAdapterInterface`
162
193
Package loadPackage (
163
194
std::shared_ptr<caffe2::serialize::ReadAdapterInterface> reader);
164
195
@@ -171,10 +202,12 @@ struct TORCH_API InterpreterManager {
171
202
registeredModuleSource_[std::move (name)] = std::move (src);
172
203
}
173
204
174
- // Util function for debugging.
205
+ // Util function for debugging which outputs the number of registered modules .
175
206
size_t countRegisteredModuleSources () {
176
207
return registeredModuleSource_.size ();
177
208
}
209
+
210
+ // Converts `obj` from on `InterpreterSession` I into a `ReplicatedObj`.
178
211
ReplicatedObj createMovable (Obj obj, InterpreterSession* I);
179
212
InterpreterManager (const InterpreterManager&) = delete ;
180
213
InterpreterManager& operator =(const InterpreterManager&) = delete ;
@@ -189,6 +222,7 @@ struct TORCH_API InterpreterManager {
189
222
std::unordered_map<std::string, std::string> registeredModuleSource_;
190
223
};
191
224
225
+ // Underlying implementation for ReplicatedObj.
192
226
struct TORCH_API ReplicatedObjImpl {
193
227
ReplicatedObjImpl (
194
228
size_t object_id,
@@ -204,32 +238,44 @@ struct TORCH_API ReplicatedObjImpl {
204
238
InterpreterManager* manager_;
205
239
};
206
240
241
+ // A python object which is Replicated from an `Obj` such that it is able to move around to different `InterpreterSessions`
242
+ // by using `InterpreterSession::fromMovable(ReplicatedObj)`
207
243
struct TORCH_API ReplicatedObj {
244
+
245
+ // default constructor for `ReplicatedObj`
208
246
ReplicatedObj () : pImpl_(nullptr ) {}
247
+
248
+ // Create an `InterpreterSession` using `onThisInterpreter`. If `onThisInterpreter` is
249
+ // a `nullptr', then the associated `InterpreterManager` allocates it.
209
250
InterpreterSession acquireSession (
210
251
const Interpreter* onThisInterpreter = nullptr ) const ;
211
252
at::IValue operator ()(at::ArrayRef<at::IValue> args) const {
212
253
auto I = acquireSession ();
213
254
return I.self (args).toIValue ();
214
255
}
215
256
257
+ // invokes `callKwargs` using the underlying python object, and returns the output as an `IValue`.
216
258
[[nodiscard]] at::IValue callKwargs (
217
259
std::vector<at::IValue> args,
218
260
std::unordered_map<std::string, c10::IValue> kwargs) const {
219
261
auto I = acquireSession ();
220
262
return I.self .callKwargs (std::move (args), std::move (kwargs)).toIValue ();
221
263
}
222
264
265
+ // invokes `callKwargs` using the underlying python object, and returns the output as an `IValue`.
223
266
[[nodiscard]] at::IValue callKwargs (
224
267
std::unordered_map<std::string, c10::IValue> kwargs) const {
225
268
auto I = acquireSession ();
226
269
return I.self .callKwargs (std::move (kwargs)).toIValue ();
227
270
}
228
271
272
+ // invokes `hasattr` using the underlying python object, and returns the output as an `IValue`.
229
273
[[nodiscard]] bool hasattr (const char * name) const {
230
274
auto I = acquireSession ();
231
275
return I.self .hasattr (name);
232
276
}
277
+
278
+
233
279
void unload (const Interpreter* onThisInterpreter = nullptr );
234
280
Obj toObj (InterpreterSession* I);
235
281
@@ -242,21 +288,24 @@ struct TORCH_API ReplicatedObj {
242
288
friend struct InterpreterManager ;
243
289
};
244
290
291
+ // PythonMethodWrapper is a more specific instance of a
292
+ // ReplicatedObj which represents a python method, and
293
+ // is therefore callable and has argument names accessible.
245
294
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
295
public:
250
296
// TODO(whc) make bound method pickleable, then directly construct from that
297
+
251
298
PythonMethodWrapper (
252
299
torch::deploy::ReplicatedObj model,
253
300
std::string methodName)
254
301
: model_(std::move(model)), methodName_(std::move(methodName)) {}
255
302
303
+ // return the name of the python method.
256
304
const std::string& name () const override {
257
305
return methodName_;
258
306
}
259
307
308
+ // overrides the `()` operater to call the underlying python method.
260
309
c10::IValue operator ()(
261
310
std::vector<c10::IValue> args,
262
311
const IValueMap& kwargs = IValueMap()) const override {
@@ -274,6 +323,7 @@ class PythonMethodWrapper : public torch::IMethod {
274
323
std::string methodName_;
275
324
};
276
325
326
+ // An object to encapsulate a `torch::package` which can act as part (or entire) enviroment for subinterpreters.
277
327
struct TORCH_API Package {
278
328
// shorthand for getting the object as a pickle resource in the package
279
329
ReplicatedObj loadPickle (const std::string& module, const std::string& file) {
@@ -308,12 +358,15 @@ struct TORCH_API Package {
308
358
}
309
359
#endif
310
360
361
+ // allocate an `InterpreterSession` and load the appropriate torch.package with it.
311
362
InterpreterSession acquireSession () {
312
363
auto I = manager_->acquireOne ();
313
364
I.self =
314
365
I.impl_ ->createOrGetPackageImporterFromContainerFile (containerFile_);
315
366
return I;
316
367
}
368
+
369
+ // Converts an `Obj` from `InterpreterSession` `I` into a `ReplicatedObj`.
317
370
ReplicatedObj createMovable (Obj obj, InterpreterSession* I) {
318
371
return manager_->createMovable (obj, I);
319
372
}
0 commit comments