Skip to content

Commit 147ca89

Browse files
authored
Merge pull request #620 from RedisAI/Create_tensor_through_gears-refactor_and_test
Test create tensor through gears
2 parents b3d44c3 + 5bef776 commit 147ca89

File tree

4 files changed

+60
-53
lines changed

4 files changed

+60
-53
lines changed

src/tensor.c

Lines changed: 18 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,11 @@ RAI_Tensor *RAI_TensorNew(void) {
9999
RAI_Tensor *ret = RedisModule_Calloc(1, sizeof(*ret));
100100
ret->refCount = 1;
101101
ret->len = LEN_UNKOWN;
102+
return ret;
102103
}
103104

104105
RAI_Tensor *RAI_TensorCreateWithDLDataType(DLDataType dtype, long long *dims, int ndims,
105-
int tensorAllocMode) {
106+
bool empty) {
106107

107108
size_t dtypeSize = Tensor_DataTypeSize(dtype);
108109
if (dtypeSize == 0) {
@@ -124,20 +125,14 @@ RAI_Tensor *RAI_TensorCreateWithDLDataType(DLDataType dtype, long long *dims, in
124125
}
125126

126127
DLDevice device = (DLDevice){.device_type = kDLCPU, .device_id = 0};
127-
void *data = NULL;
128-
switch (tensorAllocMode) {
129-
case TENSORALLOC_ALLOC:
130-
data = RedisModule_Alloc(len * dtypeSize);
131-
break;
132-
case TENSORALLOC_CALLOC:
128+
129+
// If we return an empty tensor, we initialize the data with zeros to avoid security
130+
// issues. Otherwise, we only allocate without initializing (for better performance)
131+
void *data;
132+
if (empty) {
133133
data = RedisModule_Calloc(len, dtypeSize);
134-
break;
135-
case TENSORALLOC_NONE:
136-
/* shallow copy no alloc */
137-
default:
138-
/* assume TENSORALLOC_NONE
139-
shallow copy no alloc */
140-
break;
134+
} else {
135+
data = RedisModule_Alloc(len * dtypeSize);
141136
}
142137

143138
ret->tensor = (DLManagedTensor){.dl_tensor = (DLTensor){.device = device,
@@ -214,27 +209,11 @@ RAI_Tensor *_TensorCreateWithDLDataTypeAndRString(DLDataType dtype, size_t dtype
214209
return ret;
215210
}
216211

217-
RAI_Tensor *RAI_TensorCreate(const char *dataType, long long *dims, int ndims, int hasdata) {
212+
// Important note: the tensor data must be initialized after the creation.
213+
RAI_Tensor *RAI_TensorCreate(const char *dataType, long long *dims, int ndims) {
218214
DLDataType dtype = RAI_TensorDataTypeFromString(dataType);
219-
return RAI_TensorCreateWithDLDataType(dtype, dims, ndims, TENSORALLOC_ALLOC);
220-
}
221-
222-
#if 0
223-
void RAI_TensorMoveFrom(RAI_Tensor* dst, RAI_Tensor* src) {
224-
if (--dst->refCount <= 0){
225-
RedisModule_Free(t->tensor.shape);
226-
if (t->tensor.strides) {
227-
RedisModule_Free(t->tensor.strides);
228-
}
229-
RedisModule_Free(t->tensor.data);
230-
RedisModule_Free(t);
231-
}
232-
dst->tensor.ctx = src->tensor.ctx;
233-
dst->tensor.data = src->tensor.data;
234-
235-
dst->refCount = 1;
215+
return RAI_TensorCreateWithDLDataType(dtype, dims, ndims, false);
236216
}
237-
#endif
238217

239218
RAI_Tensor *RAI_TensorCreateByConcatenatingTensors(RAI_Tensor **ts, long long n) {
240219

@@ -273,7 +252,7 @@ RAI_Tensor *RAI_TensorCreateByConcatenatingTensors(RAI_Tensor **ts, long long n)
273252

274253
DLDataType dtype = RAI_TensorDataType(ts[0]);
275254

276-
RAI_Tensor *ret = RAI_TensorCreateWithDLDataType(dtype, dims, ndims, TENSORALLOC_ALLOC);
255+
RAI_Tensor *ret = RAI_TensorCreateWithDLDataType(dtype, dims, ndims, false);
277256

278257
for (long long i = 0; i < n; i++) {
279258
memcpy(RAI_TensorData(ret) + batch_offsets[i] * sample_size * dtype_size,
@@ -300,7 +279,7 @@ RAI_Tensor *RAI_TensorCreateBySlicingTensor(RAI_Tensor *t, long long offset, lon
300279

301280
DLDataType dtype = RAI_TensorDataType(t);
302281

303-
RAI_Tensor *ret = RAI_TensorCreateWithDLDataType(dtype, dims, ndims, TENSORALLOC_ALLOC);
282+
RAI_Tensor *ret = RAI_TensorCreateWithDLDataType(dtype, dims, ndims, false);
304283

305284
memcpy(RAI_TensorData(ret), RAI_TensorData(t) + offset * sample_size * dtype_size,
306285
len * sample_size * dtype_size);
@@ -329,14 +308,14 @@ int RAI_TensorDeepCopy(RAI_Tensor *t, RAI_Tensor **dest) {
329308

330309
DLDataType dtype = RAI_TensorDataType(t);
331310

332-
RAI_Tensor *ret = RAI_TensorCreateWithDLDataType(dtype, dims, ndims, TENSORALLOC_ALLOC);
311+
RAI_Tensor *ret = RAI_TensorCreateWithDLDataType(dtype, dims, ndims, false);
333312

334313
memcpy(RAI_TensorData(ret), RAI_TensorData(t), sample_size * dtype_size);
335314
*dest = ret;
336315
return 0;
337316
}
338317

339-
// Beware: this will take ownership of dltensor
318+
// Beware: this will take ownership of dltensor.
340319
RAI_Tensor *RAI_TensorCreateFromDLTensor(DLManagedTensor *dl_tensor) {
341320

342321
RAI_Tensor *ret = RAI_TensorNew();
@@ -419,19 +398,15 @@ int RAI_TensorSetValueFromLongLong(RAI_Tensor *t, long long i, long long val) {
419398
case 8:
420399
((int8_t *)data)[i] = val;
421400
break;
422-
break;
423401
case 16:
424402
((int16_t *)data)[i] = val;
425403
break;
426-
break;
427404
case 32:
428405
((int32_t *)data)[i] = val;
429406
break;
430-
break;
431407
case 64:
432408
((int64_t *)data)[i] = val;
433409
break;
434-
break;
435410
default:
436411
return 0;
437412
}
@@ -440,19 +415,15 @@ int RAI_TensorSetValueFromLongLong(RAI_Tensor *t, long long i, long long val) {
440415
case 8:
441416
((uint8_t *)data)[i] = val;
442417
break;
443-
break;
444418
case 16:
445419
((uint16_t *)data)[i] = val;
446420
break;
447-
break;
448421
case 32:
449422
((uint32_t *)data)[i] = val;
450423
break;
451-
break;
452424
case 64:
453425
((uint64_t *)data)[i] = val;
454426
break;
455-
break;
456427
default:
457428
return 0;
458429
}
@@ -642,7 +613,6 @@ int RAI_parseTensorSetArgs(RedisModuleString **argv, int argc, RAI_Tensor **t, i
642613

643614
const char *fmtstr;
644615
int datafmt = TENSOR_NONE;
645-
int tensorAllocMode = TENSORALLOC_CALLOC;
646616
size_t ndims = 0;
647617
long long len = 1;
648618
long long *dims = (long long *)array_new(long long, 1);
@@ -656,7 +626,6 @@ int RAI_parseTensorSetArgs(RedisModuleString **argv, int argc, RAI_Tensor **t, i
656626
remaining_args = argc - 1 - argpos;
657627
if (!strcasecmp(opt, "BLOB")) {
658628
datafmt = TENSOR_BLOB;
659-
tensorAllocMode = TENSORALLOC_CALLOC;
660629
// if we've found the dataformat there are no more dimensions
661630
// check right away if the arity is correct
662631
if (remaining_args != 1 && enforceArity == 1) {
@@ -669,7 +638,6 @@ int RAI_parseTensorSetArgs(RedisModuleString **argv, int argc, RAI_Tensor **t, i
669638
break;
670639
} else if (!strcasecmp(opt, "VALUES")) {
671640
datafmt = TENSOR_VALUES;
672-
tensorAllocMode = TENSORALLOC_CALLOC;
673641
// if we've found the dataformat there are no more dimensions
674642
// check right away if the arity is correct
675643
if (remaining_args != len && enforceArity == 1) {
@@ -699,7 +667,8 @@ int RAI_parseTensorSetArgs(RedisModuleString **argv, int argc, RAI_Tensor **t, i
699667
RedisModuleString *rstr = argv[argpos];
700668
*t = _TensorCreateWithDLDataTypeAndRString(datatype, datasize, dims, ndims, rstr, error);
701669
} else {
702-
*t = RAI_TensorCreateWithDLDataType(datatype, dims, ndims, tensorAllocMode);
670+
bool is_empty = (datafmt == TENSOR_NONE);
671+
*t = RAI_TensorCreateWithDLDataType(datatype, dims, ndims, is_empty);
703672
}
704673
if (!(*t)) {
705674
array_free(dims);

src/tensor.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,10 @@ RAI_Tensor *RAI_TensorNew(void);
6565
* @param dataType string containing the numeric data type of tensor elements
6666
* @param dims n-dimensional array ( the dimension values are copied )
6767
* @param ndims number of dimensions
68-
* @param hasdata ( deprecated parameter )
6968
* @return allocated RAI_Tensor on success, or NULL if the allocation
7069
* failed.
7170
*/
72-
RAI_Tensor *RAI_TensorCreate(const char *dataType, long long *dims, int ndims, int hasdata);
71+
RAI_Tensor *RAI_TensorCreate(const char *dataType, long long *dims, int ndims);
7372

7473
/**
7574
* Allocate the memory and initialise the RAI_Tensor. Creates a tensor based on
@@ -81,12 +80,12 @@ RAI_Tensor *RAI_TensorCreate(const char *dataType, long long *dims, int ndims, i
8180
* @param dtype DLDataType
8281
* @param dims n-dimensional array ( the dimension values are copied )
8382
* @param ndims number of dimensions
84-
* @param tensorAllocMode
83+
* @param empty True if creating an empty tensor (need to be initialized)
8584
* @return allocated RAI_Tensor on success, or NULL if the allocation
8685
* failed.
8786
*/
8887
RAI_Tensor *RAI_TensorCreateWithDLDataType(DLDataType dtype, long long *dims, int ndims,
89-
int tensorAllocMode);
88+
bool empty);
9089

9190
/**
9291
* Allocate the memory for a new Tensor and copy data fom a tensor to it.

tests/flow/includes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ def send_and_disconnect(cmd, red):
5858
con = pool.get_connection(cmd[0])
5959
ret = con.send_command(*cmd)
6060
con.disconnect()
61+
# For making sure that Redis will have the time to exit cleanly.
62+
time.sleep(1)
6163
return ret
6264

6365

tests/flow/tests_withGears.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,40 @@ async def DAGRun_addOpsFromString(record):
311311
values = con.execute_command('AI.TENSORGET', 'test5_res{1}', 'VALUES')
312312
env.assertEqual(values, [b'4', b'9', b'4', b'9'])
313313

314+
315+
@skip_if_gears_not_loaded
316+
def test_tensor_create_via_gears(env):
317+
script = '''
318+
319+
import redisAI
320+
321+
def TensorCreate_FromValues(record):
322+
323+
tensor = redisAI.createTensorFromValues('DOUBLE', [2,2], [1.0, 2.0, 3.0, 4.0])
324+
redisAI.setTensorInKey('test1_res{1}', tensor)
325+
return "test1_OK"
326+
327+
def TensorCreate_FromBlob(record):
328+
tensor_blob = bytearray([5, 6, 7, 8])
329+
tensor = redisAI.createTensorFromBlob('INT8', [2,2], tensor_blob)
330+
redisAI.setTensorInKey('test2_res{1}', tensor)
331+
return "test2_OK"
332+
333+
GB("CommandReader").map(TensorCreate_FromValues).register(trigger="TensorCreate_FromValues_test1")
334+
GB("CommandReader").map(TensorCreate_FromBlob).register(trigger="TensorCreate_FromBlob_test2")
335+
'''
336+
337+
con = env.getConnection()
338+
ret = con.execute_command('rg.pyexecute', script)
339+
env.assertEqual(ret, b'OK')
340+
ret = con.execute_command('rg.trigger', 'TensorCreate_FromValues_test1')
341+
env.assertEqual(ret[0], b'test1_OK')
342+
343+
values = con.execute_command('AI.TENSORGET', 'test1_res{1}', 'VALUES')
344+
env.assertEqual(values, [b'1', b'2', b'3', b'4'])
345+
346+
ret = con.execute_command('rg.trigger', 'TensorCreate_FromBlob_test2')
347+
env.assertEqual(ret[0], b'test2_OK')
348+
349+
values = con.execute_command('AI.TENSORGET', 'test2_res{1}', 'VALUES')
350+
env.assertEqual(values, [5, 6, 7, 8])

0 commit comments

Comments
 (0)