Simulation Core
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1795 regels
85 KiB

  1. ! BSD 2-Clause License
  2. !
  3. ! Copyright (c) 2021-2022, Hewlett Packard Enterprise
  4. ! All rights reserved.
  5. !
  6. ! Redistribution and use in source and binary forms, with or without
  7. ! modification, are permitted provided that the following conditions are met:
  8. !
  9. ! 1. Redistributions of source code must retain the above copyright notice, this
  10. ! list of conditions and the following disclaimer.
  11. !
  12. ! 2. Redistributions in binary form must reproduce the above copyright notice,
  13. ! this list of conditions and the following disclaimer in the documentation
  14. ! and/or other materials provided with the distribution.
  15. !
  16. ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. ! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. ! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  20. ! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. ! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. ! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. ! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. ! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. module smartredis_client
  27. use iso_c_binding, only : c_ptr, c_bool, c_null_ptr, c_char, c_int
  28. use iso_c_binding, only : c_int8_t, c_int16_t, c_int32_t, c_int64_t, c_float, c_double, c_size_t
  29. use iso_c_binding, only : c_loc, c_f_pointer
  30. use, intrinsic :: iso_fortran_env, only: stderr => error_unit
  31. use smartredis_dataset, only : dataset_type
  32. use fortran_c_interop, only : convert_char_array_to_c, enum_kind
  33. implicit none; private
  34. include "enum_fortran.inc"
  35. include "client/client_interfaces.inc"
  36. include "client/put_tensor_interfaces.inc"
  37. include "client/unpack_tensor_interfaces.inc"
  38. include "client/misc_tensor_interfaces.inc"
  39. include "client/model_interfaces.inc"
  40. include "client/script_interfaces.inc"
  41. include "client/client_dataset_interfaces.inc"
  42. include "client/ensemble_interfaces.inc"
  43. include "client/aggregation_interfaces.inc"
  44. public :: enum_kind !< The kind of integer equivalent to a C enum. According to C an Fortran
  45. !! standards this should be c_int, but is renamed here to ensure that
  46. !! users do not have to import the iso_c_binding module into their
  47. !! programs
  48. !> Stores all data and methods associated with the SmartRedis client that is used to communicate with the database
  49. type, public :: client_type
  50. private
  51. logical(kind=c_bool) :: cluster = .false. !< True if a database cluster is being used
  52. type(c_ptr) :: client_ptr = c_null_ptr !< Pointer to the initialized SmartRedisClient
  53. logical :: is_initialized = .false. !< True if client is initialized
  54. contains
  55. ! Public procedures
  56. !> Puts a tensor into the database (overloaded)
  57. generic :: put_tensor => put_tensor_i8, put_tensor_i16, put_tensor_i32, put_tensor_i64, &
  58. put_tensor_float, put_tensor_double
  59. !> Retrieve the tensor in the database into already allocated memory (overloaded)
  60. generic :: unpack_tensor => unpack_tensor_i8, unpack_tensor_i16, unpack_tensor_i32, unpack_tensor_i64, &
  61. unpack_tensor_float, unpack_tensor_double
  62. !> Decode a response code from an API function
  63. procedure :: SR_error_parser
  64. !> Initializes a new instance of the SmartRedis client
  65. procedure :: initialize => initialize_client
  66. !> Check if a SmartRedis client has been initialized
  67. procedure :: isinitialized
  68. !> Destructs a new instance of the SmartRedis client
  69. procedure :: destructor
  70. !> Check the database for the existence of a specific model
  71. procedure :: model_exists
  72. !> Check the database for the existence of a specific tensor
  73. procedure :: tensor_exists
  74. !> Check the database for the existence of a specific key
  75. procedure :: key_exists
  76. !> Check the database for the existence of a specific dataset
  77. procedure :: dataset_exists
  78. !> Poll the database and return if the model exists
  79. procedure :: poll_model
  80. !> Poll the database and return if the tensor exists
  81. procedure :: poll_tensor
  82. !> Poll the database and return if the datasaet exists
  83. procedure :: poll_dataset
  84. !> Poll the database and return if the key exists
  85. procedure :: poll_key
  86. !> Rename a tensor within the database
  87. procedure :: rename_tensor
  88. !> Delete a tensor from the database
  89. procedure :: delete_tensor
  90. !> Copy a tensor within the database to a new name
  91. procedure :: copy_tensor
  92. !> Set a model from a file
  93. procedure :: set_model_from_file
  94. !> Set a model from a file on a system with multiple GPUs
  95. procedure :: set_model_from_file_multigpu
  96. !> Set a model from a byte string that has been loaded within the application
  97. procedure :: set_model
  98. !> Set a model from a byte string that has been loaded within the application on a system with multiple GPUs
  99. procedure :: set_model_multigpu
  100. !> Retrieve the model as a byte string
  101. procedure :: get_model
  102. !> Set a script from a specified file
  103. procedure :: set_script_from_file
  104. !> Set a script from a specified file on a system with multiple GPUS
  105. procedure :: set_script_from_file_multigpu
  106. !> Set a script as a byte or text string
  107. procedure :: set_script
  108. !> Set a script as a byte or text string on a system with multiple GPUs
  109. procedure :: set_script_multigpu
  110. !> Retrieve the script from the database
  111. procedure :: get_script
  112. !> Run a script that has already been stored in the database
  113. procedure :: run_script
  114. !> Run a script that has already been stored in the database with multiple GPUs
  115. procedure :: run_script_multigpu
  116. !> Run a model that has already been stored in the database
  117. procedure :: run_model
  118. !> Run a model that has already been stored in the database with multiple GPUs
  119. procedure :: run_model_multigpu
  120. !> Remove a script from the database
  121. procedure :: delete_script
  122. !> Remove a script from the database with multiple GPUs
  123. procedure :: delete_script_multigpu
  124. !> Remove a model from the database
  125. procedure :: delete_model
  126. !> Remove a model from the database with multiple GPUs
  127. procedure :: delete_model_multigpu
  128. !> Put a SmartRedis dataset into the database
  129. procedure :: put_dataset
  130. !> Retrieve a SmartRedis dataset from the database
  131. procedure :: get_dataset
  132. !> Rename the dataset within the database
  133. procedure :: rename_dataset
  134. !> Copy a dataset stored in the database into another name
  135. procedure :: copy_dataset
  136. !> Delete the dataset from the database
  137. procedure :: delete_dataset
  138. !> If true, preprend the ensemble id for tensor-related keys
  139. procedure :: use_tensor_ensemble_prefix
  140. !> If true, preprend the ensemble id for model-related keys
  141. procedure :: use_model_ensemble_prefix
  142. !> If true, preprend the ensemble id for dataset list-related keys
  143. procedure :: use_list_ensemble_prefix
  144. !> Specify a specific source of data (e.g. another ensemble member)
  145. procedure :: set_data_source
  146. !> Append a dataset to a list for aggregation
  147. procedure :: append_to_list
  148. !> Delete an aggregation list
  149. procedure :: delete_list
  150. !> Copy an aggregation list
  151. procedure :: copy_list
  152. !> Rename an existing aggregation list
  153. procedure :: rename_list
  154. !> Retrieve the number of datasets in the list
  155. procedure :: get_list_length
  156. !> Repeatedly check the length of the list until it is a given size
  157. procedure :: poll_list_length
  158. !> Repeatedly check the length of the list until it greater than or equal to the given size
  159. procedure :: poll_list_length_gte
  160. !> Repeatedly check the length of the list until it less than or equal to the given size
  161. procedure :: poll_list_length_lte
  162. !> Retrieve vector of datasetes from the list
  163. procedure :: get_datasets_from_list
  164. ! Private procedures
  165. procedure, private :: put_tensor_i8
  166. procedure, private :: put_tensor_i16
  167. procedure, private :: put_tensor_i32
  168. procedure, private :: put_tensor_i64
  169. procedure, private :: put_tensor_float
  170. procedure, private :: put_tensor_double
  171. procedure, private :: unpack_tensor_i8
  172. procedure, private :: unpack_tensor_i16
  173. procedure, private :: unpack_tensor_i32
  174. procedure, private :: unpack_tensor_i64
  175. procedure, private :: unpack_tensor_float
  176. procedure, private :: unpack_tensor_double
  177. end type client_type
  178. contains
  179. !> Decode a response code from an API function
  180. function SR_error_parser(self, response_code) result(is_error)
  181. class(client_type), intent(in) :: self !< Receives the initialized client
  182. integer (kind=enum_kind), intent(in) :: response_code !< The response code to decode
  183. logical :: is_error !< Indicates whether this is an error response
  184. is_error = .true.
  185. select case (response_code)
  186. case(SRNoError)
  187. is_error = .false.
  188. case(SRBadAllocError)
  189. write(stderr,*) "Memory allocation error"
  190. case(SRDatabaseError)
  191. write(stderr,*) "Backend database error"
  192. case(SRInternalError)
  193. write(stderr,*) "Internal SmartRedis error"
  194. case(SRRuntimeError)
  195. write(stderr,*) "Runtime error executing an operation"
  196. case(SRParameterError)
  197. write(stderr,*) "Bad parameter error"
  198. case(SRTimeoutError)
  199. write(stderr,*) "Timeout error"
  200. case(SRKeyError)
  201. write(stderr,*) "Key error"
  202. case(SRTypeError)
  203. write(stderr,*) "Type mismatch error"
  204. case default
  205. write(stderr,*) "Invalid or uninitialized response code"
  206. end select
  207. end function SR_error_parser
  208. !> Initializes a new instance of a SmartRedis client
  209. function initialize_client(self, cluster)
  210. integer(kind=enum_kind) :: initialize_client
  211. class(client_type), intent(inout) :: self !< Receives the initialized client
  212. logical, optional, intent(in ) :: cluster !< If true, client uses a database cluster (Default: .false.)
  213. if (present(cluster)) self%cluster = cluster
  214. initialize_client = c_constructor(self%cluster, self%client_ptr)
  215. self%is_initialized = initialize_client .eq. SRNoError
  216. end function initialize_client
  217. !> Check whether the client has been initialized
  218. logical function isinitialized(this)
  219. class(client_type) :: this
  220. isinitialized = this%is_initialized
  221. end function isinitialized
  222. !> A destructor for the SmartRedis client
  223. function destructor(self)
  224. integer(kind=enum_kind) :: destructor
  225. class(client_type), intent(inout) :: self
  226. destructor = c_destructor(self%client_ptr)
  227. self%client_ptr = C_NULL_PTR
  228. end function destructor
  229. !> Check if the specified key exists in the database
  230. function key_exists(self, key, exists)
  231. class(client_type), intent(in) :: self !< The client
  232. character(len=*), intent(in) :: key !< The key to check
  233. logical(kind=c_bool), intent(out) :: exists !< Receives whether the key exists
  234. integer(kind=enum_kind) :: key_exists
  235. ! Local variables
  236. character(kind=c_char, len=len_trim(key)) :: c_key
  237. integer(kind=c_size_t) :: c_key_length
  238. c_key = trim(key)
  239. c_key_length = len_trim(key)
  240. key_exists = key_exists_c(self%client_ptr, c_key, c_key_length, exists)
  241. end function key_exists
  242. !> Check if the specified model exists in the database
  243. function model_exists(self, model_name, exists) result(code)
  244. class(client_type), intent(in) :: self !< The client
  245. character(len=*), intent(in) :: model_name !< The model to check
  246. logical(kind=c_bool), intent(out) :: exists !< Receives whether the model exists
  247. integer(kind=enum_kind) :: code
  248. ! Local variables
  249. character(kind=c_char, len=len_trim(model_name)) :: c_model_name
  250. integer(kind=c_size_t) :: c_model_name_length
  251. c_model_name = trim(model_name)
  252. c_model_name_length = len_trim(model_name)
  253. code = model_exists_c(self%client_ptr, c_model_name, c_model_name_length, exists)
  254. end function model_exists
  255. !> Check if the specified tensor exists in the database
  256. function tensor_exists(self, tensor_name, exists) result(code)
  257. class(client_type), intent(in) :: self !< The client
  258. character(len=*), intent(in) :: tensor_name !< The tensor to check
  259. logical(kind=c_bool), intent(out) :: exists !< Receives whether the model exists
  260. integer(kind=enum_kind) :: code
  261. ! Local variables
  262. character(kind=c_char, len=len_trim(tensor_name)) :: c_tensor_name
  263. integer(kind=c_size_t) :: c_tensor_name_length
  264. c_tensor_name = trim(tensor_name)
  265. c_tensor_name_length = len_trim(tensor_name)
  266. code = tensor_exists_c(self%client_ptr, c_tensor_name, c_tensor_name_length, exists)
  267. end function tensor_exists
  268. !> Check if the specified dataset exists in the database
  269. function dataset_exists(this, dataset_name, exists) result(code)
  270. class(client_type), intent(in) :: this !< The client
  271. character(len=*), intent(in) :: dataset_name !< The dataset to check
  272. logical(kind=c_bool), intent(out) :: exists !< Receives whether the model exists
  273. integer(kind=enum_kind) :: code
  274. character(kind=c_char, len=len_trim(dataset_name)) :: c_dataset_name
  275. integer(kind=c_size_t) :: c_dataset_name_length
  276. c_dataset_name = trim(dataset_name)
  277. c_dataset_name_length = len_trim(dataset_name)
  278. code = dataset_exists_c(this%client_ptr, c_dataset_name, c_dataset_name_length, exists)
  279. end function dataset_exists
  280. !> Repeatedly poll the database until the tensor exists or the number of tries is exceeded
  281. function poll_tensor(self, tensor_name, poll_frequency_ms, num_tries, exists) result(code)
  282. class(client_type), intent(in) :: self !< The client
  283. character(len=*), intent(in) :: tensor_name !< name in the database to poll
  284. integer, intent(in) :: poll_frequency_ms !< Frequency at which to poll the database (ms)
  285. integer, intent(in) :: num_tries !< Number of times to poll the database before failing
  286. logical(kind=c_bool), intent(out) :: exists !< Receives whether the tensor exists
  287. integer(kind=enum_kind) :: code
  288. ! Local variables
  289. character(kind=c_char,len=len_trim(tensor_name)) :: c_tensor_name
  290. integer(kind=c_size_t) :: c_tensor_name_length
  291. integer(kind=c_int) :: c_poll_frequency, c_num_tries
  292. c_tensor_name = trim(tensor_name)
  293. c_tensor_name_length = len_trim(tensor_name)
  294. c_num_tries = num_tries
  295. c_poll_frequency = poll_frequency_ms
  296. code = poll_tensor_c(self%client_ptr, c_tensor_name, c_tensor_name_length, c_poll_frequency, c_num_tries, exists)
  297. end function poll_tensor
  298. !> Repeatedly poll the database until the dataset exists or the number of tries is exceeded
  299. function poll_dataset(self, dataset_name, poll_frequency_ms, num_tries, exists)
  300. integer(kind=enum_kind) :: poll_dataset
  301. class(client_type), intent(in) :: self !< The client
  302. character(len=*), intent(in) :: dataset_name !< Name in the database to poll
  303. integer, intent(in) :: poll_frequency_ms !< Frequency at which to poll the database (ms)
  304. integer, intent(in) :: num_tries !< Number of times to poll the database before failing
  305. logical(kind=c_bool), intent(out) :: exists !< Receives whether the tensor exists
  306. ! Local variables
  307. character(kind=c_char,len=len_trim(dataset_name)) :: c_dataset_name
  308. integer(kind=c_size_t) :: c_dataset_name_length
  309. integer(kind=c_int) :: c_poll_frequency, c_num_tries
  310. c_dataset_name = trim(dataset_name)
  311. c_dataset_name_length = len_trim(dataset_name)
  312. c_num_tries = num_tries
  313. c_poll_frequency = poll_frequency_ms
  314. poll_dataset = poll_dataset_c(self%client_ptr, c_dataset_name, c_dataset_name_length, c_poll_frequency, c_num_tries, exists)
  315. end function poll_dataset
  316. !> Repeatedly poll the database until the model exists or the number of tries is exceeded
  317. function poll_model(self, model_name, poll_frequency_ms, num_tries, exists) result(code)
  318. class(client_type), intent(in) :: self !< The client
  319. character(len=*), intent(in) :: model_name !< Name in the database to poll
  320. integer, intent(in) :: poll_frequency_ms !< Frequency at which to poll the database (ms)
  321. integer, intent(in) :: num_tries !< Number of times to poll the database before failing
  322. logical(kind=c_bool), intent(out) :: exists !< Receives whether the model exists
  323. integer(kind=enum_kind) :: code
  324. ! Local variables
  325. character(kind=c_char,len=len_trim(model_name)) :: c_model_name
  326. integer(kind=c_size_t) :: c_model_name_length
  327. integer(kind=c_int) :: c_poll_frequency, c_num_tries
  328. c_model_name = trim(model_name)
  329. c_model_name_length = len_trim(model_name)
  330. c_num_tries = num_tries
  331. c_poll_frequency = poll_frequency_ms
  332. code = poll_model_c(self%client_ptr, c_model_name, c_model_name_length, c_poll_frequency, c_num_tries, exists)
  333. end function poll_model
  334. !> Repeatedly poll the database until the key exists or the number of tries is exceeded
  335. function poll_key(self, key, poll_frequency_ms, num_tries, exists) result(code)
  336. class(client_type), intent(in) :: self !< The client
  337. character(len=*), intent(in) :: key !< Key in the database to poll
  338. integer, intent(in) :: poll_frequency_ms !< Frequency at which to poll the database (ms)
  339. integer, intent(in) :: num_tries !< Number of times to poll the database before failing
  340. logical(kind=c_bool), intent(out) :: exists !< Receives whether the key exists
  341. integer(kind=enum_kind) :: code
  342. ! Local variables
  343. character(kind=c_char, len=len_trim(key)) :: c_key
  344. integer(kind=c_size_t) :: c_key_length
  345. integer(kind=c_int) :: c_poll_frequency, c_num_tries
  346. c_key = trim(key)
  347. c_key_length = len_trim(key)
  348. c_num_tries = num_tries
  349. c_poll_frequency = poll_frequency_ms
  350. code = poll_key_c(self%client_ptr, c_key, c_key_length, c_poll_frequency, c_num_tries, exists)
  351. end function poll_key
  352. !> Put a tensor whose Fortran type is the equivalent 'int8' C-type
  353. function put_tensor_i8(self, name, data, dims) result(code)
  354. integer(kind=c_int8_t), dimension(..), target, intent(in) :: data !< Data to be sent
  355. class(client_type), intent(in) :: self !< Fortran SmartRedis client
  356. character(len=*), intent(in) :: name !< The unique name used to store in the database
  357. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  358. integer(kind=enum_kind) :: code
  359. include 'client/put_tensor_methods_common.inc'
  360. ! Define the type and call the C-interface
  361. data_type = tensor_int8
  362. code = put_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, &
  363. c_n_dims, data_type, c_fortran_contiguous)
  364. end function put_tensor_i8
  365. !> Put a tensor whose Fortran type is the equivalent 'int16' C-type
  366. function put_tensor_i16(self, name, data, dims) result(code)
  367. integer(kind=c_int16_t), dimension(..), target, intent(in) :: data !< Data to be sent
  368. class(client_type), intent(in) :: self !< Fortran SmartRedis client
  369. character(len=*), intent(in) :: name !< The unique name used to store in the database
  370. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  371. integer(kind=enum_kind) :: code
  372. include 'client/put_tensor_methods_common.inc'
  373. ! Define the type and call the C-interface
  374. data_type = tensor_int16
  375. code = put_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  376. data_type, c_fortran_contiguous)
  377. end function put_tensor_i16
  378. !> Put a tensor whose Fortran type is the equivalent 'int32' C-type
  379. function put_tensor_i32(self, name, data, dims) result(code)
  380. integer(kind=c_int32_t), dimension(..), target, intent(in) :: data !< Data to be sent
  381. class(client_type), intent(in) :: self !< Fortran SmartRedis client
  382. character(len=*), intent(in) :: name !< The unique name used to store in the database
  383. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  384. integer(kind=enum_kind) :: code
  385. include 'client/put_tensor_methods_common.inc'
  386. ! Define the type and call the C-interface
  387. data_type = tensor_int32
  388. code = put_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  389. data_type, c_fortran_contiguous)
  390. end function put_tensor_i32
  391. !> Put a tensor whose Fortran type is the equivalent 'int64' C-type
  392. function put_tensor_i64(self, name, data, dims) result(code)
  393. integer(kind=c_int64_t), dimension(..), target, intent(in) :: data !< Data to be sent
  394. class(client_type), intent(in) :: self !< Fortran SmartRedis client
  395. character(len=*), intent(in) :: name !< The unique name used to store in the database
  396. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  397. integer(kind=enum_kind) :: code
  398. include 'client/put_tensor_methods_common.inc'
  399. ! Define the type and call the C-interface
  400. data_type = tensor_int64
  401. code = put_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  402. data_type, c_fortran_contiguous)
  403. end function put_tensor_i64
  404. !> Put a tensor whose Fortran type is the equivalent 'float' C-type
  405. function put_tensor_float(self, name, data, dims) result(code)
  406. real(kind=c_float), dimension(..), target, intent(in) :: data !< Data to be sent
  407. class(client_type), intent(in) :: self !< Fortran SmartRedis client
  408. character(len=*), intent(in) :: name !< The unique name used to store in the database
  409. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  410. integer(kind=enum_kind) :: code
  411. include 'client/put_tensor_methods_common.inc'
  412. ! Define the type and call the C-interface
  413. data_type = tensor_flt
  414. code = put_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  415. data_type, c_fortran_contiguous)
  416. end function put_tensor_float
  417. !> Put a tensor whose Fortran type is the equivalent 'double' C-type
  418. function put_tensor_double(self, name, data, dims) result(code)
  419. real(kind=c_double), dimension(..), target, intent(in) :: data !< Data to be sent
  420. class(client_type), intent(in) :: self !< Fortran SmartRedis client
  421. character(len=*), intent(in) :: name !< The unique name used to store in the database
  422. integer, dimension(:), intent(in) :: dims !< The length of each dimension
  423. integer(kind=enum_kind) :: code
  424. include 'client/put_tensor_methods_common.inc'
  425. ! Define the type and call the C-interface
  426. data_type = tensor_dbl
  427. code = put_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  428. data_type, c_fortran_contiguous)
  429. end function put_tensor_double
  430. !> Put a tensor whose Fortran type is the equivalent 'int8' C-type
  431. function unpack_tensor_i8(self, name, result, dims) result(code)
  432. integer(kind=c_int8_t), dimension(..), target, intent(out) :: result !< Data to be sent
  433. class(client_type), intent(in) :: self !< Pointer to the initialized client
  434. character(len=*), intent(in) :: name !< The name to use to place the tensor
  435. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  436. integer(kind=enum_kind) :: code
  437. include 'client/unpack_tensor_methods_common.inc'
  438. ! Define the type and call the C-interface
  439. data_type = tensor_int8
  440. code = unpack_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  441. data_type, mem_layout)
  442. end function unpack_tensor_i8
  443. !> Put a tensor whose Fortran type is the equivalent 'int16' C-type
  444. function unpack_tensor_i16(self, name, result, dims) result(code)
  445. integer(kind=c_int16_t), dimension(..), target, intent(out) :: result !< Data to be sent
  446. class(client_type), intent(in) :: self !< Pointer to the initialized client
  447. character(len=*), intent(in) :: name !< The name to use to place the tensor
  448. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  449. integer(kind=enum_kind) :: code
  450. include 'client/unpack_tensor_methods_common.inc'
  451. ! Define the type and call the C-interface
  452. data_type = tensor_int16
  453. code = unpack_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  454. data_type, mem_layout)
  455. end function unpack_tensor_i16
  456. !> Put a tensor whose Fortran type is the equivalent 'int32' C-type
  457. function unpack_tensor_i32(self, name, result, dims) result(code)
  458. integer(kind=c_int32_t), dimension(..), target, intent(out) :: result !< Data to be sent
  459. class(client_type), intent(in) :: self !< Pointer to the initialized client
  460. character(len=*), intent(in) :: name !< The name to use to place the tensor
  461. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  462. integer(kind=enum_kind) :: code
  463. include 'client/unpack_tensor_methods_common.inc'
  464. ! Define the type and call the C-interface
  465. data_type = tensor_int32
  466. code = unpack_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, c_n_dims, &
  467. data_type, mem_layout)
  468. end function unpack_tensor_i32
  469. !> Put a tensor whose Fortran type is the equivalent 'int64' C-type
  470. function unpack_tensor_i64(self, name, result, dims) result(code)
  471. integer(kind=c_int64_t), dimension(..), target, intent(out) :: result !< Data to be sent
  472. class(client_type), intent(in) :: self !< Pointer to the initialized client
  473. character(len=*), intent(in) :: name !< The name to use to place the tensor
  474. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  475. integer(kind=enum_kind) :: code
  476. include 'client/unpack_tensor_methods_common.inc'
  477. ! Define the type and call the C-interface
  478. data_type = tensor_int64
  479. code = unpack_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, &
  480. c_n_dims, data_type, mem_layout)
  481. end function unpack_tensor_i64
  482. !> Put a tensor whose Fortran type is the equivalent 'float' C-type
  483. function unpack_tensor_float(self, name, result, dims) result(code)
  484. real(kind=c_float), dimension(..), target, intent(out) :: result !< Data to be sent
  485. class(client_type), intent(in) :: self !< Pointer to the initialized client
  486. character(len=*), intent(in) :: name !< The name to use to place the tensor
  487. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  488. integer(kind=enum_kind) :: code
  489. include 'client/unpack_tensor_methods_common.inc'
  490. ! Define the type and call the C-interface
  491. data_type = tensor_flt
  492. code = unpack_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, &
  493. c_n_dims, data_type, mem_layout)
  494. end function unpack_tensor_float
  495. !> Put a tensor whose Fortran type is the equivalent 'double' C-type
  496. function unpack_tensor_double(self, name, result, dims) result(code)
  497. real(kind=c_double), dimension(..), target, intent(out) :: result !< Data to be sent
  498. class(client_type), intent(in) :: self !< Pointer to the initialized client
  499. character(len=*), intent(in) :: name !< The name to use to place the tensor
  500. integer, dimension(:), intent(in) :: dims !< Length along each dimension of the tensor
  501. integer(kind=enum_kind) :: code
  502. include 'client/unpack_tensor_methods_common.inc'
  503. ! Define the type and call the C-interface
  504. data_type = tensor_dbl
  505. code = unpack_tensor_c(self%client_ptr, c_name, name_length, data_ptr, c_dims_ptr, &
  506. c_n_dims, data_type, mem_layout)
  507. end function unpack_tensor_double
  508. !> Move a tensor to a new name
  509. function rename_tensor(self, old_name, new_name) result(code)
  510. class(client_type), intent(in) :: self !< The initialized Fortran SmartRedis client
  511. character(len=*), intent(in) :: old_name !< The current name for the tensor
  512. !! excluding null terminating character
  513. character(len=*), intent(in) :: new_name !< The new tensor name
  514. integer(kind=enum_kind) :: code
  515. ! Local variables
  516. character(kind=c_char, len=len_trim(old_name)) :: c_old_name
  517. character(kind=c_char, len=len_trim(new_name)) :: c_new_name
  518. integer(kind=c_size_t) :: old_name_length, new_name_length
  519. c_old_name = trim(old_name)
  520. c_new_name = trim(new_name)
  521. old_name_length = len_trim(old_name)
  522. new_name_length = len_trim(new_name)
  523. code = rename_tensor_c(self%client_ptr, c_old_name, old_name_length, c_new_name, new_name_length)
  524. end function rename_tensor
  525. !> Delete a tensor
  526. function delete_tensor(self, name) result(code)
  527. class(client_type), intent(in) :: self !< The initialized Fortran SmartRedis client
  528. character(len=*), intent(in) :: name !< The name associated with the tensor
  529. integer(kind=enum_kind) :: code
  530. ! Local variables
  531. character(kind=c_char, len=len_trim(name)) :: c_name
  532. integer(kind=c_size_t) :: name_length
  533. c_name = trim(name)
  534. name_length = len_trim(name)
  535. code = delete_tensor_c(self%client_ptr, c_name, name_length)
  536. end function delete_tensor
  537. !> Copy a tensor to the destination name
  538. function copy_tensor(self, src_name, dest_name) result(code)
  539. class(client_type), intent(in) :: self !< The initialized Fortran SmartRedis client
  540. character(len=*), intent(in) :: src_name !< The name associated with the tensor
  541. !! excluding null terminating character
  542. character(len=*), intent(in) :: dest_name !< The new tensor name
  543. integer(kind=enum_kind) :: code
  544. ! Local variables
  545. character(kind=c_char, len=len_trim(src_name)) :: c_src_name
  546. character(kind=c_char, len=len_trim(dest_name)) :: c_dest_name
  547. integer(kind=c_size_t) :: src_name_length, dest_name_length
  548. c_src_name = trim(src_name)
  549. c_dest_name = trim(dest_name)
  550. src_name_length = len_trim(src_name, kind=c_size_t)
  551. dest_name_length = len_trim(dest_name, kind=c_size_t)
  552. code = copy_tensor_c(self%client_ptr, c_src_name, src_name_length, c_dest_name, dest_name_length)
  553. end function copy_tensor
  554. !> Retrieve the model from the database
  555. function get_model(self, name, model) result(code)
  556. class(client_type), intent(in ) :: self !< An initialized SmartRedis client
  557. character(len=*), intent(in ) :: name !< The name associated with the model
  558. character(len=*), intent( out) :: model !< The model as a continuous buffer
  559. integer(kind=enum_kind) :: code
  560. ! Local variables
  561. character(kind=c_char, len=len_trim(name)) :: c_name
  562. integer(kind=c_size_t) :: name_length, model_length
  563. character(kind=c_char), dimension(:), pointer :: f_str_ptr
  564. type(c_ptr) :: c_str_ptr
  565. integer :: i
  566. c_name = trim(name)
  567. name_length = len_trim(name)
  568. code = get_model_c(self%client_ptr, name, name_length, c_str_ptr, model_length, c_str_ptr)
  569. call c_f_pointer(c_str_ptr, f_str_ptr, [ model_length ])
  570. do i=1,model_length
  571. model(i:i) = f_str_ptr(i)
  572. enddo
  573. end function get_model
  574. !> Load the machine learning model from a file and set the configuration
  575. function set_model_from_file(self, name, model_file, backend, device, batch_size, min_batch_size, tag, &
  576. inputs, outputs) result(code)
  577. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  578. character(len=*), intent(in) :: name !< The name to use to place the model
  579. character(len=*), intent(in) :: model_file !< The file storing the model
  580. character(len=*), intent(in) :: backend !< The name of the backend (TF, TFLITE, TORCH, ONNX)
  581. character(len=*), intent(in) :: device !< The name of the device (CPU, GPU, GPU:0, GPU:1...)
  582. integer, optional, intent(in) :: batch_size !< The batch size for model execution
  583. integer, optional, intent(in) :: min_batch_size !< The minimum batch size for model execution
  584. character(len=*), optional, intent(in) :: tag !< A tag to attach to the model for
  585. !! information purposes
  586. character(len=*), dimension(:), optional, intent(in) :: inputs !< One or more names of model input nodes (TF
  587. !! models)
  588. character(len=*), dimension(:), optional, intent(in) :: outputs !< One or more names of model output nodes (TF models)
  589. integer(kind=enum_kind) :: code
  590. ! Local variables
  591. character(kind=c_char, len=len_trim(name)) :: c_name
  592. character(kind=c_char, len=len_trim(model_file)) :: c_model_file
  593. character(kind=c_char, len=len_trim(backend)) :: c_backend
  594. character(kind=c_char, len=len_trim(device)) :: c_device
  595. character(kind=c_char, len=:), allocatable :: c_tag
  596. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  597. character(kind=c_char,len=1), target, dimension(1) :: dummy_inputs, dummy_outputs
  598. integer(c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  599. integer(kind=c_size_t) :: name_length, model_file_length, backend_length, device_length, tag_length, n_inputs, &
  600. n_outputs
  601. integer(kind=c_int) :: c_batch_size, c_min_batch_size
  602. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  603. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  604. integer :: i
  605. integer :: max_length, length
  606. ! Set default values for the optional inputs
  607. c_batch_size = 0
  608. if (present(batch_size)) c_batch_size = batch_size
  609. c_min_batch_size = 0
  610. if (present(min_batch_size)) c_min_batch_size = min_batch_size
  611. if (present(tag)) then
  612. allocate(character(kind=c_char, len=len_trim(tag)) :: c_tag)
  613. c_tag = tag
  614. tag_length = len_trim(tag)
  615. else
  616. allocate(character(kind=c_char, len=1) :: c_tag)
  617. c_tag = ''
  618. tag_length = 1
  619. endif
  620. ! Cast to c_char kind stringts
  621. c_name = trim(name)
  622. c_model_file = trim(model_file)
  623. c_backend = trim(backend)
  624. c_device = trim(device)
  625. name_length = len_trim(name)
  626. model_file_length = len_trim(model_file)
  627. backend_length = len_trim(backend)
  628. device_length = len_trim(device)
  629. dummy_inputs = ''
  630. if (present(inputs)) then
  631. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  632. n_inputs)
  633. else
  634. call convert_char_array_to_c(dummy_inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr,&
  635. n_inputs)
  636. endif
  637. dummy_outputs =''
  638. if (present(outputs)) then
  639. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, output_lengths_ptr,&
  640. n_outputs)
  641. else
  642. call convert_char_array_to_c(dummy_outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  643. output_lengths_ptr, n_outputs)
  644. endif
  645. code = set_model_from_file_c(self%client_ptr, c_name, name_length, c_model_file, model_file_length, &
  646. c_backend, backend_length, c_device, device_length, c_batch_size, c_min_batch_size, &
  647. c_tag, tag_length, inputs_ptr, input_lengths_ptr, n_inputs, outputs_ptr, &
  648. output_lengths_ptr, n_outputs)
  649. if (allocated(c_inputs)) deallocate(c_inputs)
  650. if (allocated(input_lengths)) deallocate(input_lengths)
  651. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  652. if (allocated(c_outputs)) deallocate(c_outputs)
  653. if (allocated(output_lengths)) deallocate(output_lengths)
  654. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  655. end function set_model_from_file
  656. !> Load the machine learning model from a file and set the configuration for use in multi-GPU systems
  657. function set_model_from_file_multigpu(self, name, model_file, backend, first_gpu, num_gpus, batch_size, min_batch_size, &
  658. tag, inputs, outputs) result(code)
  659. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  660. character(len=*), intent(in) :: name !< The name to use to place the model
  661. character(len=*), intent(in) :: model_file !< The file storing the model
  662. character(len=*), intent(in) :: backend !< The name of the backend (TF, TFLITE, TORCH, ONNX)
  663. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  664. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  665. integer, optional, intent(in) :: batch_size !< The batch size for model execution
  666. integer, optional, intent(in) :: min_batch_size !< The minimum batch size for model execution
  667. character(len=*), optional, intent(in) :: tag !< A tag to attach to the model for
  668. !! information purposes
  669. character(len=*), dimension(:), optional, intent(in) :: inputs !< One or more names of model input nodes (TF
  670. !! models)
  671. character(len=*), dimension(:), optional, intent(in) :: outputs !< One or more names of model output nodes (TF models)
  672. integer(kind=enum_kind) :: code
  673. ! Local variables
  674. character(kind=c_char, len=len_trim(name)) :: c_name
  675. character(kind=c_char, len=len_trim(model_file)) :: c_model_file
  676. character(kind=c_char, len=len_trim(backend)) :: c_backend
  677. character(kind=c_char, len=:), allocatable :: c_tag
  678. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  679. character(kind=c_char,len=1), target, dimension(1) :: dummy_inputs, dummy_outputs
  680. integer(c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  681. integer(kind=c_size_t) :: name_length, model_file_length, backend_length, tag_length, n_inputs, &
  682. n_outputs
  683. integer(kind=c_int) :: c_batch_size, c_min_batch_size, c_first_gpu, c_num_gpus
  684. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  685. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  686. integer :: i
  687. integer :: max_length, length
  688. ! Set default values for the optional inputs
  689. c_batch_size = 0
  690. if (present(batch_size)) c_batch_size = batch_size
  691. c_min_batch_size = 0
  692. if (present(min_batch_size)) c_min_batch_size = min_batch_size
  693. if (present(tag)) then
  694. allocate(character(kind=c_char, len=len_trim(tag)) :: c_tag)
  695. c_tag = tag
  696. tag_length = len_trim(tag)
  697. else
  698. allocate(character(kind=c_char, len=1) :: c_tag)
  699. c_tag = ''
  700. tag_length = 1
  701. endif
  702. ! Cast to c_char kind stringts
  703. c_name = trim(name)
  704. c_model_file = trim(model_file)
  705. c_backend = trim(backend)
  706. name_length = len_trim(name)
  707. model_file_length = len_trim(model_file)
  708. backend_length = len_trim(backend)
  709. ! Convert to C int
  710. c_first_gpu = first_gpu
  711. c_num_gpus = num_gpus
  712. dummy_inputs = ''
  713. if (present(inputs)) then
  714. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  715. n_inputs)
  716. else
  717. call convert_char_array_to_c(dummy_inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr,&
  718. n_inputs)
  719. endif
  720. dummy_outputs =''
  721. if (present(outputs)) then
  722. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, output_lengths_ptr,&
  723. n_outputs)
  724. else
  725. call convert_char_array_to_c(dummy_outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  726. output_lengths_ptr, n_outputs)
  727. endif
  728. code = set_model_from_file_multigpu_c(self%client_ptr, c_name, name_length, c_model_file, model_file_length, &
  729. c_backend, backend_length, c_first_gpu, c_num_gpus, c_batch_size, c_min_batch_size, &
  730. c_tag, tag_length, inputs_ptr, input_lengths_ptr, n_inputs, outputs_ptr, &
  731. output_lengths_ptr, n_outputs)
  732. if (allocated(c_inputs)) deallocate(c_inputs)
  733. if (allocated(input_lengths)) deallocate(input_lengths)
  734. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  735. if (allocated(c_outputs)) deallocate(c_outputs)
  736. if (allocated(output_lengths)) deallocate(output_lengths)
  737. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  738. end function set_model_from_file_multigpu
  739. !> Establish a model to run
  740. function set_model(self, name, model, backend, device, batch_size, min_batch_size, tag, &
  741. inputs, outputs) result(code)
  742. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  743. character(len=*), intent(in) :: name !< The name to use to place the model
  744. character(len=*), intent(in) :: model !< The binary representation of the model
  745. character(len=*), intent(in) :: backend !< The name of the backend (TF, TFLITE, TORCH, ONNX)
  746. character(len=*), intent(in) :: device !< The name of the device (CPU, GPU, GPU:0, GPU:1...)
  747. integer, intent(in) :: batch_size !< The batch size for model execution
  748. integer, intent(in) :: min_batch_size !< The minimum batch size for model execution
  749. character(len=*), intent(in) :: tag !< A tag to attach to the model for information purposes
  750. character(len=*), dimension(:), intent(in) :: inputs !< One or more names of model input nodes (TF models)
  751. character(len=*), dimension(:), intent(in) :: outputs !< One or more names of model output nodes (TF models)
  752. integer(kind=enum_kind) :: code
  753. ! Local variables
  754. character(kind=c_char, len=len_trim(name)) :: c_name
  755. character(kind=c_char, len=len_trim(model)) :: c_model
  756. character(kind=c_char, len=len_trim(backend)) :: c_backend
  757. character(kind=c_char, len=len_trim(device)) :: c_device
  758. character(kind=c_char, len=len_trim(tag)) :: c_tag
  759. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  760. integer(c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  761. integer(kind=c_size_t) :: name_length, model_length, backend_length, device_length, tag_length, n_inputs, &
  762. n_outputs
  763. integer(kind=c_int) :: c_batch_size, c_min_batch_size
  764. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  765. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  766. integer :: i
  767. integer :: max_length, length
  768. c_name = trim(name)
  769. c_model = trim(model)
  770. c_backend = trim(backend)
  771. c_device = trim(device)
  772. c_tag = trim(tag)
  773. name_length = len_trim(name)
  774. model_length = len_trim(model)
  775. backend_length = len_trim(backend)
  776. device_length = len_trim(device)
  777. tag_length = len_trim(tag)
  778. ! Copy the input array into a c_char
  779. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  780. n_inputs)
  781. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  782. output_lengths_ptr, n_outputs)
  783. ! Cast the batch sizes to C integers
  784. c_batch_size = batch_size
  785. c_min_batch_size = min_batch_size
  786. code = set_model_c(self%client_ptr, c_name, name_length, c_model, model_length, c_backend, backend_length, &
  787. c_device, device_length, batch_size, min_batch_size, c_tag, tag_length, &
  788. inputs_ptr, input_lengths_ptr, n_inputs, outputs_ptr, output_lengths_ptr, n_outputs)
  789. if (allocated(c_inputs)) deallocate(c_inputs)
  790. if (allocated(input_lengths)) deallocate(input_lengths)
  791. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  792. if (allocated(c_outputs)) deallocate(c_outputs)
  793. if (allocated(output_lengths)) deallocate(output_lengths)
  794. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  795. end function set_model
  796. !> Set a model from a byte string to run on a system with multiple GPUs
  797. function set_model_multigpu(self, name, model, backend, first_gpu, num_gpus, batch_size, min_batch_size, tag, &
  798. inputs, outputs) result(code)
  799. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  800. character(len=*), intent(in) :: name !< The name to use to place the model
  801. character(len=*), intent(in) :: model !< The binary representation of the model
  802. character(len=*), intent(in) :: backend !< The name of the backend (TF, TFLITE, TORCH, ONNX)
  803. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  804. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  805. integer, intent(in) :: batch_size !< The batch size for model execution
  806. integer, intent(in) :: min_batch_size !< The minimum batch size for model execution
  807. character(len=*), intent(in) :: tag !< A tag to attach to the model for information purposes
  808. character(len=*), dimension(:), intent(in) :: inputs !< One or more names of model input nodes (TF models)
  809. character(len=*), dimension(:), intent(in) :: outputs !< One or more names of model output nodes (TF models)
  810. integer(kind=enum_kind) :: code
  811. ! Local variables
  812. character(kind=c_char, len=len_trim(name)) :: c_name
  813. character(kind=c_char, len=len_trim(model)) :: c_model
  814. character(kind=c_char, len=len_trim(backend)) :: c_backend
  815. character(kind=c_char, len=len_trim(tag)) :: c_tag
  816. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  817. integer(c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  818. integer(kind=c_size_t) :: name_length, model_length, backend_length, tag_length, n_inputs, n_outputs
  819. integer(kind=c_int) :: c_batch_size, c_min_batch_size, c_first_gpu, c_num_gpus
  820. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  821. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  822. integer :: i
  823. integer :: max_length, length
  824. c_name = trim(name)
  825. c_model = trim(model)
  826. c_backend = trim(backend)
  827. c_tag = trim(tag)
  828. name_length = len_trim(name)
  829. model_length = len_trim(model)
  830. backend_length = len_trim(backend)
  831. tag_length = len_trim(tag)
  832. ! Copy the input array into a c_char
  833. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  834. n_inputs)
  835. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  836. output_lengths_ptr, n_outputs)
  837. ! Cast the batch sizes to C integers
  838. c_batch_size = batch_size
  839. c_min_batch_size = min_batch_size
  840. c_first_gpu = first_gpu
  841. c_num_gpus = num_gpus
  842. code = set_model_multigpu_c(self%client_ptr, c_name, name_length, c_model, model_length, c_backend, backend_length, &
  843. c_first_gpu, c_num_gpus, c_batch_size, c_min_batch_size, c_tag, tag_length, &
  844. inputs_ptr, input_lengths_ptr, n_inputs, outputs_ptr, output_lengths_ptr, n_outputs)
  845. if (allocated(c_inputs)) deallocate(c_inputs)
  846. if (allocated(input_lengths)) deallocate(input_lengths)
  847. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  848. if (allocated(c_outputs)) deallocate(c_outputs)
  849. if (allocated(output_lengths)) deallocate(output_lengths)
  850. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  851. end function set_model_multigpu
  852. !> Run a model in the database using the specified input and output tensors
  853. function run_model(self, name, inputs, outputs) result(code)
  854. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  855. character(len=*), intent(in) :: name !< The name to use to place the model
  856. character(len=*), dimension(:), intent(in) :: inputs !< One or more names of model input nodes (TF models)
  857. character(len=*), dimension(:), intent(in) :: outputs !< One or more names of model output nodes (TF models)
  858. integer(kind=enum_kind) :: code
  859. ! Local variables
  860. character(kind=c_char, len=len_trim(name)) :: c_name
  861. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  862. integer(c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  863. integer(kind=c_size_t) :: n_inputs, n_outputs, name_length
  864. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  865. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  866. integer :: i
  867. integer :: max_length, length
  868. c_name = trim(name)
  869. name_length = len_trim(name)
  870. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  871. n_inputs)
  872. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  873. output_lengths_ptr, n_outputs)
  874. code = run_model_c(self%client_ptr, c_name, name_length, inputs_ptr, input_lengths_ptr, n_inputs, outputs_ptr, &
  875. output_lengths_ptr, n_outputs)
  876. if (allocated(c_inputs)) deallocate(c_inputs)
  877. if (allocated(input_lengths)) deallocate(input_lengths)
  878. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  879. if (allocated(c_outputs)) deallocate(c_outputs)
  880. if (allocated(output_lengths)) deallocate(output_lengths)
  881. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  882. end function run_model
  883. !> Run a model in the database using the specified input and output tensors in a multi-GPU system
  884. function run_model_multigpu(self, name, inputs, outputs, offset, first_gpu, num_gpus) result(code)
  885. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  886. character(len=*), intent(in) :: name !< The name to use to place the model
  887. character(len=*), dimension(:), intent(in) :: inputs !< One or more names of model input nodes (TF models)
  888. character(len=*), dimension(:), intent(in) :: outputs !< One or more names of model output nodes (TF models)
  889. integer, intent(in) :: offset !< Index of the current image, such as a processor ID
  890. !! or MPI rank
  891. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  892. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  893. integer(kind=enum_kind) :: code
  894. ! Local variables
  895. character(kind=c_char, len=len_trim(name)) :: c_name
  896. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  897. integer(kind=c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  898. integer(kind=c_size_t) :: n_inputs, n_outputs, name_length
  899. integer(kind=c_int) :: c_first_gpu, c_num_gpus, c_offset
  900. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  901. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  902. integer :: i
  903. integer :: max_length, length
  904. c_name = trim(name)
  905. name_length = len_trim(name)
  906. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  907. n_inputs)
  908. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  909. output_lengths_ptr, n_outputs)
  910. ! Cast to c integer
  911. c_offset = offset
  912. c_first_gpu = first_gpu
  913. c_num_gpus = num_gpus
  914. code = run_model_multigpu_c(self%client_ptr, c_name, name_length, inputs_ptr, input_lengths_ptr, n_inputs, &
  915. outputs_ptr, output_lengths_ptr, n_outputs, c_offset, c_first_gpu, c_num_gpus)
  916. if (allocated(c_inputs)) deallocate(c_inputs)
  917. if (allocated(input_lengths)) deallocate(input_lengths)
  918. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  919. if (allocated(c_outputs)) deallocate(c_outputs)
  920. if (allocated(output_lengths)) deallocate(output_lengths)
  921. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  922. end function run_model_multigpu
  923. !> Remove a model from the database
  924. function delete_model(self, name) result(code)
  925. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  926. character(len=*), intent(in) :: name !< The name to use to remove the model
  927. integer(kind=enum_kind) :: code
  928. ! Local variables
  929. character(kind=c_char, len=len_trim(name)) :: c_name
  930. integer(kind=c_size_t) :: name_length
  931. c_name = trim(name)
  932. name_length = len_trim(name)
  933. code = delete_model_c(self%client_ptr, c_name, name_length)
  934. end function delete_model
  935. !> Remove a model from the database
  936. function delete_model_multigpu(self, name, first_gpu, num_gpus) result(code)
  937. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  938. character(len=*), intent(in) :: name !< The name to use to remove the model
  939. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  940. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  941. integer(kind=enum_kind) :: code
  942. ! Local variables
  943. character(kind=c_char, len=len_trim(name)) :: c_name
  944. integer(kind=c_size_t) :: name_length
  945. integer(kind=c_int) :: c_first_gpu, c_num_gpus
  946. c_name = trim(name)
  947. name_length = len_trim(name)
  948. c_first_gpu = first_gpu
  949. c_num_gpus = num_gpus
  950. code = delete_model_multigpu_c(self%client_ptr, c_name, name_length, c_first_gpu, c_num_gpus )
  951. end function delete_model_multigpu
  952. !> Retrieve the script from the database
  953. function get_script(self, name, script) result(code)
  954. class(client_type), intent(in ) :: self !< An initialized SmartRedis client
  955. character(len=*), intent(in ) :: name !< The name to use to place the script
  956. character(len=*), intent( out) :: script !< The script as a continuous buffer
  957. integer(kind=enum_kind) :: code
  958. ! Local variables
  959. character(kind=c_char, len=len_trim(name)) :: c_name
  960. integer(kind=c_size_t) :: name_length, script_length
  961. character(kind=c_char), dimension(:), pointer :: f_str_ptr
  962. type(c_ptr) :: c_str_ptr
  963. integer :: i
  964. c_name = trim(name)
  965. name_length = len_trim(name)
  966. code = get_script_c(self%client_ptr, name, name_length, c_str_ptr, script_length)
  967. call c_f_pointer(c_str_ptr, f_str_ptr, [ script_length ])
  968. do i=1,script_length
  969. script(i:i) = f_str_ptr(i)
  970. enddo
  971. end function get_script
  972. !> Set a script (from file) in the database for future execution
  973. function set_script_from_file(self, name, device, script_file) result(code)
  974. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  975. character(len=*), intent(in) :: name !< The name to use to place the script
  976. character(len=*), intent(in) :: device !< The name of the device (CPU, GPU, GPU:0, GPU:1...)
  977. character(len=*), intent(in) :: script_file !< The file storing the script
  978. integer(kind=enum_kind) :: code
  979. ! Local variables
  980. character(kind=c_char, len=len_trim(name)) :: c_name
  981. character(kind=c_char, len=len_trim(device)) :: c_device
  982. character(kind=c_char, len=len_trim(script_file)) :: c_script_file
  983. integer(kind=c_size_t) :: name_length
  984. integer(kind=c_size_t) :: script_file_length
  985. integer(kind=c_size_t) :: device_length
  986. c_name = trim(name)
  987. c_script_file = trim(script_file)
  988. c_device = trim(device)
  989. name_length = len_trim(name)
  990. script_file_length = len_trim(script_file)
  991. device_length = len_trim(device)
  992. code = set_script_from_file_c(self%client_ptr, c_name, name_length, c_device, device_length, &
  993. c_script_file, script_file_length)
  994. end function set_script_from_file
  995. !> Set a script (from file) in the database for future execution in a multi-GPU system
  996. function set_script_from_file_multigpu(self, name, script_file, first_gpu, num_gpus) result(code)
  997. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  998. character(len=*), intent(in) :: name !< The name to use to place the script
  999. character(len=*), intent(in) :: script_file !< The file storing the script
  1000. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  1001. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  1002. integer(kind=enum_kind) :: code
  1003. ! Local variables
  1004. character(kind=c_char, len=len_trim(name)) :: c_name
  1005. character(kind=c_char, len=len_trim(script_file)) :: c_script_file
  1006. integer(kind=c_size_t) :: name_length
  1007. integer(kind=c_size_t) :: script_file_length
  1008. integer(kind=c_size_t) :: device_length
  1009. integer(kind=c_int) :: c_first_gpu, c_num_gpus
  1010. c_name = trim(name)
  1011. c_script_file = trim(script_file)
  1012. name_length = len_trim(name)
  1013. script_file_length = len_trim(script_file)
  1014. c_first_gpu = first_gpu
  1015. c_num_gpus = num_gpus
  1016. code = set_script_from_file_multigpu_c(self%client_ptr, c_name, name_length, c_script_file, script_file_length, &
  1017. c_first_gpu, c_num_gpus)
  1018. end function set_script_from_file_multigpu
  1019. !> Set a script (from buffer) in the database for future execution
  1020. function set_script(self, name, device, script) result(code)
  1021. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1022. character(len=*), intent(in) :: name !< The name to use to place the script
  1023. character(len=*), intent(in) :: device !< The name of the device (CPU, GPU, GPU:0, GPU:1...)
  1024. character(len=*), intent(in) :: script !< The file storing the script
  1025. integer(kind=enum_kind) :: code
  1026. ! Local variables
  1027. character(kind=c_char, len=len_trim(name)) :: c_name
  1028. character(kind=c_char, len=len_trim(device)) :: c_device
  1029. character(kind=c_char, len=len_trim(script)) :: c_script
  1030. integer(kind=c_size_t) :: name_length
  1031. integer(kind=c_size_t) :: script_length
  1032. integer(kind=c_size_t) :: device_length
  1033. c_name = trim(name)
  1034. c_script = trim(script)
  1035. c_device = trim(device)
  1036. name_length = len_trim(name)
  1037. script_length = len_trim(script)
  1038. device_length = len_trim(device)
  1039. code = set_script_c(self%client_ptr, c_name, name_length, c_device, device_length, c_script, script_length)
  1040. end function set_script
  1041. !> Set a script (from buffer) in the database for future execution in a multi-GPU system
  1042. function set_script_multigpu(self, name, script, first_gpu, num_gpus) result(code)
  1043. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1044. character(len=*), intent(in) :: name !< The name to use to place the script
  1045. character(len=*), intent(in) :: script !< The file storing the script
  1046. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  1047. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  1048. integer(kind=enum_kind) :: code
  1049. ! Local variables
  1050. character(kind=c_char, len=len_trim(name)) :: c_name
  1051. character(kind=c_char, len=len_trim(script)) :: c_script
  1052. integer(kind=c_size_t) :: name_length
  1053. integer(kind=c_size_t) :: script_length
  1054. integer(kind=c_size_t) :: device_length
  1055. integer(kind=c_int) :: c_first_gpu, c_num_gpus
  1056. c_name = trim(name)
  1057. c_script = trim(script)
  1058. name_length = len_trim(name)
  1059. script_length = len_trim(script)
  1060. c_first_gpu = first_gpu
  1061. c_num_gpus = num_gpus
  1062. code = set_script_multigpu_c(self%client_ptr, c_name, name_length, c_script, script_length, c_first_gpu, c_num_gpus)
  1063. end function set_script_multigpu
  1064. function run_script(self, name, func, inputs, outputs) result(code)
  1065. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1066. character(len=*), intent(in) :: name !< The name to use to place the script
  1067. character(len=*), intent(in) :: func !< The name of the function in the script to call
  1068. character(len=*), dimension(:), intent(in) :: inputs !< One or more names of script input nodes (TF scripts)
  1069. character(len=*), dimension(:), intent(in) :: outputs !< One or more names of script output nodes (TF scripts)
  1070. integer(kind=enum_kind) :: code
  1071. ! Local variables
  1072. character(kind=c_char, len=len_trim(name)) :: c_name
  1073. character(kind=c_char, len=len_trim(func)) :: c_func
  1074. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  1075. integer(c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  1076. integer(kind=c_size_t) :: n_inputs, n_outputs, name_length, func_length
  1077. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  1078. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  1079. integer :: i
  1080. integer :: max_length, length
  1081. c_name = trim(name)
  1082. c_func = trim(func)
  1083. name_length = len_trim(name)
  1084. func_length = len_trim(func)
  1085. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  1086. n_inputs)
  1087. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  1088. output_lengths_ptr, n_outputs)
  1089. code = run_script_c(self%client_ptr, c_name, name_length, c_func, func_length, inputs_ptr, input_lengths_ptr, &
  1090. n_inputs, outputs_ptr, output_lengths_ptr, n_outputs)
  1091. if (allocated(c_inputs)) deallocate(c_inputs)
  1092. if (allocated(input_lengths)) deallocate(input_lengths)
  1093. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  1094. if (allocated(c_outputs)) deallocate(c_outputs)
  1095. if (allocated(output_lengths)) deallocate(output_lengths)
  1096. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  1097. end function run_script
  1098. function run_script_multigpu(self, name, func, inputs, outputs, offset, first_gpu, num_gpus) result(code)
  1099. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1100. character(len=*), intent(in) :: name !< The name to use to place the script
  1101. character(len=*), intent(in) :: func !< The name of the function in the script to call
  1102. character(len=*), dimension(:), intent(in) :: inputs !< One or more names of script input nodes (TF scripts)
  1103. character(len=*), dimension(:), intent(in) :: outputs !< One or more names of script output nodes (TF scripts)
  1104. integer, intent(in) :: offset !< Index of the current image, such as a processor ID
  1105. !! or MPI rank
  1106. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  1107. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  1108. integer(kind=enum_kind) :: code
  1109. ! Local variables
  1110. character(kind=c_char, len=len_trim(name)) :: c_name
  1111. character(kind=c_char, len=len_trim(func)) :: c_func
  1112. integer(kind=c_int) :: c_first_gpu, c_num_gpus, c_offset
  1113. character(kind=c_char, len=:), allocatable, target :: c_inputs(:), c_outputs(:)
  1114. integer(c_size_t), dimension(:), allocatable, target :: input_lengths, output_lengths
  1115. integer(kind=c_size_t) :: n_inputs, n_outputs, name_length, func_length
  1116. type(c_ptr) :: inputs_ptr, input_lengths_ptr, outputs_ptr, output_lengths_ptr
  1117. type(c_ptr), dimension(:), allocatable :: ptrs_to_inputs, ptrs_to_outputs
  1118. integer :: i
  1119. integer :: max_length, length
  1120. c_name = trim(name)
  1121. c_func = trim(func)
  1122. name_length = len_trim(name)
  1123. func_length = len_trim(func)
  1124. call convert_char_array_to_c(inputs, c_inputs, ptrs_to_inputs, inputs_ptr, input_lengths, input_lengths_ptr, &
  1125. n_inputs)
  1126. call convert_char_array_to_c(outputs, c_outputs, ptrs_to_outputs, outputs_ptr, output_lengths, &
  1127. output_lengths_ptr, n_outputs)
  1128. ! Cast to c integer
  1129. c_offset = offset
  1130. c_first_gpu = first_gpu
  1131. c_num_gpus = num_gpus
  1132. code = run_script_multigpu_c(self%client_ptr, c_name, name_length, c_func, func_length, inputs_ptr, input_lengths_ptr, &
  1133. n_inputs, outputs_ptr, output_lengths_ptr, n_outputs, c_offset, c_first_gpu, c_num_gpus)
  1134. if (allocated(c_inputs)) deallocate(c_inputs)
  1135. if (allocated(input_lengths)) deallocate(input_lengths)
  1136. if (allocated(ptrs_to_inputs)) deallocate(ptrs_to_inputs)
  1137. if (allocated(c_outputs)) deallocate(c_outputs)
  1138. if (allocated(output_lengths)) deallocate(output_lengths)
  1139. if (allocated(ptrs_to_outputs)) deallocate(ptrs_to_outputs)
  1140. end function run_script_multigpu
  1141. !> Remove a script from the database
  1142. function delete_script(self, name) result(code)
  1143. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1144. character(len=*), intent(in) :: name !< The name to use to delete the script
  1145. integer(kind=enum_kind) :: code
  1146. ! Local variables
  1147. character(kind=c_char, len=len_trim(name)) :: c_name
  1148. integer(kind=c_size_t) :: name_length
  1149. c_name = trim(name)
  1150. name_length = len_trim(name)
  1151. code = delete_script_c(self%client_ptr, c_name, name_length)
  1152. end function delete_script
  1153. !> Remove a script_multigpu from the database
  1154. function delete_script_multigpu(self, name, first_gpu, num_gpus) result(code)
  1155. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1156. character(len=*), intent(in) :: name !< The name to use to delete the script_multigpu
  1157. integer, intent(in) :: first_gpu !< The first GPU (zero-based) to use with the model
  1158. integer, intent(in) :: num_gpus !< The number of GPUs to use with the model
  1159. integer(kind=enum_kind) :: code
  1160. ! Local variables
  1161. character(kind=c_char, len=len_trim(name)) :: c_name
  1162. integer(kind=c_int) :: c_first_gpu, c_num_gpus
  1163. integer(kind=c_size_t) :: name_length
  1164. c_name = trim(name)
  1165. name_length = len_trim(name)
  1166. c_first_gpu = first_gpu
  1167. c_num_gpus = num_gpus
  1168. code = delete_script_multigpu_c(self%client_ptr, c_name, name_length, c_first_gpu, c_num_gpus)
  1169. end function delete_script_multigpu
  1170. !> Store a dataset in the database
  1171. function put_dataset(self, dataset) result(code)
  1172. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1173. type(dataset_type), intent(in) :: dataset !< Dataset to store in the dataset
  1174. integer(kind=enum_kind) :: code
  1175. code = put_dataset_c(self%client_ptr, dataset%dataset_ptr)
  1176. end function put_dataset
  1177. !> Retrieve a dataset from the database
  1178. function get_dataset(self, name, dataset) result(code)
  1179. class(client_type), intent(in ) :: self !< An initialized SmartRedis client
  1180. character(len=*), intent(in ) :: name !< Name of the dataset to get
  1181. type(dataset_type), intent( out) :: dataset !< receives the dataset
  1182. integer(kind=enum_kind) :: code
  1183. ! Local variables
  1184. character(kind=c_char, len=len_trim(name)) :: c_name
  1185. integer(kind=c_size_t) :: name_length
  1186. c_name = trim(name)
  1187. name_length = len_trim(name)
  1188. code = get_dataset_c(self%client_ptr, c_name, name_length, dataset%dataset_ptr)
  1189. end function get_dataset
  1190. !> Rename a dataset stored in the database
  1191. function rename_dataset(self, name, new_name) result(code)
  1192. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1193. character(len=*), intent(in) :: name !< Original name of the dataset
  1194. character(len=*), intent(in) :: new_name !< New name of the dataset
  1195. integer(kind=enum_kind) :: code
  1196. ! Local variables
  1197. character(kind=c_char, len=len_trim(name)) :: c_name
  1198. character(kind=c_char, len=len_trim(new_name)) :: c_new_name
  1199. integer(kind=c_size_t) :: name_length, new_name_length
  1200. c_name = trim(name)
  1201. c_new_name = trim(new_name)
  1202. name_length = len_trim(name)
  1203. new_name_length = len_trim(new_name)
  1204. code = rename_dataset_c(self%client_ptr, c_name, name_length, c_new_name, new_name_length)
  1205. end function rename_dataset
  1206. !> Copy a dataset within the database to a new name
  1207. function copy_dataset(self, name, new_name) result(code)
  1208. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1209. character(len=*), intent(in) :: name !< Source name of the dataset
  1210. character(len=*), intent(in) :: new_name !< Name of the new dataset
  1211. integer(kind=enum_kind) :: code
  1212. ! Local variables
  1213. character(kind=c_char, len=len_trim(name)) :: c_name
  1214. character(kind=c_char, len=len_trim(new_name)) :: c_new_name
  1215. integer(kind=c_size_t) :: name_length, new_name_length
  1216. c_name = trim(name)
  1217. c_new_name = trim(new_name)
  1218. name_length = len_trim(name)
  1219. new_name_length = len_trim(new_name)
  1220. code = copy_dataset_c(self%client_ptr, c_name, name_length, c_new_name, new_name_length)
  1221. end function copy_dataset
  1222. !> Delete a dataset stored within a database
  1223. function delete_dataset(self, name) result(code)
  1224. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1225. character(len=*), intent(in) :: name !< Name of the dataset to delete
  1226. integer(kind=enum_kind) :: code
  1227. ! Local variables
  1228. character(kind=c_char, len=len_trim(name)) :: c_name
  1229. integer(kind=c_size_t) :: name_length
  1230. c_name = trim(name)
  1231. name_length = len_trim(name)
  1232. code = delete_dataset_c(self%client_ptr, c_name, name_length)
  1233. end function delete_dataset
  1234. !> Set the data source (i.e. name prefix for get functions)
  1235. function set_data_source(self, source_id) result(code)
  1236. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1237. character(len=*), intent(in) :: source_id !< The name prefix
  1238. integer(kind=enum_kind) :: code
  1239. ! Local variables
  1240. character(kind=c_char, len=len_trim(source_id)) :: c_source_id
  1241. integer(kind=c_size_t) :: source_id_length
  1242. c_source_id = trim(source_id)
  1243. source_id_length = len_trim(source_id)
  1244. code = set_data_source_c(self%client_ptr, c_source_id, source_id_length)
  1245. end function set_data_source
  1246. !> Set whether names of model and script entities should be prefixed (e.g. in an ensemble) to form database names.
  1247. !! Prefixes will only be used if they were previously set through the environment variables SSKEYOUT and SSKEYIN.
  1248. !! Keys of entities created before client function is called will not be affected. By default, the client does not
  1249. !! prefix model and script names.
  1250. function use_model_ensemble_prefix(self, use_prefix) result(code)
  1251. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1252. logical, intent(in) :: use_prefix !< The prefix setting
  1253. integer(kind=enum_kind) :: code
  1254. code = use_model_ensemble_prefix_c(self%client_ptr, logical(use_prefix,kind=c_bool))
  1255. end function use_model_ensemble_prefix
  1256. !> Set whether names of tensor and dataset entities should be prefixed (e.g. in an ensemble) to form database keys.
  1257. !! Prefixes will only be used if they were previously set through the environment variables SSKEYOUT and SSKEYIN.
  1258. !! Keys of entities created before client function is called will not be affected. By default, the client prefixes
  1259. !! tensor and dataset keys with the first prefix specified with the SSKEYIN and SSKEYOUT environment variables.
  1260. function use_tensor_ensemble_prefix(self, use_prefix) result(code)
  1261. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1262. logical, intent(in) :: use_prefix !< The prefix setting
  1263. integer(kind=enum_kind) :: code
  1264. code = use_tensor_ensemble_prefix_c(self%client_ptr, logical(use_prefix,kind=c_bool))
  1265. end function use_tensor_ensemble_prefix
  1266. !> Control whether aggregation lists are prefixed
  1267. function use_list_ensemble_prefix(self, use_prefix) result(code)
  1268. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1269. logical, intent(in) :: use_prefix !< The prefix setting
  1270. integer(kind=enum_kind) :: code
  1271. code = use_list_ensemble_prefix_c(self%client_ptr, logical(use_prefix,kind=c_bool))
  1272. end function use_list_ensemble_prefix
  1273. !> Appends a dataset to the aggregation list When appending a dataset to an aggregation list, the list will
  1274. !! automatically be created if it does not exist (i.e. this is the first entry in the list). Aggregation
  1275. !! lists work by referencing the dataset by storing its key, so appending a dataset to an aggregation list
  1276. !! does not create a copy of the dataset. Also, for this reason, the dataset must have been previously
  1277. !! placed into the database with a separate call to put_dataset().
  1278. function append_to_list(self, list_name, dataset) result(code)
  1279. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1280. character(len=*), intent(in) :: list_name !< Name of the dataset to get
  1281. type(dataset_type), intent(in) :: dataset !< Dataset to append to the list
  1282. integer(kind=enum_kind) :: code
  1283. integer(kind=c_size_t) :: list_name_length
  1284. character(kind=c_char,len=len_trim(list_name)) :: list_name_c
  1285. list_name_c = trim(list_name)
  1286. list_name_length = len_trim(list_name)
  1287. code = append_to_list_c(self%client_ptr, list_name_c, list_name_length, dataset%dataset_ptr)
  1288. end function append_to_list
  1289. !> Delete an aggregation list
  1290. function delete_list(self, list_name) result(code)
  1291. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1292. character(len=*), intent(in) :: list_name !< Name of the aggregated dataset list to delete
  1293. integer(kind=enum_kind) :: code
  1294. integer(kind=c_size_t) :: list_name_length
  1295. character(kind=c_char,len=len_trim(list_name)) :: list_name_c
  1296. list_name_c = trim(list_name)
  1297. list_name_length = len_trim(list_name)
  1298. code = delete_list_c(self%client_ptr, list_name_c, list_name_length)
  1299. end function delete_list
  1300. !> Copy an aggregation list
  1301. function copy_list(self, src_name, dest_name) result(code)
  1302. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1303. character(len=*), intent(in) :: src_name !< Name of the dataset to copy
  1304. character(len=*), intent(in) :: dest_name !< The new list name
  1305. integer(kind=enum_kind) :: code
  1306. integer(kind=c_size_t) :: src_name_length, dest_name_length
  1307. character(kind=c_char,len=len_trim(src_name)) :: src_name_c
  1308. character(kind=c_char,len=len_trim(dest_name)) :: dest_name_c
  1309. src_name_c = trim(src_name)
  1310. src_name_length = len_trim(src_name)
  1311. dest_name_c = trim(dest_name)
  1312. dest_name_length = len_trim(dest_name)
  1313. code = copy_list_c(self%client_ptr, src_name_c, src_name_length, dest_name_c, dest_name_length)
  1314. end function copy_list
  1315. !> Rename an aggregation list
  1316. function rename_list(self, src_name, dest_name) result(code)
  1317. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1318. character(len=*), intent(in) :: src_name !< Name of the dataset to rename
  1319. character(len=*), intent(in) :: dest_name !< The new list name
  1320. integer(kind=enum_kind) :: code
  1321. integer(kind=c_size_t) :: src_name_length, dest_name_length
  1322. character(kind=c_char,len=len_trim(src_name)) :: src_name_c
  1323. character(kind=c_char,len=len_trim(dest_name)) :: dest_name_c
  1324. src_name_c = trim(src_name)
  1325. src_name_length = len_trim(src_name)
  1326. dest_name_c = trim(dest_name)
  1327. dest_name_length = len_trim(dest_name)
  1328. code = rename_list_c(self%client_ptr, src_name_c, src_name_length, dest_name_c, dest_name_length)
  1329. end function rename_list
  1330. !> Get the length of the aggregation list
  1331. function get_list_length(self, list_name, result_length) result(code)
  1332. class(client_type), intent(in ) :: self !< An initialized SmartRedis client
  1333. character(len=*), intent(in ) :: list_name !< Name of the dataset to get
  1334. integer, intent( out) :: result_length !< The length of the list
  1335. integer(kind=enum_kind) :: code
  1336. integer(kind=c_size_t) :: list_name_length
  1337. integer(kind=c_int) :: result_length_c
  1338. character(kind=c_char,len=len_trim(list_name)) :: list_name_c
  1339. list_name_c = trim(list_name)
  1340. list_name_length = len_trim(list_name)
  1341. code = get_list_length_c(self%client_ptr, list_name_c, list_name_length, result_length_c)
  1342. result_length = result_length_c
  1343. end function get_list_length
  1344. !> Get the length of the aggregation list
  1345. function poll_list_length(self, list_name, list_length, poll_frequency_ms, num_tries, poll_result) result(code)
  1346. class(client_type), intent(in ) :: self !< An initialized SmartRedis client
  1347. character(len=*), intent(in ) :: list_name !< Name of the dataset to get
  1348. integer, intent(in ) :: list_length !< The desired length of the list
  1349. integer, intent(in ) :: poll_frequency_ms !< Frequency at which to poll the database (ms)
  1350. integer, intent(in ) :: num_tries !< Number of times to poll the database before failing
  1351. logical(kind=c_bool), intent( out) :: poll_result !< True if the list is the requested length, False if not after num_tries.
  1352. integer(kind=enum_kind) :: code
  1353. ! Local variables
  1354. character(kind=c_char, len=len_trim(list_name)) :: list_name_c
  1355. integer(kind=c_size_t) :: list_name_length
  1356. integer(kind=c_int) :: c_poll_frequency, c_num_tries, c_list_length
  1357. list_name_c = trim(list_name)
  1358. list_name_length = len_trim(list_name)
  1359. c_num_tries = num_tries
  1360. c_poll_frequency = poll_frequency_ms
  1361. c_list_length = list_length
  1362. code = poll_list_length_c(self%client_ptr, list_name_c, list_name_length, &
  1363. c_list_length, c_poll_frequency, c_num_tries, poll_result)
  1364. end function poll_list_length
  1365. !> Get the length of the aggregation list
  1366. function poll_list_length_gte(self, list_name, list_length, poll_frequency_ms, num_tries, poll_result) result(code)
  1367. class(client_type), intent(in ) :: self !< An initialized SmartRedis client
  1368. character(len=*), intent(in ) :: list_name !< Name of the dataset to get
  1369. integer, intent(in ) :: list_length !< The desired length of the list
  1370. integer, intent(in ) :: poll_frequency_ms !< Frequency at which to poll the database (ms)
  1371. integer, intent(in ) :: num_tries !< Number of times to poll the database before failing
  1372. logical(kind=c_bool), intent( out) :: poll_result !< True if the list is the requested length, False if not after num_tries.
  1373. integer(kind=enum_kind) :: code
  1374. ! Local variables
  1375. character(kind=c_char, len=len_trim(list_name)) :: list_name_c
  1376. integer(kind=c_size_t) :: list_name_length
  1377. integer(kind=c_int) :: c_poll_frequency, c_num_tries, c_list_length
  1378. list_name_c = trim(list_name)
  1379. list_name_length = len_trim(list_name)
  1380. c_num_tries = num_tries
  1381. c_poll_frequency = poll_frequency_ms
  1382. c_list_length = list_length
  1383. code = poll_list_length_gte_c(self%client_ptr, list_name_c, list_name_length, &
  1384. c_list_length, c_poll_frequency, c_num_tries, poll_result)
  1385. end function poll_list_length_gte
  1386. !> Get the length of the aggregation list
  1387. function poll_list_length_lte(self, list_name, list_length, poll_frequency_ms, num_tries, poll_result) result(code)
  1388. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1389. character(len=*), intent(in) :: list_name !< Name of the dataset to get
  1390. integer, intent(in) :: list_length !< The desired length of the list
  1391. integer, intent(in) :: poll_frequency_ms !< Frequency at which to poll the database (ms)
  1392. integer, intent(in) :: num_tries !< Number of times to poll the database before failing
  1393. logical(kind=c_bool), intent(out) :: poll_result !< True if the list is the requested length, False if not after num_tries.
  1394. integer(kind=enum_kind) :: code
  1395. ! Local variables
  1396. character(kind=c_char, len=len_trim(list_name)) :: list_name_c
  1397. integer(kind=c_size_t) :: list_name_length
  1398. integer(kind=c_int) :: c_poll_frequency, c_num_tries, c_list_length
  1399. list_name_c = trim(list_name)
  1400. list_name_length = len_trim(list_name)
  1401. c_num_tries = num_tries
  1402. c_poll_frequency = poll_frequency_ms
  1403. c_list_length = list_length
  1404. code = poll_list_length_lte_c(self%client_ptr, list_name_c, list_name_length, &
  1405. c_list_length, c_poll_frequency, c_num_tries, poll_result)
  1406. end function poll_list_length_lte
  1407. !> Get datasets from an aggregation list. Note that this will deallocate an existing list.
  1408. !! NOTE: This potentially be less performant than get_datasets_from_list_range due to an
  1409. !! extra query to the database to get the list length. This is for now necessary because
  1410. !! difficulties in allocating memory for Fortran alloctables from within C.
  1411. function get_datasets_from_list(self, list_name, datasets, num_datasets) result(code)
  1412. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1413. character(len=*), intent(in) :: list_name !< Name of the dataset to get
  1414. type(dataset_type), dimension(:), allocatable, intent( out) :: datasets !< The array of datasets included
  1415. integer(kind=enum_kind) :: code
  1416. !! in the list
  1417. integer, intent(out) :: num_datasets !< The numbr of datasets returned
  1418. character(kind=c_char, len=len_trim(list_name)) :: list_name_c
  1419. integer(kind=c_size_t) :: list_name_length
  1420. integer(kind=c_int) :: c_poll_frequency, c_num_tries, c_list_length, c_num_datasets
  1421. type(c_ptr), dimension(:), allocatable, target :: dataset_ptrs
  1422. type(c_ptr) :: ptr_to_dataset_ptrs
  1423. integer :: i
  1424. code = self%get_list_length(list_name, num_datasets)
  1425. allocate(dataset_ptrs(num_datasets))
  1426. ptr_to_dataset_ptrs = c_loc(dataset_ptrs)
  1427. list_name_c = trim(list_name)
  1428. list_name_length = len_trim(list_name)
  1429. c_num_datasets = num_datasets
  1430. code = get_dataset_list_range_allocated_c(self%client_ptr, list_name_c, list_name_length, &
  1431. 0, c_num_datasets-1, ptr_to_dataset_ptrs)
  1432. if (allocated(datasets)) deallocate(datasets)
  1433. allocate(datasets(num_datasets))
  1434. do i=1,num_datasets
  1435. datasets(i)%dataset_ptr = dataset_ptrs(i)
  1436. enddo
  1437. deallocate(dataset_ptrs)
  1438. end function get_datasets_from_list
  1439. !> Get datasets from an aggregation list over a given range by index. Note that this will deallocate an existing list
  1440. function get_datasets_from_list_range(self, list_name, start_index, end_index, datasets) result(code)
  1441. class(client_type), intent(in) :: self !< An initialized SmartRedis client
  1442. character(len=*), intent(in) :: list_name !< Name of the dataset to get
  1443. integer, intent(in) :: start_index !< The starting index of the range (inclusive,
  1444. !! starting at zero). Negative values are
  1445. !! supported. A negative value indicates offsets
  1446. !! starting at the end of the list. For example, -1 is
  1447. !! the last element of the list.
  1448. integer, intent(in) :: end_index !< The ending index of the range (inclusive,
  1449. !! starting at zero). Negative values are
  1450. !! supported. A negative value indicates offsets
  1451. !! starting at the end of the list. For example, -1 is
  1452. !! the last element of the list.
  1453. type(dataset_type), dimension(:), allocatable, intent( out) :: datasets !< The array of datasets included
  1454. integer(kind=enum_kind) :: code
  1455. !! in the list
  1456. character(kind=c_char, len=len_trim(list_name)) :: list_name_c
  1457. integer(kind=c_size_t) :: list_name_length
  1458. integer(kind=c_int) :: c_poll_frequency, c_num_tries, c_list_length, c_num_datasets
  1459. integer(kind=c_int) :: c_start_index, c_end_index
  1460. integer :: num_datasets, i
  1461. type(c_ptr), dimension(:), allocatable, target :: dataset_ptrs
  1462. type(c_ptr) :: ptr_to_dataset_ptrs
  1463. code = self%get_list_length(list_name, num_datasets)
  1464. if (code /= SRNoError) return
  1465. allocate(dataset_ptrs(num_datasets))
  1466. ptr_to_dataset_ptrs = c_loc(dataset_ptrs)
  1467. list_name_c = trim(list_name)
  1468. list_name_length = len_trim(list_name)
  1469. c_num_datasets = num_datasets
  1470. code = get_dataset_list_range_allocated_c(self%client_ptr, list_name_c, list_name_length, &
  1471. c_start_index, c_end_index, ptr_to_dataset_ptrs)
  1472. if (allocated(datasets)) deallocate(datasets)
  1473. allocate(datasets(num_datasets))
  1474. do i=1,num_datasets
  1475. datasets(i)%dataset_ptr = dataset_ptrs(i)
  1476. enddo
  1477. deallocate(dataset_ptrs)
  1478. end function get_datasets_from_list_range
  1479. end module smartredis_client