root/opal/mca/pmix/pmix4x/pmix/src/mca/psquash/flex128/psquash_flex128.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. flex128_init
  2. flex128_finalize
  3. flex128_get_max_size
  4. flex128_encode_int
  5. flex128_decode_int
  6. flex_pack_integer
  7. flex_unpack_integer

   1 /*
   2  * Copyright (c) 2019      IBM Corporation.  All rights reserved.
   3  * Copyright (c) 2019      Mellanox Technologies, Inc.
   4  *                         All rights reserved.
   5  *
   6  * $COPYRIGHT$
   7  *
   8  * Additional copyrights may follow
   9  *
  10  * $HEADER$
  11  */
  12 
  13 #include <src/include/pmix_config.h>
  14 
  15 #include <pmix_common.h>
  16 
  17 #include "src/include/pmix_socket_errno.h"
  18 #include "src/include/pmix_globals.h"
  19 #include "src/util/argv.h"
  20 #include "src/util/error.h"
  21 #include "src/util/output.h"
  22 
  23 #include <unistd.h>
  24 #ifdef HAVE_SYS_TYPES_H
  25 #include <sys/types.h>
  26 #endif
  27 
  28 #include "src/mca/psquash/base/base.h"
  29 #include "psquash_flex128.h"
  30 
  31 /* Flexible packing constants */
  32 #define FLEX_BASE7_MAX_BUF_SIZE (SIZEOF_SIZE_T+1)
  33 #define FLEX_BASE7_MASK ((1<<7) - 1)
  34 #define FLEX_BASE7_SHIFT 7
  35 #define FLEX_BASE7_CONT_FLAG (1<<7)
  36 
  37 /**
  38  * Packing conversion of a signed integer value to a flexible representation.
  39  * The main idea is to split a signed negative value onto an absolute value
  40  * and a sign bit stored in the special location.
  41  * This allows efficient representetion of negative values in the
  42  * flexible form.
  43  *
  44  * type - type (pmix_data_type_t) of integer value
  45  * ptr - pointer to the signed integer value
  46  *       with the type defined as (type)
  47  * out - flexible representation of *ptr,
  48  *       extended to uint64_t if needed
  49  * (see a comment to `pmix_bfrops_pack_flex` for additional details)
  50  */
  51 #define FLEX128_PACK_CONVERT_SIGNED(type, ptr, out)         \
  52 do {                                                        \
  53     type __tbuf = 0;                                        \
  54     size_t __tmp;                                           \
  55     int __sign = 0;                                         \
  56     memcpy(&__tbuf, (ptr), sizeof(type));                   \
  57     __tmp = __tbuf;                                         \
  58     (out) = (size_t)__tmp;                                  \
  59     if (__tmp & (1UL << (sizeof(__tmp)*CHAR_BIT-1))) {      \
  60         __sign = 1;                                         \
  61         out = ~(out);                                       \
  62     }                                                       \
  63     (out) = ((out) << 1) + __sign;                          \
  64 } while (0)
  65 
  66 /**
  67  * Packing conversion of a signed integer value to a flexible representation.
  68  * For unsigned types it is reduced to a memcopy.
  69  *
  70  * type - usual integer C-type of integer value
  71  * ptr - pointer to the signed integer value
  72  *       with the type defined as (type)
  73  * out - flexible representation of *ptr,
  74  *       extended to uint64_t if needed
  75  * (see a comment to `pmix_bfrops_pack_flex` for additional details)
  76  */
  77 #define FLEX128_PACK_CONVERT_UNSIGNED(type, ptr, out)       \
  78 do {                                                        \
  79     type __tbuf = 0;                                        \
  80     memcpy(&__tbuf, (ptr), sizeof(type));                   \
  81     out = __tbuf;                                           \
  82 } while (0)
  83 
  84 /**
  85  * Packing conversion from integer value to a flexible representation.
  86  *
  87  * r - return status code
  88  * t - type (pmix_data_type_t) of integer value, it is determines
  89  *     which type of integer is converted
  90  * s - pointer to the integer value with the type defined as (t)
  91  * d - flexible representation output value (uin64_t)
  92  * (see a comment to `pmix_bfrops_pack_flex` for additional details)
  93  */
  94 #define FLEX128_PACK_CONVERT(r, t, s, d)                            \
  95 do {                                                                \
  96     (r) = PMIX_SUCCESS;                                             \
  97     switch (t) {                                                    \
  98         case PMIX_INT16:                                            \
  99             FLEX128_PACK_CONVERT_SIGNED(int16_t, s, d);             \
 100             break;                                                  \
 101         case PMIX_UINT16:                                           \
 102             FLEX128_PACK_CONVERT_UNSIGNED(uint16_t, s, d);          \
 103             break;                                                  \
 104         case PMIX_INT:                                              \
 105         case PMIX_INT32:                                            \
 106             FLEX128_PACK_CONVERT_SIGNED(int32_t, s, d);             \
 107             break;                                                  \
 108         case PMIX_UINT:                                             \
 109         case PMIX_UINT32:                                           \
 110             FLEX128_PACK_CONVERT_UNSIGNED(uint32_t, s, d);          \
 111             break;                                                  \
 112         case PMIX_INT64:                                            \
 113             FLEX128_PACK_CONVERT_SIGNED(int64_t, s, d);             \
 114             break;                                                  \
 115         case PMIX_SIZE:                                             \
 116             FLEX128_PACK_CONVERT_UNSIGNED(size_t, s, d);            \
 117             break;                                                  \
 118         case PMIX_UINT64:                                           \
 119             FLEX128_PACK_CONVERT_UNSIGNED(uint64_t, s, d);          \
 120             break;                                                  \
 121         default:                                                    \
 122             (r) = PMIX_ERR_BAD_PARAM;                               \
 123     }                                                               \
 124 } while(0)
 125 
 126 /**
 127  * Unpacking conversion from a flexible representation to a
 128  * signed integer value.
 129  *
 130  * type - C-type of a signed integer value
 131  * val - flexible representation (uint64_t)
 132  * ptr - pointer to a 64-bit output buffer for the upacked value
 133  * (see a comment to `pmix_bfrops_pack_flex` for additional details)
 134  */
 135 #define FLEX128_UNPACK_CONVERT_SIGNED(type, val, ptr)           \
 136 do {                                                            \
 137     type __tbuf = 0;                                            \
 138     size_t __tmp = val;                                         \
 139     int sign = (__tmp) & 1;                                     \
 140     __tmp >>= 1;                                                \
 141     if (sign) {                                                 \
 142         __tmp = ~__tmp;                                         \
 143     }                                                           \
 144     __tbuf = (type)__tmp;                                       \
 145     memcpy(ptr, &__tbuf, sizeof(type));                         \
 146 } while (0)
 147 
 148 /**
 149  * Unpacking conversion of a flexible representation value
 150  * to an unsigned integer.
 151  *
 152  * type - C-type of unsigned integer value
 153  * val - flexible representation value (uint64_t)
 154  * ptr - pointer to a 64-bit output buffer for the upacked value
 155  * (see a comment to `pmix_bfrops_pack_flex` for additional details)
 156  */
 157 #define FLEX128_UNPACK_CONVERT_UNSIGNED(type, val, ptr)         \
 158 do {                                                            \
 159     type __tbuf = 0;                                            \
 160     __tbuf = (type)val;                                         \
 161     memcpy(ptr, &__tbuf, sizeof(type));                         \
 162 } while (0)
 163 
 164 /**
 165  * Unpacking conversion of a flexible representation value
 166  * to an integer.
 167  *
 168  * r - return status code
 169  * t - type (pmix_data_type_t) of integer value, it is determines
 170  *     which type of integer is converted
 171  * s - flex-representation value (uin64_t)
 172  * d - pointer to a 64-bit output buffer for the upacked value
 173  * (see a comment to `pmix_bfrops_pack_flex` for additional details)
 174  */
 175 #define FLEX128_UNPACK_CONVERT(r, t, s, d)                              \
 176 do {                                                                    \
 177     (r) = PMIX_SUCCESS;                                                 \
 178     switch (t) {                                                        \
 179         case PMIX_INT16:                                                \
 180             FLEX128_UNPACK_CONVERT_SIGNED(int16_t, s, d);               \
 181             break;                                                      \
 182         case PMIX_UINT16:                                               \
 183             FLEX128_UNPACK_CONVERT_UNSIGNED(uint16_t, s, d);            \
 184             break;                                                      \
 185         case PMIX_INT:                                                  \
 186         case PMIX_INT32:                                                \
 187             FLEX128_UNPACK_CONVERT_SIGNED(int32_t, s, d);               \
 188             break;                                                      \
 189         case PMIX_UINT:                                                 \
 190         case PMIX_UINT32:                                               \
 191             FLEX128_UNPACK_CONVERT_UNSIGNED(uint32_t, s, d);            \
 192             break;                                                      \
 193         case PMIX_INT64:                                                \
 194             FLEX128_UNPACK_CONVERT_SIGNED(int64_t, s, d);               \
 195             break;                                                      \
 196         case PMIX_SIZE:                                                 \
 197             FLEX128_UNPACK_CONVERT_UNSIGNED(size_t, s, d);              \
 198             break;                                                      \
 199         case PMIX_UINT64:                                               \
 200             FLEX128_UNPACK_CONVERT_UNSIGNED(uint64_t, s, d);            \
 201             break;                                                      \
 202         default:                                                        \
 203             (r) = PMIX_ERR_BAD_PARAM;                                   \
 204     }                                                                   \
 205 } while(0)
 206 
 207 static pmix_status_t flex128_init(void);
 208 
 209 static void flex128_finalize(void);
 210 
 211 static pmix_status_t flex128_get_max_size(pmix_data_type_t type, size_t *size);
 212 
 213 static pmix_status_t flex128_encode_int(pmix_data_type_t type, void *src,
 214                                         void *dst, size_t *size);
 215 
 216 static pmix_status_t flex128_decode_int(pmix_data_type_t type, void *src,
 217                                         size_t src_len, void *dest,
 218                                         size_t *dst_size);
 219 
 220 static size_t flex_pack_integer(size_t val,
 221                                 uint8_t out_buf[FLEX_BASE7_MAX_BUF_SIZE]);
 222 
 223 static size_t flex_unpack_integer(const uint8_t in_buf[], size_t buf_size,
 224                                   size_t *out_val, size_t *out_val_size);
 225 
 226 pmix_psquash_base_module_t pmix_flex128_module = {
 227     .name = "flex128",
 228     .int_type_is_encoded = true,
 229     .init = flex128_init,
 230     .finalize = flex128_finalize,
 231     .get_max_size = flex128_get_max_size,
 232     .encode_int = flex128_encode_int,
 233     .decode_int = flex128_decode_int
 234 };
 235 
 236 
 237 static pmix_status_t flex128_init(void)
 238 {
 239     pmix_output_verbose(2, pmix_globals.debug_output,
 240                         "psquash: flex128 init");
 241     return PMIX_SUCCESS;
 242 }
 243 
 244 static void flex128_finalize(void)
 245 {
 246     pmix_output_verbose(2, pmix_globals.debug_output,
 247                         "psquash: flex128 finalize");
 248 }
 249 
 250 static pmix_status_t flex128_get_max_size(pmix_data_type_t type, size_t *size)
 251  {
 252     pmix_status_t rc;
 253     PMIX_SQUASH_TYPE_SIZEOF(rc, type, *size);
 254     /* the size of the packed value can be 1B larger
 255      * because of continuation flags */
 256     *size += 1;
 257     return rc;
 258 }
 259 
 260 static pmix_status_t flex128_encode_int(pmix_data_type_t type, void *src,
 261                                         void *dst, size_t *size)
 262 {
 263     pmix_status_t rc = PMIX_SUCCESS;
 264     uint8_t tmp_buf[FLEX_BASE7_MAX_BUF_SIZE];
 265     uint64_t tmp;
 266 
 267     FLEX128_PACK_CONVERT(rc, type, (uint8_t*)src, tmp);
 268     if (PMIX_SUCCESS != rc) {
 269         PMIX_ERROR_LOG(rc);
 270         return rc;
 271     }
 272     *size = flex_pack_integer(tmp, tmp_buf);
 273     memcpy(dst, tmp_buf, *size);
 274 
 275     return rc;
 276 }
 277 
 278 static pmix_status_t flex128_decode_int(pmix_data_type_t type, void *src,
 279                                         size_t src_len, void *dest, size_t *dst_size)
 280 {
 281     pmix_status_t rc = PMIX_SUCCESS;
 282     size_t tmp;
 283     size_t val_size, unpack_val_size;
 284 
 285     PMIX_SQUASH_TYPE_SIZEOF(rc, type, val_size);
 286     if (PMIX_SUCCESS != rc) {
 287         PMIX_ERROR_LOG(rc);
 288         return rc;
 289     }
 290     *dst_size = flex_unpack_integer(src, src_len, &tmp, &unpack_val_size);
 291 
 292     if( val_size < unpack_val_size ) { // sanity check
 293         rc = PMIX_ERR_UNPACK_FAILURE;
 294         PMIX_ERROR_LOG(rc);
 295         return rc;
 296     }
 297     FLEX128_UNPACK_CONVERT(rc, type, tmp, (uint8_t*)dest);
 298     if (PMIX_SUCCESS != rc) {
 299         PMIX_ERROR_LOG(rc);
 300         return rc;
 301     }
 302 
 303     return rc;
 304 }
 305 
 306 /*
 307  * Typical representation of a number in computer systems is:
 308  * A[0]*B^0 + A[1]*B^1 + A[2]*B^2 + ... + A[n]*B^n
 309  * where B called a base and B == 256 (one byte)
 310  *
 311  * This encoding changes the default representation by introducing an additional
 312  * bit per each byte to store a "continuation flag". So integers are now encoded
 313  * with the same representation, but the base B = 128 and the remaning bit is
 314  * used to indicate whether or not the next byte contains more bits of this value.
 315  */
 316 static size_t flex_pack_integer(size_t val,
 317                                 uint8_t out_buf[FLEX_BASE7_MAX_BUF_SIZE])
 318 {
 319     size_t tmp = val;
 320     size_t idx = 0;
 321 
 322     do {
 323         uint8_t val = tmp & FLEX_BASE7_MASK;
 324         tmp >>= FLEX_BASE7_SHIFT;
 325         if (PMIX_UNLIKELY(tmp)) {
 326             val |= FLEX_BASE7_CONT_FLAG;
 327         }
 328         out_buf[idx++] = val;
 329     } while(tmp && idx < SIZEOF_SIZE_T);
 330 
 331     /* If we have leftover (VERY unlikely) */
 332     if (PMIX_UNLIKELY(SIZEOF_SIZE_T == idx && tmp)) {
 333         out_buf[idx++] = tmp;
 334     }
 335 
 336     return idx;
 337 }
 338 
 339 /*
 340  * See a comment to `pmix_bfrops_pack_flex` for additional details.
 341  */
 342 static size_t flex_unpack_integer(const uint8_t in_buf[], size_t buf_size,
 343                                   size_t *out_val, size_t *out_val_size)
 344 {
 345     size_t value = 0, shift = 0, shift_last = 0;
 346     size_t idx = 0;
 347     uint8_t val = 0, val_last = 0;
 348     uint8_t hi_bit = 0;
 349     size_t flex_size = buf_size;
 350 
 351     /* restrict the buf size to max flex size */
 352     if (buf_size > FLEX_BASE7_MAX_BUF_SIZE) {
 353         flex_size = FLEX_BASE7_MAX_BUF_SIZE;
 354     }
 355 
 356     do {
 357         val = in_buf[idx++];
 358         val_last = val;
 359         shift_last = shift;
 360         value = value + (((uint64_t)val & FLEX_BASE7_MASK) << shift);
 361         shift += FLEX_BASE7_SHIFT;
 362     } while(PMIX_UNLIKELY((val & FLEX_BASE7_CONT_FLAG) &&
 363                           (idx < (flex_size-1))));
 364     /* If we have leftover (VERY unlikely) */
 365     if (PMIX_UNLIKELY((flex_size-1) == idx &&
 366                       (val & FLEX_BASE7_CONT_FLAG))) {
 367         val = in_buf[idx++];
 368         val_last = val;
 369         value = value + ((uint64_t)val << shift);
 370         shift_last = shift;
 371     }
 372     /* compute the most significant bit of val */
 373     while (val_last != 0) {
 374         val_last >>= 1;
 375         hi_bit++;
 376     }
 377     /* compute the real val size */
 378     *out_val_size = (hi_bit + shift_last)/CHAR_BIT +
 379             !!((hi_bit + shift_last) & (CHAR_BIT - 1));
 380     *out_val = value;
 381 
 382     return idx;
 383 }

/* [<][>][^][v][top][bottom][index][help] */