MCPcopy Create free account
hub / github.com/pydata/numexpr / prepareThreads

Function prepareThreads

numexpr3/interpreter.cpp:144–229  ·  view source on GitHub ↗

This function prepares the pointers towards the temporary memory block, and the NumExprObjects used by threads. Replacement for get_temps_space() and NumExprObject_copy_threadsafe().

Source from the content-addressed store, hash-verified

142// the NumExprObjects used by threads.
143// Replacement for get_temps_space() and NumExprObject_copy_threadsafe().
144int
145prepareThreads( NumExprObject* self, NpyIter *iter, int *pc_error, char **errorMessage ) {
146 // Variables
147 int I = 0, R = 0;
148 npy_intp memOffset = 0, taskFactor, numBlocks;
149
150 // Setup error tracking
151 gs.ret_code = 0;
152 gs.pc_error = pc_error;
153 gs.errorMessage = errorMessage;
154
155 // printf( "prepareThreads #1\n");
156 // Stuff from vm_engine_iter_parallel:
157 NpyIter_GetIterIndexRange(iter, &gs.start, &gs.vlen);
158
159 // Try to make it so each thread gets 16 tasks. This is a compromise
160 // between 1 task per thread and one block per task.
161 // RAM: would be nice to benchmark this sort of assumption.
162 taskFactor = TASKS_PER_THREAD*BLOCK_SIZE1*gs.n_thread;
163 numBlocks = (gs.vlen - gs.start + taskFactor - 1) /
164 taskFactor;
165 gs.task_size = numBlocks * BLOCK_SIZE1; // Note this is much bigger than BLOCK_SIZE1
166
167
168 // Ensure the temporary memory storage is big enough
169 // printf("Original: gs.tempSize = %d, gs.tempArena = %p\n", gs.tempSize, gs.tempArena );
170 if( BLOCK_SIZE1 * gs.n_thread * self->total_temp_itemsize > gs.tempSize ) {
171 // printf( "temp size too small, resizing #1\n");
172 numexpr_set_tempsize( BLOCK_SIZE1 * gs.n_thread * self->total_temp_itemsize );
173 // printf("Engorged: gs.tempSize = %d, gs.tempArena = %p\n", gs.tempSize, gs.tempArena );
174 }
175
176 // `Do` part of the `for` loop before, use `self` for the first thread.
177 gs.iter[0] = iter;
178 gs.params[0] = *self;
179 gs.params[0].registers = (NumExprReg *)gs.registerArena;
180 memcpy( gs.params[0].registers, self->registers, self->n_reg*sizeof(NumExprReg) );
181
182 // Setup temporaries memory pointers for the first NumExprObject
183 // printf( "self->n_reg = %d, gs.tempArena = %p\n", self->n_reg, gs.tempArena );
184 for( R=0; R < self->n_reg; R++ ) {
185 if( self->registers[R].kind != KIND_TEMP ) continue;
186
187 // printf( "reg#%d has kind %d and itemsize %d\n", R, self->registers[R].kind, (int)self->registers[R].itemsize );
188 gs.params[0].registers[R].mem = gs.tempArena + memOffset;
189 // printf( " thread #0, reg #%d, points to %p\n", R, gs.params[0].registers[R].mem );
190 memOffset += BLOCK_SIZE1 * self->registers[R].itemsize;
191 }
192
193 // Make copies of iterators and NumExprObjects for each additional thread
194 for( I = 1; I < gs.n_thread; ++I ) {
195 // TODO: add reduce_iter when you parallelize reductions
196 gs.iter[I] = NpyIter_Copy(iter);
197 if (gs.iter[I] == NULL) {
198 // Error: deallocate all iterators and return an error code.
199 --I;
200 // Only the original iterator should ever be called, and not copies.
201 NpyIter_Deallocate(gs.iter[0]);

Callers 1

run_interpreterFunction · 0.85

Calls 1

numexpr_set_tempsizeFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…